diff options
| -rw-r--r-- | libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java | 73 |
1 files changed, 72 insertions, 1 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java index 7a569799ab84..52391d2f5a79 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java @@ -16,12 +16,15 @@ package com.android.wm.shell.back; +import static android.view.MotionEvent.ACTION_MOVE; import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.RemoteAnimationTarget.MODE_OPENING; import static android.window.BackEvent.EDGE_RIGHT; import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_CROSS_TASK; +import static com.android.window.flags.Flags.predictiveBackTimestampApi; import static com.android.wm.shell.back.BackAnimationConstants.UPDATE_SYSUI_FLAGS_THRESHOLD; +import static com.android.wm.shell.back.CrossActivityBackAnimationKt.scaleCentered; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; import android.animation.Animator; @@ -36,11 +39,14 @@ import android.graphics.Rect; import android.graphics.RectF; import android.os.Handler; import android.os.RemoteException; +import android.util.TimeUtils; import android.view.Choreographer; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; +import android.view.MotionEvent; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; +import android.view.VelocityTracker; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.window.BackEvent; @@ -48,6 +54,9 @@ import android.window.BackMotionEvent; import android.window.BackProgressAnimator; import android.window.IOnBackInvokedCallback; +import com.android.internal.dynamicanimation.animation.FloatValueHolder; +import com.android.internal.dynamicanimation.animation.SpringAnimation; +import com.android.internal.dynamicanimation.animation.SpringForce; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.internal.policy.SystemBarUtils; import com.android.internal.protolog.ProtoLog; @@ -81,6 +90,11 @@ public class CrossTaskBackAnimation extends ShellBackAnimation { /** Duration of post animation after gesture committed. */ private static final int POST_ANIMATION_DURATION_MS = 500; + private static final float SPRING_SCALE = 100f; + private static final float DEFAULT_FLING_VELOCITY = 320f; + private static final float MAX_FLING_VELOCITY = 1000f; + private static final float FLING_SPRING_STIFFNESS = 320f; + private final Rect mStartTaskRect = new Rect(); private float mCornerRadius; private int mStatusbarHeight; @@ -114,6 +128,14 @@ public class CrossTaskBackAnimation extends ShellBackAnimation { private float mInterWindowMargin; private float mVerticalMargin; + private final FloatValueHolder mPostCommitFlingScale = new FloatValueHolder(SPRING_SCALE); + private final SpringForce mPostCommitFlingSpring = new SpringForce(SPRING_SCALE) + .setStiffness(FLING_SPRING_STIFFNESS) + .setDampingRatio(1f); + private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); + private float mGestureProgress = 0f; + private long mDownTime = 0L; + @Inject public CrossTaskBackAnimation(Context context, BackAnimationBackground background, @ShellMainThread Handler handler) { @@ -168,6 +190,7 @@ public class CrossTaskBackAnimation extends ShellBackAnimation { if (mEnteringTarget == null || mClosingTarget == null) { return; } + mGestureProgress = progress; float touchY = event.getTouchY(); @@ -229,6 +252,8 @@ public class CrossTaskBackAnimation extends ShellBackAnimation { } mClosingCurrentRect.set(left, top, left + width, top + height); + + applyFlingScale(mClosingCurrentRect); applyTransform(mClosingTarget.leash, mClosingCurrentRect, mCornerRadius); } @@ -239,9 +264,19 @@ public class CrossTaskBackAnimation extends ShellBackAnimation { float height = mapRange(progress, mEnteringStartRect.height(), mStartTaskRect.height()); mEnteringCurrentRect.set(left, top, left + width, top + height); + + applyFlingScale(mEnteringCurrentRect); applyTransform(mEnteringTarget.leash, mEnteringCurrentRect, mCornerRadius); } + private void applyFlingScale(RectF rect) { + // apply a scale to the rect to account for fling velocity + final float flingScale = Math.min(mPostCommitFlingScale.getValue() / SPRING_SCALE, 1f); + if (flingScale >= 1f) return; + scaleCentered(rect, flingScale, /* pivotX */ rect.right, + /* pivotY */ rect.top + rect.height() / 2); + } + /** Transform the target window to match the target rect. */ private void applyTransform(SurfaceControl leash, RectF targetRect, float cornerRadius) { if (leash == null || !leash.isValid()) { @@ -280,6 +315,9 @@ public class CrossTaskBackAnimation extends ShellBackAnimation { mTransformMatrix.reset(); mClosingCurrentRect.setEmpty(); mInitialTouchPos.set(0, 0); + mGestureProgress = 0; + mDownTime = 0; + mVelocityTracker.clear(); if (mFinishCallback != null) { try { @@ -295,10 +333,24 @@ public class CrossTaskBackAnimation extends ShellBackAnimation { private void onGestureProgress(@NonNull BackEvent backEvent) { if (!mBackInProgress) { mBackInProgress = true; + mDownTime = backEvent.getFrameTime(); } float progress = backEvent.getProgress(); mTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY()); - updateGestureBackProgress(getInterpolatedProgress(progress), backEvent); + float interpolatedProgress = getInterpolatedProgress(progress); + if (predictiveBackTimestampApi()) { + mVelocityTracker.addMovement( + MotionEvent.obtain( + /* downTime */ mDownTime, + /* eventTime */ backEvent.getFrameTime(), + /* action */ ACTION_MOVE, + /* x */ interpolatedProgress * SPRING_SCALE, + /* y */ 0f, + /* metaState */ 0 + ) + ); + } + updateGestureBackProgress(interpolatedProgress, backEvent); } private void onGestureCommitted() { @@ -307,6 +359,25 @@ public class CrossTaskBackAnimation extends ShellBackAnimation { return; } + if (predictiveBackTimestampApi()) { + // kick off spring animation with the current velocity from the pre-commit phase, this + // affects the scaling of the closing and/or opening task during post-commit + mVelocityTracker.computeCurrentVelocity(1000); + float startVelocity = mGestureProgress < 0.1f + ? -DEFAULT_FLING_VELOCITY : -mVelocityTracker.getXVelocity(); + SpringAnimation flingAnimation = + new SpringAnimation(mPostCommitFlingScale, SPRING_SCALE) + .setStartVelocity(Math.max(-MAX_FLING_VELOCITY, Math.min(0f, startVelocity))) + .setStartValue(SPRING_SCALE) + .setMinimumVisibleChange(0.1f) + .setSpring(mPostCommitFlingSpring); + flingAnimation.start(); + // do an animation-frame immediately to prevent idle frame + flingAnimation.doAnimationFrame( + Choreographer.getInstance().getLastFrameTimeNanos() / TimeUtils.NANOS_PER_MS + ); + } + // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current // coordinate of the gesture driven phase. mEnteringCurrentRect.round(mEnteringStartRect); |