diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java index 0451653f49..a11625a346 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java @@ -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 diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index febe360349..79e3c4261b 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -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); diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java index ae7de87be6..8398c48d9e 100644 --- a/quickstep/src/com/android/quickstep/QuickScrubController.java +++ b/quickstep/src/com/android/quickstep/QuickScrubController.java @@ -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, diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index f29cc2257b..28d6366393 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -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 { 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 { 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 { } mClipAnimationHelper.offsetTarget( firstTask.getCurveScaleForInterpolation(interpolation), offsetFromFirstTask, - mActivityControlHelper.getTranslationYForQuickScrub(mActivity)); + mActivityControlHelper.getTranslationYForQuickScrub(mActivity), + QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR); } } diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java index 14b40467ff..c28a6bdc60 100644 --- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java +++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java @@ -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) { diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index af7a735f55..128a19e06a 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -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 DIM_ALPHA = - new FloatProperty("dimAlpha") { + public static final Property DIM_ALPHA_MULTIPLIER = + new FloatProperty("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); diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 4f447b113a..4b2ca45e50 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -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 ZOOM_SCALE = new FloatProperty("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)); } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 87ee076f36..e10f974e2a 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -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 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 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; diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java index 0d388feeb1..8374f98ccc 100644 --- a/src/com/android/launcher3/anim/Interpolators.java +++ b/src/com/android/launcher3/anim/Interpolators.java @@ -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)); + }; + } } \ No newline at end of file