Merge "Significantly reduce gesture feedback when swiping up to home screen." into sc-v2-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
e2455aa1cf
@@ -1307,7 +1307,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
}
|
||||
|
||||
final RectF startRect = new RectF(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx);
|
||||
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mLauncher);
|
||||
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mLauncher,
|
||||
mDeviceProfile);
|
||||
|
||||
// Hook up floating views to the closing window animators.
|
||||
if (floatingIconView != null) {
|
||||
|
||||
@@ -137,6 +137,12 @@ public class LauncherSwipeHandlerV2 extends
|
||||
// opaque until it is ready.
|
||||
private boolean mIsFloatingIconReady = false;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected View getViewIgnoredInWorkspaceRevealAnimation() {
|
||||
return workspaceView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RectF getWindowTargetRect() {
|
||||
super.getWindowTargetRect();
|
||||
|
||||
@@ -295,7 +295,7 @@ public abstract class SwipeUpAnimationLogic implements
|
||||
taskViewSimulator.getCurrentCornerRadius(),
|
||||
homeAnimationFactory.getEndRadius(cropRectF));
|
||||
} else {
|
||||
anim = new RectFSpringAnim(startRect, targetRect, mContext);
|
||||
anim = new RectFSpringAnim(startRect, targetRect, mContext, mDp);
|
||||
}
|
||||
homeAnimationFactory.setAnimation(anim);
|
||||
|
||||
|
||||
@@ -15,24 +15,31 @@
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
|
||||
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.FlingSpringAnim;
|
||||
import com.android.launcher3.touch.OverScroll;
|
||||
import com.android.launcher3.util.DynamicResource;
|
||||
import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
|
||||
import com.android.systemui.plugins.ResourceProvider;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -94,7 +101,6 @@ public class RectFSpringAnim extends ReleaseCheck {
|
||||
private float mCurrentCenterX;
|
||||
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;
|
||||
@@ -105,20 +111,68 @@ public class RectFSpringAnim extends ReleaseCheck {
|
||||
private boolean mRectScaleAnimEnded;
|
||||
|
||||
private float mMinVisChange;
|
||||
private float mYOvershoot;
|
||||
private int mMaxVelocityPxPerS;
|
||||
|
||||
public RectFSpringAnim(RectF startRect, RectF targetRect, Context context) {
|
||||
/**
|
||||
* Indicates which part of the start & target rects we are interpolating between.
|
||||
*/
|
||||
public static final int TRACKING_TOP = 0;
|
||||
public static final int TRACKING_CENTER = 1;
|
||||
public static final int TRACKING_BOTTOM = 2;
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef(value = {TRACKING_TOP,
|
||||
TRACKING_CENTER,
|
||||
TRACKING_BOTTOM})
|
||||
public @interface Tracking{}
|
||||
|
||||
@Tracking
|
||||
public final int mTracking;
|
||||
|
||||
public RectFSpringAnim(RectF startRect, RectF targetRect, Context context,
|
||||
@Nullable DeviceProfile deviceProfile) {
|
||||
mStartRect = startRect;
|
||||
mTargetRect = targetRect;
|
||||
mCurrentCenterX = mStartRect.centerX();
|
||||
|
||||
mTrackingBottomY = startRect.bottom < targetRect.bottom;
|
||||
mCurrentY = mTrackingBottomY ? mStartRect.bottom : mStartRect.top;
|
||||
|
||||
ResourceProvider rp = DynamicResource.provider(context);
|
||||
mMinVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
|
||||
mYOvershoot = rp.getDimension(R.dimen.swipe_up_y_overshoot);
|
||||
mMaxVelocityPxPerS = (int) rp.getDimension(R.dimen.swipe_up_max_velocity);
|
||||
setCanRelease(true);
|
||||
|
||||
if (deviceProfile == null) {
|
||||
mTracking = startRect.bottom < targetRect.bottom
|
||||
? TRACKING_BOTTOM
|
||||
: TRACKING_TOP;
|
||||
} else {
|
||||
int heightPx = deviceProfile.heightPx;
|
||||
Rect padding = deviceProfile.workspacePadding;
|
||||
|
||||
final float topThreshold = heightPx / 3f;
|
||||
final float bottomThreshold = deviceProfile.heightPx - padding.bottom;
|
||||
|
||||
if (targetRect.bottom > bottomThreshold) {
|
||||
mTracking = TRACKING_BOTTOM;
|
||||
} else if (targetRect.top < topThreshold) {
|
||||
mTracking = TRACKING_TOP;
|
||||
} else {
|
||||
mTracking = TRACKING_CENTER;
|
||||
}
|
||||
}
|
||||
|
||||
mCurrentY = getTrackedYFromRect(mStartRect);
|
||||
}
|
||||
|
||||
private float getTrackedYFromRect(RectF rect) {
|
||||
switch (mTracking) {
|
||||
case TRACKING_TOP:
|
||||
return rect.top;
|
||||
case TRACKING_BOTTOM:
|
||||
return rect.bottom;
|
||||
case TRACKING_CENTER:
|
||||
default:
|
||||
return rect.centerY();
|
||||
}
|
||||
}
|
||||
|
||||
public void onTargetPositionChanged() {
|
||||
@@ -127,10 +181,22 @@ public class RectFSpringAnim extends ReleaseCheck {
|
||||
}
|
||||
|
||||
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);
|
||||
switch (mTracking) {
|
||||
case TRACKING_TOP:
|
||||
if (mRectYAnim.getTargetPosition() != mTargetRect.top) {
|
||||
mRectYAnim.updatePosition(mCurrentY, mTargetRect.top);
|
||||
}
|
||||
break;
|
||||
case TRACKING_BOTTOM:
|
||||
if (mRectYAnim.getTargetPosition() != mTargetRect.bottom) {
|
||||
mRectYAnim.updatePosition(mCurrentY, mTargetRect.bottom);
|
||||
}
|
||||
break;
|
||||
case TRACKING_CENTER:
|
||||
if (mRectYAnim.getTargetPosition() != mTargetRect.centerY()) {
|
||||
mRectYAnim.updatePosition(mCurrentY, mTargetRect.centerY());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,22 +225,29 @@ public class RectFSpringAnim extends ReleaseCheck {
|
||||
maybeOnEnd();
|
||||
});
|
||||
|
||||
// We dampen the user velocity here to keep the natural feeling and to prevent the
|
||||
// rect from straying too from a linear path.
|
||||
final float xVelocityPxPerS = velocityPxPerMs.x * 1000;
|
||||
final float yVelocityPxPerS = velocityPxPerMs.y * 1000;
|
||||
final float dampedXVelocityPxPerS = OverScroll.dampedScroll(
|
||||
Math.abs(xVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(xVelocityPxPerS);
|
||||
final float dampedYVelocityPxPerS = OverScroll.dampedScroll(
|
||||
Math.abs(yVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(yVelocityPxPerS);
|
||||
|
||||
float startX = mCurrentCenterX;
|
||||
float endX = mTargetRect.centerX();
|
||||
float minXValue = Math.min(startX, endX);
|
||||
float maxXValue = Math.max(startX, endX);
|
||||
mRectXAnim = new FlingSpringAnim(this, context, 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;
|
||||
mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
|
||||
dampedXVelocityPxPerS, mMinVisChange, minXValue, maxXValue, onXEndListener);
|
||||
|
||||
float startY = mCurrentY;
|
||||
float endY = mTrackingBottomY ? mTargetRect.bottom : mTargetRect.top;
|
||||
float minYValue = Math.min(startY, endY - mYOvershoot);
|
||||
float endY = getTrackedYFromRect(mTargetRect);
|
||||
float minYValue = Math.min(startY, endY);
|
||||
float maxYValue = Math.max(startY, endY);
|
||||
mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY, startVelocityY,
|
||||
mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);
|
||||
mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY, dampedYVelocityPxPerS,
|
||||
mMinVisChange, minYValue, maxYValue, onYEndListener);
|
||||
|
||||
float minVisibleChange = Math.abs(1f / mStartRect.height());
|
||||
ResourceProvider rp = DynamicResource.provider(context);
|
||||
@@ -234,12 +307,25 @@ public class RectFSpringAnim extends ReleaseCheck {
|
||||
mTargetRect.width());
|
||||
float currentHeight = Utilities.mapRange(mCurrentScaleProgress, mStartRect.height(),
|
||||
mTargetRect.height());
|
||||
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);
|
||||
switch (mTracking) {
|
||||
case TRACKING_TOP:
|
||||
mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
|
||||
mCurrentY,
|
||||
mCurrentCenterX + currentWidth / 2,
|
||||
mCurrentY + currentHeight);
|
||||
break;
|
||||
case TRACKING_BOTTOM:
|
||||
mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
|
||||
mCurrentY - currentHeight,
|
||||
mCurrentCenterX + currentWidth / 2,
|
||||
mCurrentY);
|
||||
break;
|
||||
case TRACKING_CENTER:
|
||||
mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
|
||||
mCurrentY - currentHeight / 2,
|
||||
mCurrentCenterX + currentWidth / 2,
|
||||
mCurrentY + currentHeight / 2);
|
||||
break;
|
||||
}
|
||||
for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
|
||||
onUpdateListener.onUpdate(null, mCurrentRect, mCurrentScaleProgress);
|
||||
|
||||
@@ -132,7 +132,7 @@ public class RectFSpringAnim2 extends RectFSpringAnim {
|
||||
|
||||
public RectFSpringAnim2(RectF startRect, RectF targetRect, Context context, float startRadius,
|
||||
float endRadius) {
|
||||
super(startRect, targetRect, context);
|
||||
super(startRect, targetRect, context, null);
|
||||
mStartRect = startRect;
|
||||
mTargetRect = targetRect;
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
@NonNull Rect destinationBoundsTransformed,
|
||||
int cornerRadius,
|
||||
@NonNull View view) {
|
||||
super(startBounds, new RectF(destinationBoundsTransformed), context);
|
||||
super(startBounds, new RectF(destinationBoundsTransformed), context, null);
|
||||
mTaskId = taskId;
|
||||
mComponentName = componentName;
|
||||
mLeash = leash;
|
||||
|
||||
@@ -184,8 +184,8 @@
|
||||
|
||||
<!-- Swipe up to home related -->
|
||||
<dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
|
||||
<dimen name="swipe_up_y_overshoot">10dp</dimen>
|
||||
<dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
|
||||
<dimen name="swipe_up_max_velocity">7.619dp</dimen>
|
||||
|
||||
<array name="dynamic_resources">
|
||||
<item>@dimen/swipe_up_duration</item>
|
||||
@@ -201,6 +201,7 @@
|
||||
<item>@dimen/swipe_up_launcher_alpha_max_progress</item>
|
||||
<item>@dimen/swipe_up_rect_2_y_stiffness_low_swipe_multiplier</item>
|
||||
<item>@dimen/swipe_up_low_swipe_duration_multiplier</item>
|
||||
<item>@dimen/swipe_up_max_velocity</item>
|
||||
|
||||
<item>@dimen/c1_a</item>
|
||||
<item>@dimen/c1_b</item>
|
||||
|
||||
@@ -40,8 +40,8 @@ public class FlingSpringAnim {
|
||||
private float mTargetPosition;
|
||||
|
||||
public <K> FlingSpringAnim(K object, Context context, FloatPropertyCompat<K> property,
|
||||
float startPosition, float targetPosition, float startVelocity, float minVisChange,
|
||||
float minValue, float maxValue, float springVelocityFactor,
|
||||
float startPosition, float targetPosition, float startVelocityPxPerS,
|
||||
float minVisChange, float minValue, float maxValue,
|
||||
OnAnimationEndListener onEndListener) {
|
||||
ResourceProvider rp = DynamicResource.provider(context);
|
||||
float damping = rp.getFloat(R.dimen.swipe_up_rect_xy_damping_ratio);
|
||||
@@ -53,19 +53,19 @@ public class FlingSpringAnim {
|
||||
// Have the spring pull towards the target if we've slowed down too much before
|
||||
// reaching it.
|
||||
.setMinimumVisibleChange(minVisChange)
|
||||
.setStartVelocity(startVelocity)
|
||||
.setStartVelocity(startVelocityPxPerS)
|
||||
.setMinValue(minValue)
|
||||
.setMaxValue(maxValue);
|
||||
mTargetPosition = targetPosition;
|
||||
|
||||
// We are already past the fling target, so skip it to avoid losing a frame of the spring.
|
||||
mSkipFlingAnim = startPosition <= minValue && startVelocity < 0
|
||||
|| startPosition >= maxValue && startVelocity > 0;
|
||||
mSkipFlingAnim = startPosition <= minValue && startVelocityPxPerS < 0
|
||||
|| startPosition >= maxValue && startVelocityPxPerS > 0;
|
||||
|
||||
mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> {
|
||||
mSpringAnim = new SpringAnimation(object, property)
|
||||
.setStartValue(value)
|
||||
.setStartVelocity(velocity * springVelocityFactor)
|
||||
.setStartVelocity(velocity)
|
||||
.setSpring(new SpringForce(mTargetPosition)
|
||||
.setStiffness(stiffness)
|
||||
.setDampingRatio(damping));
|
||||
|
||||
Reference in New Issue
Block a user