Merge "Polish cross task back animation" into main
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index c4be384..55a9132 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -476,4 +476,11 @@
<item type="dimen" format="float" name="splash_icon_enlarge_foreground_threshold">0.44</item>
<!-- Scaling factor applied to splash icons without provided background i.e. (192 / 160) -->
<item type="dimen" format="float" name="splash_icon_no_background_scale_factor">1.2</item>
+
+ <!-- The margin between the entering window and the exiting window during cross task back -->
+ <dimen name="cross_task_back_inter_window_margin">14dp</dimen>
+ <!-- The vertical margin that needs to be preserved between the scaled window bounds and the
+ original window bounds (once the surface is scaled enough to do so) -->
+ <dimen name="cross_task_back_vertical_margin">8dp</dimen>
+
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index 2ec9e8b..880579d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -88,6 +88,8 @@
public static final PathInterpolator DIM_INTERPOLATOR =
new PathInterpolator(.23f, .87f, .52f, -0.11f);
+ public static final Interpolator DECELERATE = new PathInterpolator(0f, 0f, 0.5f, 1f);
+
// Create the default emphasized interpolator
private static PathInterpolator createEmphasizedInterpolator() {
Path path = new Path();
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 fc5ff01..8ec297e 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
@@ -18,7 +18,6 @@
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.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
@@ -37,7 +36,7 @@
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
-import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.window.BackEvent;
import android.window.BackMotionEvent;
@@ -46,6 +45,8 @@
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.annotations.ShellMainThread;
import javax.inject.Inject;
@@ -68,32 +69,18 @@
private static final int BACKGROUNDCOLOR = 0x43433A;
/**
- * Minimum scale of the entering window.
+ * Minimum scale of the entering and closing window.
*/
- private static final float ENTERING_MIN_WINDOW_SCALE = 0.85f;
+ private static final float MIN_WINDOW_SCALE = 0.8f;
- /**
- * Minimum scale of the closing window.
- */
- private static final float CLOSING_MIN_WINDOW_SCALE = 0.75f;
-
- /**
- * Minimum color scale of the closing window.
- */
- private static final float CLOSING_MIN_WINDOW_COLOR_SCALE = 0.1f;
-
- /**
- * The margin between the entering window and the closing window
- */
- private static final int WINDOW_MARGIN = 35;
-
- /** Max window translation in the Y axis. */
- private static final int WINDOW_MAX_DELTA_Y = 160;
+ /** Duration of post animation after gesture committed. */
+ private static final int POST_ANIMATION_DURATION_MS = 500;
private final Rect mStartTaskRect = new Rect();
private final float mCornerRadius;
// The closing window properties.
+ private final Rect mClosingStartRect = new Rect();
private final RectF mClosingCurrentRect = new RectF();
// The entering window properties.
@@ -101,44 +88,32 @@
private final RectF mEnteringCurrentRect = new RectF();
private final PointF mInitialTouchPos = new PointF();
- private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
-
+ private final Interpolator mPostAnimationInterpolator = Interpolators.EMPHASIZED;
+ private final Interpolator mYMovementInterpolator = Interpolators.DECELERATE;
+ private final Interpolator mProgressInterpolator = new DecelerateInterpolator();
private final Matrix mTransformMatrix = new Matrix();
private final float[] mTmpFloat9 = new float[9];
- private final float[] mTmpTranslate = {0, 0, 0};
private final BackAnimationRunner mBackAnimationRunner;
private final BackAnimationBackground mBackground;
private final Context mContext;
private RemoteAnimationTarget mEnteringTarget;
private RemoteAnimationTarget mClosingTarget;
- private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+ private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
private boolean mBackInProgress = false;
- private boolean mIsRightEdge;
- private float mProgress = 0;
- private PointF mTouchPos = new PointF();
+ private final PointF mTouchPos = new PointF();
private IRemoteAnimationFinishedCallback mFinishCallback;
- private BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
+ private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
+ private float mInterWindowMargin;
+ private float mVerticalMargin;
@Inject
public CrossTaskBackAnimation(Context context, BackAnimationBackground background) {
- mContext = context;
mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
mBackAnimationRunner = new BackAnimationRunner(
new Callback(), new Runner(), context, CUJ_PREDICTIVE_BACK_CROSS_TASK);
mBackground = background;
- }
-
- private static void computeScaleTransformMatrix(float scale, float[] matrix) {
- matrix[0] = scale;
- matrix[1] = 0;
- matrix[2] = 0;
- matrix[3] = 0;
- matrix[4] = scale;
- matrix[5] = 0;
- matrix[6] = 0;
- matrix[7] = 0;
- matrix[8] = scale;
+ mContext = context;
}
private static float mapRange(float value, float min, float max) {
@@ -146,7 +121,7 @@
}
private float getInterpolatedProgress(float backProgress) {
- return 1 - (1 - backProgress) * (1 - backProgress) * (1 - backProgress);
+ return mProgressInterpolator.getInterpolation(backProgress);
}
private void startBackAnimation() {
@@ -162,6 +137,10 @@
// Draw background.
mBackground.ensureBackground(mClosingTarget.windowConfiguration.getBounds(),
BACKGROUNDCOLOR, mTransaction);
+ mInterWindowMargin = mContext.getResources()
+ .getDimension(R.dimen.cross_task_back_inter_window_margin);
+ mVerticalMargin = mContext.getResources()
+ .getDimension(R.dimen.cross_task_back_vertical_margin);
}
private void updateGestureBackProgress(float progress, BackEvent event) {
@@ -169,44 +148,38 @@
return;
}
- float touchX = event.getTouchX();
float touchY = event.getTouchY();
- float dX = Math.abs(touchX - mInitialTouchPos.x);
// The 'follow width' is the width of the window if it completely matches
// the gesture displacement.
final int width = mStartTaskRect.width();
final int height = mStartTaskRect.height();
- // The 'progress width' is the width of the window if it strictly linearly interpolates
- // to minimum scale base on progress.
- float enteringScale = mapRange(progress, 1, ENTERING_MIN_WINDOW_SCALE);
- float closingScale = mapRange(progress, 1, CLOSING_MIN_WINDOW_SCALE);
- float closingColorScale = mapRange(progress, 1, CLOSING_MIN_WINDOW_COLOR_SCALE);
+ float scale = mapRange(progress, 1, MIN_WINDOW_SCALE);
+ float scaledWidth = scale * width;
+ float scaledHeight = scale * height;
- // The final width is derived from interpolating between the follow with and progress width
- // using gesture progress.
- float enteringWidth = enteringScale * width;
- float closingWidth = closingScale * width;
- float enteringHeight = (float) height / width * enteringWidth;
- float closingHeight = (float) height / width * closingWidth;
-
- float deltaYRatio = (touchY - mInitialTouchPos.y) / height;
// Base the window movement in the Y axis on the touch movement in the Y axis.
- float deltaY = (float) Math.sin(deltaYRatio * Math.PI * 0.5f) * WINDOW_MAX_DELTA_Y;
- // Move the window along the Y axis.
- float closingTop = (height - closingHeight) * 0.5f + deltaY;
- float enteringTop = (height - enteringHeight) * 0.5f + deltaY;
- // Move the window along the X axis.
- float right = width - (progress * WINDOW_MARGIN);
- float left = right - closingWidth;
+ float rawYDelta = touchY - mInitialTouchPos.y;
+ float yDirection = rawYDelta < 0 ? -1 : 1;
+ // limit yDelta interpretation to 1/2 of screen height in either direction
+ float deltaYRatio = Math.min(height / 2f, Math.abs(rawYDelta)) / (height / 2f);
+ float interpolatedYRatio = mYMovementInterpolator.getInterpolation(deltaYRatio);
+ // limit y-shift so surface never passes 8dp screen margin
+ float deltaY = yDirection * interpolatedYRatio * Math.max(0f,
+ (height - scaledHeight) / 2f - mVerticalMargin);
- mClosingCurrentRect.set(left, closingTop, right, closingTop + closingHeight);
- mEnteringCurrentRect.set(left - enteringWidth - WINDOW_MARGIN, enteringTop,
- left - WINDOW_MARGIN, enteringTop + enteringHeight);
+ // Move the window along the Y axis.
+ float scaledTop = (height - scaledHeight) * 0.5f + deltaY;
+ // Move the window along the X axis.
+ float right = width - (progress * mVerticalMargin);
+ float left = right - scaledWidth;
+
+ mClosingCurrentRect.set(left, scaledTop, right, scaledTop + scaledHeight);
+ mEnteringCurrentRect.set(left - scaledWidth - mInterWindowMargin, scaledTop,
+ left - mInterWindowMargin, scaledTop + scaledHeight);
applyTransform(mClosingTarget.leash, mClosingCurrentRect, mCornerRadius);
- applyColorTransform(mClosingTarget.leash, closingColorScale);
applyTransform(mEnteringTarget.leash, mEnteringCurrentRect, mCornerRadius);
mTransaction.apply();
@@ -214,9 +187,21 @@
}
private void updatePostCommitClosingAnimation(float progress) {
+ float targetLeft =
+ mStartTaskRect.left + (1 - MIN_WINDOW_SCALE) * mStartTaskRect.width() / 2;
+ float targetTop =
+ mStartTaskRect.top + (1 - MIN_WINDOW_SCALE) * mStartTaskRect.height() / 2;
+ float targetWidth = mStartTaskRect.width() * MIN_WINDOW_SCALE;
+ float targetHeight = mStartTaskRect.height() * MIN_WINDOW_SCALE;
+
+ float left = mapRange(progress, mClosingStartRect.left, targetLeft);
+ float top = mapRange(progress, mClosingStartRect.top, targetTop);
+ float width = mapRange(progress, mClosingStartRect.width(), targetWidth);
+ float height = mapRange(progress, mClosingStartRect.height(), targetHeight);
mTransaction.setLayer(mClosingTarget.leash, 0);
- float alpha = mapRange(progress, 1, 0);
- mTransaction.setAlpha(mClosingTarget.leash, alpha);
+
+ mClosingCurrentRect.set(left, top, left + width, top + height);
+ applyTransform(mClosingTarget.leash, mClosingCurrentRect, mCornerRadius);
}
private void updatePostCommitEnteringAnimation(float progress) {
@@ -244,14 +229,6 @@
.setCornerRadius(leash, cornerRadius);
}
- private void applyColorTransform(SurfaceControl leash, float colorScale) {
- if (leash == null) {
- return;
- }
- computeScaleTransformMatrix(colorScale, mTmpFloat9);
- mTransaction.setColorTransform(leash, mTmpFloat9, mTmpTranslate);
- }
-
private void finishAnimation() {
if (mEnteringTarget != null) {
mEnteringTarget.leash.release();
@@ -276,7 +253,8 @@
try {
mFinishCallback.onAnimationFinished();
} catch (RemoteException e) {
- e.printStackTrace();
+ ProtoLog.e(WM_SHELL_BACK_PREVIEW,
+ "RemoteException when invoking onAnimationFinished callback");
}
mFinishCallback = null;
}
@@ -285,12 +263,11 @@
private void onGestureProgress(@NonNull BackEvent backEvent) {
if (!mBackInProgress) {
mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
- mIsRightEdge = backEvent.getSwipeEdge() == EDGE_RIGHT;
mBackInProgress = true;
}
- mProgress = backEvent.getProgress();
+ float progress = backEvent.getProgress();
mTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
- updateGestureBackProgress(getInterpolatedProgress(mProgress), backEvent);
+ updateGestureBackProgress(getInterpolatedProgress(progress), backEvent);
}
private void onGestureCommitted() {
@@ -302,9 +279,11 @@
// 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);
+ mClosingCurrentRect.round(mClosingStartRect);
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(300);
- valueAnimator.setInterpolator(mInterpolator);
+ ValueAnimator valueAnimator =
+ ValueAnimator.ofFloat(1f, 0f).setDuration(POST_ANIMATION_DURATION_MS);
+ valueAnimator.setInterpolator(mPostAnimationInterpolator);
valueAnimator.addUpdateListener(animation -> {
float progress = animation.getAnimatedFraction();
updatePostCommitEnteringAnimation(progress);