diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index d3b05763ff..e83c2f3382 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -43,6 +43,7 @@ import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.views.LauncherLayoutListener; +import com.android.quickstep.views.LauncherRecentsView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.RecentsViewContainer; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -65,6 +66,8 @@ public interface ActivityControlHelper { */ boolean onQuickInteractionStart(T activity, boolean activityVisible); + float getTranslationYForQuickScrub(T activity); + void executeOnWindowAvailable(T activity, Runnable action); void onTransitionCancelled(T activity, boolean activityVisible); @@ -117,6 +120,13 @@ public interface ActivityControlHelper { return !fromState.overviewUi; } + @Override + public float getTranslationYForQuickScrub(Launcher activity) { + LauncherRecentsView recentsView = activity.getOverviewPanel(); + float transYFactor = FAST_OVERVIEW.getOverviewScaleAndTranslationYFactor(activity)[1]; + return recentsView.computeTranslationYForFactor(transYFactor); + } + @Override public void executeOnWindowAvailable(Launcher activity, Runnable action) { if (activity.getWorkspace().runOnOverlayHidden(action)) { @@ -275,6 +285,11 @@ public interface ActivityControlHelper { return false; } + @Override + public float getTranslationYForQuickScrub(RecentsActivity activity) { + return 0; + } + @Override public void executeOnWindowAvailable(RecentsActivity activity, Runnable action) { action.run(); diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 25539aa754..dacae75cd9 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -458,17 +458,6 @@ public class WindowTransformSwipeHandler { } mLauncherTransitionController.setPlayFraction(shift); - // Make sure the window follows the first task if it moves, e.g. during quick scrub. - View firstTask = mRecentsView.getPageAt(0); - // The first task may be null if we are swiping up from a task that does not - // appear in the list (ie. the assistant) - if (firstTask != null) { - int scrollForFirstTask = mRecentsView.getScrollForPage(0); - int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX()); - mClipAnimationHelper.offsetTarget(firstTask.getScaleX(), - offsetFromFirstTask + firstTask.getTranslationX(), - mRecentsView.getTranslationY()); - } if (mRecentsAnimationWrapper.controller != null) { // TODO: This logic is spartanic! boolean passedThreshold = shift > 0.12f; @@ -714,11 +703,31 @@ public class WindowTransformSwipeHandler { } private void onQuickScrubStart() { - mActivityControlHelper.onQuickInteractionStart(mActivity, mWasLauncherAlreadyVisible); + if (mLauncherTransitionController != null) { + mLauncherTransitionController.getAnimationPlayer().end(); + mLauncherTransitionController = null; + } + + mActivityControlHelper.onQuickInteractionStart(mActivity, false); mQuickScrubController.onQuickScrubStart(false); // Inform the last progress in case we skipped before. mQuickScrubController.onQuickScrubProgress(mCurrentQuickScrubProgress); + + // Make sure the window follows the first task if it moves, e.g. during quick scrub. + TaskView firstTask = mRecentsView.getPageAt(0); + // The first task may be null if we are swiping up from a task that does not + // appear in the list (i.e. the assistant) + if (firstTask != null) { + int scrollForFirstTask = mRecentsView.getScrollForPage(0); + int scrollForSecondTask = mRecentsView.getChildCount() > 1 + ? mRecentsView.getScrollForPage(1) : scrollForFirstTask; + int offsetFromFirstTask = scrollForFirstTask - scrollForSecondTask; + float interpolation = offsetFromFirstTask / (mRecentsView.getWidth() / 2); + mClipAnimationHelper.offsetTarget( + firstTask.getCurveScaleForInterpolation(interpolation), offsetFromFirstTask, + mActivityControlHelper.getTranslationYForQuickScrub(mActivity)); + } } private void onFinishedTransitionToQuickScrub() { diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java index fb7a850d75..eb67155579 100644 --- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java +++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java @@ -15,9 +15,13 @@ */ package com.android.quickstep.util; +import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.launcher3.anim.Interpolators.SCROLL; + import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Matrix.ScaleToFit; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; @@ -46,8 +50,10 @@ public class ClipAnimationHelper { private final RectF mSourceRect = new RectF(); // The bounds of the task view in launcher window coordinates private final RectF mTargetRect = new RectF(); - // Doesn't change after initialized, used as an anchor when changing mTargetRect - private final RectF mInitialTargetRect = new RectF(); + // Doesn't change after initialized, used as an anchor when changing mTargetOffset + private final PointF mInitialTargetOffset = new PointF(); + // Set when the final window destination is changed, such as offsetting for quick scrub + private final PointF mTargetOffset = new PointF(); // The insets to be used for clipping the app window, which can be larger than mSourceInsets // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In // app window coordinates. @@ -60,6 +66,9 @@ public class ClipAnimationHelper { private final Rect mClipRect = new Rect(); private final RectFEvaluator mRectFEvaluator = new RectFEvaluator(); private final Matrix mTmpMatrix = new Matrix(); + private final RectF mTmpRectF = new RectF(); + + private float mTargetScale = 1f; public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) { mHomeStackBounds.set(homeStackBounds); @@ -75,10 +84,9 @@ public class ClipAnimationHelper { mSourceStackBounds.width() - mSourceInsets.right, mSourceStackBounds.height() - mSourceInsets.bottom); mTargetRect.set(targetRect); - mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left, + mInitialTargetOffset.set(mHomeStackBounds.left - mSourceStackBounds.left, mHomeStackBounds.top - mSourceStackBounds.top); - - mInitialTargetRect.set(mTargetRect); + mTargetOffset.set(mInitialTargetOffset); // Calculate the clip based on the target rect (since the content insets and the // launcher insets may differ, so the aspect ratio of the target rect can differ @@ -98,10 +106,13 @@ public class ClipAnimationHelper { public void applyTransform(RemoteAnimationTargetSet targetSet, float progress) { RectF currentRect; - synchronized (mTargetRect) { - currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect); + mTmpRectF.set(mTargetRect); + Utilities.scaleRectFAboutCenter(mTmpRectF, mTargetScale); + 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(mTargetRect.centerX() - currentRect.centerX(), 0); + currentRect.offset(mTargetOffset.x * SCROLL.getInterpolation(progress), + mTargetOffset.y * LINEAR.getInterpolation(progress)); } mClipRect.left = (int) (mSourceWindowClipInsets.left * progress); @@ -131,10 +142,10 @@ public class ClipAnimationHelper { } public void offsetTarget(float scale, float offsetX, float offsetY) { - synchronized (mTargetRect) { - mTargetRect.set(mInitialTargetRect); - Utilities.scaleRectFAboutCenter(mTargetRect, scale); - mTargetRect.offset(offsetX, offsetY); + synchronized (mTargetOffset) { + mTargetScale = scale; + mTargetOffset.set(mInitialTargetOffset); + mTargetOffset.offset(offsetX, offsetY); } } @@ -187,13 +198,11 @@ public class ClipAnimationHelper { } public void drawForProgress(TaskThumbnailView ttv, Canvas canvas, float progress) { - RectF currentRect; - synchronized (mTargetRect) { - currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect); - } + RectF currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect); - canvas.translate(mSourceStackBounds.left - mHomeStackBounds.left, - mSourceStackBounds.top - mHomeStackBounds.top); + synchronized (mTargetOffset) { + canvas.translate(-mTargetOffset.x, -mTargetOffset.y); + } mTmpMatrix.setRectToRect(mTargetRect, currentRect, ScaleToFit.FILL); canvas.concat(mTmpMatrix); canvas.translate(mTargetRect.left, mTargetRect.top); diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 06e5311410..d69beb6a51 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -86,7 +86,11 @@ public class LauncherRecentsView extends RecentsView { public void setTranslationYFactor(float translationFactor) { mTranslationYFactor = translationFactor; - setTranslationY(mTranslationYFactor * (getPaddingBottom() - getPaddingTop())); + setTranslationY(computeTranslationYForFactor(mTranslationYFactor)); + } + + public float computeTranslationYForFactor(float translationYFactor) { + return translationYFactor * (getPaddingBottom() - getPaddingTop()); } @Override diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index b32d8dd45d..8c1076a972 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -219,11 +219,20 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback mSnapshotView.setDimAlpha(mCurveDimAlpha); } - mCurveScale = 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR; + mCurveScale = getCurveScaleForCurveInterpolation(curveInterpolation); setScaleX(mCurveScale); setScaleY(mCurveScale); } + public float getCurveScaleForInterpolation(float linearInterpolation) { + float curveInterpolation = CURVE_INTERPOLATOR.getInterpolation(linearInterpolation); + return getCurveScaleForCurveInterpolation(curveInterpolation); + } + + private float getCurveScaleForCurveInterpolation(float curveInterpolation) { + return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR; + } + public float getCurveScale() { return mCurveScale; }