From 78595cd7dea011bcfc9b40791a5f85bdaa122c23 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 16 Apr 2018 14:08:57 -0700 Subject: [PATCH] Compute window offset when quick scrub starts Instead of setting the window center to match the task center on every update, compute the final offset when quick scrub starts and interpolate alongside other factors such as window scale. Bug: 78027888 Change-Id: I33b115764d46ecd6907ecb82b1ba12aeefc583c5 --- .../quickstep/ActivityControlHelper.java | 15 +++++++ .../WindowTransformSwipeHandler.java | 33 +++++++++----- .../quickstep/util/ClipAnimationHelper.java | 45 +++++++++++-------- .../quickstep/views/LauncherRecentsView.java | 6 ++- .../com/android/quickstep/views/TaskView.java | 11 ++++- 5 files changed, 78 insertions(+), 32 deletions(-) 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; }