Tune quick scrub
- Change durations/interpolators when starting from home vs an app - Increase dim animation duration after quick scrub from an app - Also fixed contention between setting dim alpha for the animation and setting dim alpha for scrolling Change-Id: I2c9ea52d4eafaad8954f3ff9d3c0c459a07953bc
This commit is contained in:
parent
99dcc9fd83
commit
d58c2d5a48
|
@ -28,7 +28,7 @@ public class FastOverviewState extends OverviewState {
|
|||
| FLAG_OVERVIEW_UI | FLAG_HIDE_BACK_BUTTON | FLAG_DISABLE_ACCESSIBILITY;
|
||||
|
||||
public FastOverviewState(int id) {
|
||||
super(id, QuickScrubController.QUICK_SCRUB_START_DURATION, STATE_FLAGS);
|
||||
super(id, QuickScrubController.QUICK_SCRUB_FROM_HOME_START_DURATION, STATE_FLAGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,6 +17,8 @@ package com.android.launcher3.uioverrides;
|
|||
|
||||
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR;
|
||||
import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_TRANSLATION_Y_FACTOR;
|
||||
import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_Y_FACTOR;
|
||||
import static com.android.quickstep.views.RecentsView.ADJACENT_SCALE;
|
||||
import static com.android.quickstep.views.RecentsViewContainer.CONTENT_ALPHA;
|
||||
|
@ -24,12 +26,14 @@ import static com.android.quickstep.views.RecentsViewContainer.CONTENT_ALPHA;
|
|||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager.AnimationConfig;
|
||||
import com.android.launcher3.LauncherStateManager.StateHandler;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.quickstep.views.LauncherRecentsView;
|
||||
import com.android.quickstep.views.RecentsViewContainer;
|
||||
|
@ -69,7 +73,13 @@ public class RecentsViewStateController implements StateHandler {
|
|||
PropertySetter setter = config.getPropertySetter(builder);
|
||||
float[] scaleTranslationYFactor = toState.getOverviewScaleAndTranslationYFactor(mLauncher);
|
||||
setter.setFloat(mRecentsView, ADJACENT_SCALE, scaleTranslationYFactor[0], LINEAR);
|
||||
setter.setFloat(mRecentsView, TRANSLATION_Y_FACTOR, scaleTranslationYFactor[1], LINEAR);
|
||||
Interpolator transYInterpolator = LINEAR;
|
||||
if (toState == LauncherState.FAST_OVERVIEW) {
|
||||
transYInterpolator = Interpolators.clampToProgress(QUICK_SCRUB_START_INTERPOLATOR, 0,
|
||||
QUICK_SCRUB_TRANSLATION_Y_FACTOR);
|
||||
}
|
||||
setter.setFloat(mRecentsView, TRANSLATION_Y_FACTOR, scaleTranslationYFactor[1],
|
||||
transYInterpolator);
|
||||
setter.setFloat(mRecentsViewContainer, CONTENT_ALPHA, toState.overviewUi ? 1 : 0,
|
||||
AGGRESSIVE_EASE_IN_OUT);
|
||||
|
||||
|
|
|
@ -16,8 +16,11 @@
|
|||
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.Alarm;
|
||||
import com.android.launcher3.BaseActivity;
|
||||
|
@ -37,7 +40,11 @@ import com.android.quickstep.views.TaskView;
|
|||
*/
|
||||
public class QuickScrubController implements OnAlarmListener {
|
||||
|
||||
public static final int QUICK_SCRUB_START_DURATION = 210;
|
||||
public static final int QUICK_SCRUB_FROM_APP_START_DURATION = 240;
|
||||
public static final int QUICK_SCRUB_FROM_HOME_START_DURATION = 150;
|
||||
// We want the translation y to finish faster than the rest of the animation.
|
||||
public static final float QUICK_SCRUB_TRANSLATION_Y_FACTOR = 5f / 6;
|
||||
public static final Interpolator QUICK_SCRUB_START_INTERPOLATOR = FAST_OUT_SLOW_IN;
|
||||
|
||||
/**
|
||||
* Snap to a new page when crossing these thresholds. The first and last auto-advance.
|
||||
|
@ -168,23 +175,27 @@ public class QuickScrubController implements OnAlarmListener {
|
|||
|
||||
public void snapToNextTaskIfAvailable() {
|
||||
if (mInQuickScrub && mRecentsView.getChildCount() > 0) {
|
||||
int duration = mStartedFromHome ? QUICK_SCRUB_FROM_HOME_START_DURATION
|
||||
: QUICK_SCRUB_FROM_APP_START_DURATION;
|
||||
int pageToGoTo = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1;
|
||||
goToPageWithHaptic(pageToGoTo, QUICK_SCRUB_START_DURATION, true /* forceHaptic */);
|
||||
goToPageWithHaptic(pageToGoTo, duration, true /* forceHaptic */,
|
||||
QUICK_SCRUB_START_INTERPOLATOR);
|
||||
}
|
||||
}
|
||||
|
||||
private void goToPageWithHaptic(int pageToGoTo) {
|
||||
goToPageWithHaptic(pageToGoTo, -1 /* overrideDuration */, false /* forceHaptic */);
|
||||
goToPageWithHaptic(pageToGoTo, -1 /* overrideDuration */, false /* forceHaptic */, null);
|
||||
}
|
||||
|
||||
private void goToPageWithHaptic(int pageToGoTo, int overrideDuration, boolean forceHaptic) {
|
||||
private void goToPageWithHaptic(int pageToGoTo, int overrideDuration, boolean forceHaptic,
|
||||
Interpolator interpolator) {
|
||||
pageToGoTo = Utilities.boundToRange(pageToGoTo, 0, mRecentsView.getPageCount() - 1);
|
||||
boolean snappingToPage = pageToGoTo != mRecentsView.getNextPage();
|
||||
if (snappingToPage) {
|
||||
int duration = overrideDuration > -1 ? overrideDuration
|
||||
: Math.abs(pageToGoTo - mRecentsView.getNextPage())
|
||||
* QUICKSCRUB_SNAP_DURATION_PER_PAGE;
|
||||
mRecentsView.snapToPage(pageToGoTo, duration);
|
||||
mRecentsView.snapToPage(pageToGoTo, duration, interpolator);
|
||||
}
|
||||
if (snappingToPage || forceHaptic) {
|
||||
mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
|
||||
|
|
|
@ -17,11 +17,9 @@ package com.android.quickstep;
|
|||
|
||||
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
|
||||
import static com.android.launcher3.Utilities.postAsyncCallback;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||
import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_START_DURATION;
|
||||
import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_FROM_APP_START_DURATION;
|
||||
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
|
||||
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
|
||||
|
||||
|
@ -455,7 +453,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
|||
setStateOnUiThread(STATE_QUICK_SCRUB_START | STATE_GESTURE_COMPLETED);
|
||||
|
||||
// Start the window animation without waiting for launcher.
|
||||
animateToProgress(1f, QUICK_SCRUB_START_DURATION, TOUCH_RESPONSE_INTERPOLATOR);
|
||||
animateToProgress(1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
|
@ -502,10 +500,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
|||
|
||||
RecentsAnimationControllerCompat controller = mRecentsAnimationWrapper.getController();
|
||||
if (controller != null) {
|
||||
Interpolator interpolator = mInteractionType == INTERACTION_QUICK_SCRUB
|
||||
? ACCEL_2 : LINEAR;
|
||||
float interpolated = interpolator.getInterpolation(shift);
|
||||
mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet, interpolated);
|
||||
mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet, shift);
|
||||
|
||||
// TODO: This logic is spartanic!
|
||||
boolean passedThreshold = shift > 0.12f;
|
||||
|
@ -793,7 +788,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
|||
}
|
||||
mClipAnimationHelper.offsetTarget(
|
||||
firstTask.getCurveScaleForInterpolation(interpolation), offsetFromFirstTask,
|
||||
mActivityControlHelper.getTranslationYForQuickScrub(mActivity));
|
||||
mActivityControlHelper.getTranslationYForQuickScrub(mActivity),
|
||||
QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.SCROLL;
|
||||
import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_TRANSLATION_Y_FACTOR;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
|
@ -30,11 +30,13 @@ import android.graphics.RectF;
|
|||
import android.os.Build;
|
||||
import android.os.RemoteException;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
@ -78,6 +80,9 @@ public class ClipAnimationHelper {
|
|||
private final RectF mTmpRectF = new RectF();
|
||||
|
||||
private float mTargetScale = 1f;
|
||||
private Interpolator mInterpolator = LINEAR;
|
||||
// We translate y slightly faster than the rest of the animation for quick scrub.
|
||||
private Interpolator mOffsetYInterpolator = LINEAR;
|
||||
|
||||
// Whether to boost the opening animation target layers, or the closing
|
||||
private int mBoostModeTargetLayers = -1;
|
||||
|
@ -134,12 +139,13 @@ public class ClipAnimationHelper {
|
|||
RectF currentRect;
|
||||
mTmpRectF.set(mTargetRect);
|
||||
Utilities.scaleRectFAboutCenter(mTmpRectF, mTargetScale);
|
||||
float offsetYProgress = mOffsetYInterpolator.getInterpolation(progress);
|
||||
progress = mInterpolator.getInterpolation(progress);
|
||||
currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTmpRectF);
|
||||
|
||||
synchronized (mTargetOffset) {
|
||||
// Stay lined up with the center of the target, since it moves for quick scrub.
|
||||
currentRect.offset(mTargetOffset.x * SCROLL.getInterpolation(progress),
|
||||
mTargetOffset.y * LINEAR.getInterpolation(progress));
|
||||
currentRect.offset(mTargetOffset.x * progress, mTargetOffset.y * offsetYProgress);
|
||||
}
|
||||
|
||||
mClipRect.left = (int) (mSourceWindowClipInsets.left * progress);
|
||||
|
@ -180,11 +186,14 @@ public class ClipAnimationHelper {
|
|||
mTaskTransformCallback = callback;
|
||||
}
|
||||
|
||||
public void offsetTarget(float scale, float offsetX, float offsetY) {
|
||||
public void offsetTarget(float scale, float offsetX, float offsetY, Interpolator interpolator) {
|
||||
synchronized (mTargetOffset) {
|
||||
mTargetScale = scale;
|
||||
mTargetOffset.set(offsetX, offsetY);
|
||||
}
|
||||
mTargetScale = scale;
|
||||
mInterpolator = interpolator;
|
||||
mOffsetYInterpolator = Interpolators.clampToProgress(mInterpolator, 0,
|
||||
QUICK_SCRUB_TRANSLATION_Y_FACTOR);
|
||||
}
|
||||
|
||||
public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
|
||||
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -52,16 +51,16 @@ public class TaskThumbnailView extends View {
|
|||
|
||||
private static final LightingColorFilter[] sDimFilterCache = new LightingColorFilter[256];
|
||||
|
||||
public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
|
||||
new FloatProperty<TaskThumbnailView>("dimAlpha") {
|
||||
public static final Property<TaskThumbnailView, Float> DIM_ALPHA_MULTIPLIER =
|
||||
new FloatProperty<TaskThumbnailView>("dimAlphaMultiplier") {
|
||||
@Override
|
||||
public void setValue(TaskThumbnailView thumbnail, float dimAlpha) {
|
||||
thumbnail.setDimAlpha(dimAlpha);
|
||||
public void setValue(TaskThumbnailView thumbnail, float dimAlphaMultiplier) {
|
||||
thumbnail.setDimAlphaMultipler(dimAlphaMultiplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(TaskThumbnailView thumbnailView) {
|
||||
return thumbnailView.mDimAlpha;
|
||||
return thumbnailView.mDimAlphaMultiplier;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -81,6 +80,7 @@ public class TaskThumbnailView extends View {
|
|||
protected BitmapShader mBitmapShader;
|
||||
|
||||
private float mDimAlpha = 1f;
|
||||
private float mDimAlphaMultiplier = 1f;
|
||||
|
||||
public TaskThumbnailView(Context context) {
|
||||
this(context, null);
|
||||
|
@ -128,6 +128,11 @@ public class TaskThumbnailView extends View {
|
|||
updateThumbnailPaintFilter();
|
||||
}
|
||||
|
||||
public void setDimAlphaMultipler(float dimAlphaMultipler) {
|
||||
mDimAlphaMultiplier = dimAlphaMultipler;
|
||||
setDimAlpha(mDimAlpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alpha of the dim layer on top of this view.
|
||||
*
|
||||
|
@ -191,7 +196,7 @@ public class TaskThumbnailView extends View {
|
|||
}
|
||||
|
||||
private void updateThumbnailPaintFilter() {
|
||||
int mul = (int) ((1 - mDimAlpha) * 255);
|
||||
int mul = (int) ((1 - mDimAlpha * mDimAlphaMultiplier) * 255);
|
||||
if (mBitmapShader != null) {
|
||||
LightingColorFilter filter = getLightingColorFilter(mul);
|
||||
mPaint.setColorFilter(filter);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package com.android.quickstep.views;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
|
||||
import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA_MULTIPLIER;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
|
@ -78,6 +78,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
|
|||
private static final float EDGE_SCALE_DOWN_FACTOR = 0.03f;
|
||||
|
||||
public static final long SCALE_ICON_DURATION = 120;
|
||||
private static final long DIM_ANIM_DURATION = 700;
|
||||
|
||||
public static final Property<TaskView, Float> ZOOM_SCALE =
|
||||
new FloatProperty<TaskView>("zoomScale") {
|
||||
|
@ -97,7 +98,6 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
|
|||
private IconView mIconView;
|
||||
private float mCurveScale;
|
||||
private float mZoomScale;
|
||||
private float mCurveDimAlpha;
|
||||
private Animator mDimAlphaAnim;
|
||||
|
||||
public TaskView(Context context) {
|
||||
|
@ -200,8 +200,9 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
|
|||
|
||||
public void animateIconToScaleAndDim(float scale) {
|
||||
mIconView.animate().scaleX(scale).scaleY(scale).setDuration(SCALE_ICON_DURATION).start();
|
||||
mDimAlphaAnim = ObjectAnimator.ofFloat(mSnapshotView, DIM_ALPHA, scale * mCurveDimAlpha);
|
||||
mDimAlphaAnim.setDuration(SCALE_ICON_DURATION);
|
||||
mDimAlphaAnim = ObjectAnimator.ofFloat(mSnapshotView, DIM_ALPHA_MULTIPLIER, 1 - scale,
|
||||
scale);
|
||||
mDimAlphaAnim.setDuration(DIM_ANIM_DURATION);
|
||||
mDimAlphaAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
|
@ -218,7 +219,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
|
|||
if (mDimAlphaAnim != null) {
|
||||
mDimAlphaAnim.cancel();
|
||||
}
|
||||
mSnapshotView.setDimAlpha(iconScale * mCurveDimAlpha);
|
||||
mSnapshotView.setDimAlphaMultipler(iconScale);
|
||||
}
|
||||
|
||||
public void resetVisualProperties() {
|
||||
|
@ -235,11 +236,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
|
|||
float curveInterpolation =
|
||||
CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation);
|
||||
|
||||
mCurveDimAlpha = curveInterpolation * MAX_PAGE_SCRIM_ALPHA;
|
||||
if (mDimAlphaAnim == null && mIconView.getScaleX() > 0) {
|
||||
mSnapshotView.setDimAlpha(mCurveDimAlpha);
|
||||
}
|
||||
|
||||
mSnapshotView.setDimAlpha(curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
|
||||
setCurveScale(getCurveScaleForCurveInterpolation(curveInterpolation));
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import android.content.res.TypedArray;
|
|||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.InputDevice;
|
||||
|
@ -44,6 +45,7 @@ import android.view.animation.Interpolator;
|
|||
import android.widget.ScrollView;
|
||||
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.pageindicators.PageIndicator;
|
||||
import com.android.launcher3.touch.OverScroll;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
|
@ -1422,7 +1424,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||
return snapToPage(whichPage, duration, false, null);
|
||||
}
|
||||
|
||||
protected boolean snapToPage(int whichPage, int duration, TimeInterpolator interpolator) {
|
||||
public boolean snapToPage(int whichPage, int duration, TimeInterpolator interpolator) {
|
||||
return snapToPage(whichPage, duration, false, interpolator);
|
||||
}
|
||||
|
||||
|
@ -1441,6 +1443,12 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
|||
|
||||
protected boolean snapToPage(int whichPage, int delta, int duration, boolean immediate,
|
||||
TimeInterpolator interpolator) {
|
||||
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
duration *= Settings.System.getFloat(getContext().getContentResolver(),
|
||||
Settings.System.WINDOW_ANIMATION_SCALE, 1);
|
||||
}
|
||||
|
||||
whichPage = validateNewPage(whichPage);
|
||||
|
||||
mNextPage = whichPage;
|
||||
|
|
|
@ -115,4 +115,24 @@ public class Interpolators {
|
|||
public static Interpolator scrollInterpolatorForVelocity(float velocity) {
|
||||
return Math.abs(velocity) > FAST_FLING_PX_MS ? SCROLL : SCROLL_CUBIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given interpolator such that the entire progress is set between the given bounds.
|
||||
* That is, we set the interpolation to 0 until lowerBound and reach 1 by upperBound.
|
||||
*/
|
||||
public static Interpolator clampToProgress(Interpolator interpolator, float lowerBound,
|
||||
float upperBound) {
|
||||
if (upperBound <= lowerBound) {
|
||||
throw new IllegalArgumentException("lowerBound must be less than upperBound");
|
||||
}
|
||||
return t -> {
|
||||
if (t < lowerBound) {
|
||||
return 0;
|
||||
}
|
||||
if (t > upperBound) {
|
||||
return 1;
|
||||
}
|
||||
return interpolator.getInterpolation((t - lowerBound) / (upperBound - lowerBound));
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue