diff --git a/quickstep/recents_ui_overrides/res/values/dimens.xml b/quickstep/recents_ui_overrides/res/values/dimens.xml index 61c576e82b..b316edd737 100644 --- a/quickstep/recents_ui_overrides/res/values/dimens.xml +++ b/quickstep/recents_ui_overrides/res/values/dimens.xml @@ -23,4 +23,8 @@ 80dp + + + 18dp + 10dp \ No newline at end of file diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index d927d83068..404cfe62ff 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -1077,8 +1077,7 @@ public class WindowTransformSwipeHandler final View floatingView = homeAnimationFactory.getFloatingView(); final boolean isFloatingIconView = floatingView instanceof FloatingIconView; - - RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect); + RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mActivity.getResources()); if (isFloatingIconView) { FloatingIconView fiv = (FloatingIconView) floatingView; anim.addAnimatorListener(fiv); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java index 09db6952f7..3f4ad58ab8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java @@ -19,6 +19,7 @@ import android.animation.Animator; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; +import android.content.res.Resources; import android.graphics.PointF; import android.graphics.RectF; import android.util.FloatProperty; @@ -26,6 +27,7 @@ import android.util.FloatProperty; import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener; import androidx.dynamicanimation.animation.FloatPropertyCompat; +import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.FlingSpringAnim; @@ -63,16 +65,16 @@ public class RectFSpringAnim { } }; - private static final FloatPropertyCompat RECT_CENTER_Y = - new FloatPropertyCompat("rectCenterYSpring") { + private static final FloatPropertyCompat RECT_Y = + new FloatPropertyCompat("rectYSpring") { @Override public float getValue(RectFSpringAnim anim) { - return anim.mCurrentCenterY; + return anim.mCurrentY; } @Override - public void setValue(RectFSpringAnim anim, float currentCenterY) { - anim.mCurrentCenterY = currentCenterY; + public void setValue(RectFSpringAnim anim, float y) { + anim.mCurrentY = y; anim.onUpdate(); } }; @@ -98,7 +100,9 @@ public class RectFSpringAnim { private final List mAnimatorListeners = new ArrayList<>(); private float mCurrentCenterX; - private float mCurrentCenterY; + private float mCurrentY; + // If true, tracking the bottom of the rects, else tracking the top. + private boolean mTrackingBottomY; private float mCurrentScaleProgress; private FlingSpringAnim mRectXAnim; private FlingSpringAnim mRectYAnim; @@ -108,19 +112,32 @@ public class RectFSpringAnim { private boolean mRectYAnimEnded; private boolean mRectScaleAnimEnded; - public RectFSpringAnim(RectF startRect, RectF targetRect) { + private float mMinVisChange; + private float mYOvershoot; + + public RectFSpringAnim(RectF startRect, RectF targetRect, Resources resources) { mStartRect = startRect; mTargetRect = targetRect; mCurrentCenterX = mStartRect.centerX(); - mCurrentCenterY = mStartRect.centerY(); + + mTrackingBottomY = startRect.bottom < targetRect.bottom; + mCurrentY = mTrackingBottomY ? mStartRect.bottom : mStartRect.top; + + mMinVisChange = resources.getDimensionPixelSize(R.dimen.swipe_up_fling_min_visible_change); + mYOvershoot = resources.getDimensionPixelSize(R.dimen.swipe_up_y_overshoot); } public void onTargetPositionChanged() { if (mRectXAnim != null && mRectXAnim.getTargetPosition() != mTargetRect.centerX()) { mRectXAnim.updatePosition(mCurrentCenterX, mTargetRect.centerX()); } - if (mRectYAnim != null && mRectYAnim.getTargetPosition() != mTargetRect.centerY()) { - mRectYAnim.updatePosition(mCurrentCenterY, mTargetRect.centerY()); + + if (mRectYAnim != null) { + if (mTrackingBottomY && mRectYAnim.getTargetPosition() != mTargetRect.bottom) { + mRectYAnim.updatePosition(mCurrentY, mTargetRect.bottom); + } else if (!mTrackingBottomY && mRectYAnim.getTargetPosition() != mTargetRect.top) { + mRectYAnim.updatePosition(mCurrentY, mTargetRect.top); + } } } @@ -142,10 +159,23 @@ public class RectFSpringAnim { mRectYAnimEnded = true; maybeOnEnd(); }); - mRectXAnim = new FlingSpringAnim(this, RECT_CENTER_X, mCurrentCenterX, - mTargetRect.centerX(), velocityPxPerMs.x * 1000, onXEndListener); - mRectYAnim = new FlingSpringAnim(this, RECT_CENTER_Y, mCurrentCenterY, - mTargetRect.centerY(), velocityPxPerMs.y * 1000, onYEndListener); + + float startX = mCurrentCenterX; + float endX = mTargetRect.centerX(); + float minXValue = Math.min(startX, endX); + float maxXValue = Math.max(startX, endX); + mRectXAnim = new FlingSpringAnim(this, RECT_CENTER_X, startX, endX, + velocityPxPerMs.x * 1000, mMinVisChange, minXValue, maxXValue, 1f, onXEndListener); + + float startVelocityY = velocityPxPerMs.y * 1000; + // Scale the Y velocity based on the initial velocity to tune the curves. + float springVelocityFactor = 0.1f + 0.9f * Math.abs(startVelocityY) / 20000.0f; + float startY = mCurrentY; + float endY = mTrackingBottomY ? mTargetRect.bottom : mTargetRect.top; + float minYValue = Math.min(startY, endY - mYOvershoot); + float maxYValue = Math.max(startY, endY); + mRectYAnim = new FlingSpringAnim(this, RECT_Y, startY, endY, startVelocityY, + mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener); mRectScaleAnim = ObjectAnimator.ofPropertyValuesHolder(this, PropertyValuesHolder.ofFloat(RECT_SCALE_PROGRESS, 1)) @@ -182,8 +212,13 @@ public class RectFSpringAnim { mTargetRect.width()); float currentHeight = Utilities.mapRange(mCurrentScaleProgress, mStartRect.height(), mTargetRect.height()); - mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentCenterY - currentHeight / 2, - mCurrentCenterX + currentWidth / 2, mCurrentCenterY + currentHeight / 2); + if (mTrackingBottomY) { + mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentY - currentHeight, + mCurrentCenterX + currentWidth / 2, mCurrentY); + } else { + mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentY, + mCurrentCenterX + currentWidth / 2, mCurrentY + currentHeight); + } for (OnUpdateListener onUpdateListener : mOnUpdateListeners) { onUpdateListener.onUpdate(mCurrentRect, mCurrentScaleProgress); } diff --git a/src/com/android/launcher3/anim/FlingSpringAnim.java b/src/com/android/launcher3/anim/FlingSpringAnim.java index 3d981c136c..f53ea51509 100644 --- a/src/com/android/launcher3/anim/FlingSpringAnim.java +++ b/src/com/android/launcher3/anim/FlingSpringAnim.java @@ -28,8 +28,6 @@ import androidx.dynamicanimation.animation.SpringForce; public class FlingSpringAnim { private static final float FLING_FRICTION = 1.5f; - // Have the spring pull towards the target if we've slowed down too much before reaching it. - private static final float FLING_END_THRESHOLD_PX = 50f; private static final float SPRING_STIFFNESS = 200; private static final float SPRING_DAMPING = 0.85f; @@ -39,23 +37,27 @@ public class FlingSpringAnim { private float mTargetPosition; public FlingSpringAnim(K object, FloatPropertyCompat property, float startPosition, - float targetPosition, float startVelocity, OnAnimationEndListener onEndListener) { + float targetPosition, float startVelocity, float minVisChange, float minValue, + float maxValue, float springVelocityFactor, OnAnimationEndListener onEndListener) { mFlingAnim = new FlingAnimation(object, property) .setFriction(FLING_FRICTION) - .setMinimumVisibleChange(FLING_END_THRESHOLD_PX) + // Have the spring pull towards the target if we've slowed down too much before + // reaching it. + .setMinimumVisibleChange(minVisChange) .setStartVelocity(startVelocity) - .setMinValue(Math.min(startPosition, targetPosition)) - .setMaxValue(Math.max(startPosition, targetPosition)); + .setMinValue(minValue) + .setMaxValue(maxValue); mTargetPosition = targetPosition; mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> { mSpringAnim = new SpringAnimation(object, property) - .setStartVelocity(velocity) + .setStartValue(value) + .setStartVelocity(velocity * springVelocityFactor) .setSpring(new SpringForce(mTargetPosition) .setStiffness(SPRING_STIFFNESS) .setDampingRatio(SPRING_DAMPING)); mSpringAnim.addEndListener(onEndListener); - mSpringAnim.start(); + mSpringAnim.animateToFinalPosition(mTargetPosition); })); }