diff options
author | Tony Wickham <twickham@google.com> | 2019-06-03 10:21:20 -0700 |
---|---|---|
committer | Tony Wickham <twickham@google.com> | 2019-06-10 15:15:40 -0700 |
commit | fa37c529e1f3587a4fe8362a0c66daa639d372a3 (patch) | |
tree | 9e7b4e8cad273d355c723cdb44ed7a29fb777bd0 /quickstep/recents_ui_overrides | |
parent | c11ea4e965daf3858a222f801fdae907fdc25087 (diff) | |
download | android_packages_apps_Trebuchet-fa37c529e1f3587a4fe8362a0c66daa639d372a3.tar.gz android_packages_apps_Trebuchet-fa37c529e1f3587a4fe8362a0c66daa639d372a3.tar.bz2 android_packages_apps_Trebuchet-fa37c529e1f3587a4fe8362a0c66daa639d372a3.zip |
Translate recents when attaching to app window instead of fading
When attaching recents, translate it offscreen and use a spring to pull it
into position. When detaching, use the same spring to pull it back offscreen.
Bug: 129985827
Change-Id: I05339e2ec0932070365023bfafc83cbf2a4e178e
Diffstat (limited to 'quickstep/recents_ui_overrides')
3 files changed, 105 insertions, 33 deletions
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index 1b82bcb57..7809e454a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -16,16 +16,23 @@ package com.android.quickstep; import static android.view.View.TRANSLATION_Y; + import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; +import static com.android.launcher3.LauncherStateManager.ANIM_ALL; import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_DAMPING_RATIO; import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_STIFFNESS; +import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; +import static com.android.launcher3.anim.Interpolators.INSTANT; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.quickstep.WindowTransformSwipeHandler.RECENTS_ATTACH_DURATION; +import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY; +import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -44,14 +51,18 @@ import android.view.animation.Interpolator; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherInitListenerEx; import com.android.launcher3.LauncherState; +import com.android.launcher3.LauncherStateManager; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.SpringObjectAnimator; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.testing.TestProtocol; @@ -100,6 +111,13 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe } @Override + public void onSwipeUpToHomeComplete(Launcher activity) { + // Ensure recents is at the correct position for NORMAL state. For example, when we detach + // recents, we assume the first task is invisible, making translation off by one task. + activity.getStateManager().reapplyState(); + } + + @Override public void onAssistantVisibilityChanged(float visibility) { Launcher launcher = getCreatedActivity(); if (launcher != null) { @@ -156,18 +174,23 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe public AnimatorPlaybackController createActivityAnimationToHome() { // Return an empty APC here since we have an non-user controlled animation to home. long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx); - AnimatorSet as = new AnimatorSet(); - as.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - activity.getStateManager().goToState(NORMAL, false); - } - }); - return AnimatorPlaybackController.wrap(as, accuracy); + return activity.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy, + 0 /* animComponents */); } @Override public void playAtomicAnimation(float velocity) { + // Setup workspace with 0 duration to prepare for our staggered animation. + LauncherStateManager stateManager = activity.getStateManager(); + AnimatorSetBuilder builder = new AnimatorSetBuilder(); + // setRecentsAttachedToAppWindow() will animate recents out. + builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW); + stateManager.createAtomicAnimation(BACKGROUND_APP, NORMAL, builder, ANIM_ALL, 0); + builder.build().start(); + + // Stop scrolling so that it doesn't interfere with the translation offscreen. + recentsView.getScroller().forceFinished(true); + new StaggeredWorkspaceAnim(activity, workspaceView, velocity).start(); } }; @@ -201,7 +224,8 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe return new AnimationFactory() { private Animator mShelfAnim; private ShelfAnimState mShelfState; - private Animator mAttachToWindowAnim; + private Animator mAttachToWindowFadeAnim; + private SpringAnimation mAttachToWindowTranslationXAnim; private boolean mIsAttachedToWindow; @Override @@ -267,20 +291,60 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe return; } mIsAttachedToWindow = attached; - if (mAttachToWindowAnim != null) { - mAttachToWindowAnim.cancel(); + if (mAttachToWindowFadeAnim != null) { + mAttachToWindowFadeAnim.cancel(); } - mAttachToWindowAnim = ObjectAnimator.ofFloat(activity.getOverviewPanel(), + RecentsView recentsView = activity.getOverviewPanel(); + mAttachToWindowFadeAnim = ObjectAnimator.ofFloat(recentsView, RecentsView.CONTENT_ALPHA, attached ? 1 : 0); - mAttachToWindowAnim.addListener(new AnimatorListenerAdapter() { + + int runningTaskIndex = recentsView.getRunningTaskIndex(); + if (runningTaskIndex == 0) { + // If we are on the first task (we haven't quick switched), translate recents in + // from the side. Calculate the start translation based on current scale/scroll. + float currScale = recentsView.getScaleX(); + float scrollOffsetX = recentsView.getScrollOffset(); + + float offscreenX = NORMAL.getOverviewScaleAndTranslation(activity).translationX; + // The first task is hidden, so offset by its width. + int firstTaskWidth = recentsView.getTaskViewAt(0).getWidth(); + offscreenX -= (firstTaskWidth + recentsView.getPageSpacing()) * currScale; + // Offset since scale pushes tasks outwards. + offscreenX += firstTaskWidth * (currScale - 1) / 2; + offscreenX = Math.max(0, offscreenX); + if (recentsView.isRtl()) { + offscreenX = -offscreenX; + } + + float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0; + float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX; + if (mAttachToWindowTranslationXAnim == null) { + mAttachToWindowTranslationXAnim = new SpringAnimation(recentsView, + SpringAnimation.TRANSLATION_X).setSpring(new SpringForce() + .setDampingRatio(DAMPING_RATIO_LOW_BOUNCY) + .setStiffness(STIFFNESS_LOW)); + } + if (!recentsView.isShown() && animate) { + recentsView.setTranslationX(fromTranslationX); + mAttachToWindowTranslationXAnim.setStartValue(fromTranslationX); + } + mAttachToWindowTranslationXAnim.animateToFinalPosition(toTranslationX); + if (!animate && mAttachToWindowTranslationXAnim.canSkipToEnd()) { + mAttachToWindowTranslationXAnim.skipToEnd(); + } + + mAttachToWindowFadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2); + } else { + mAttachToWindowFadeAnim.setInterpolator(ACCEL_DEACCEL); + } + mAttachToWindowFadeAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mAttachToWindowAnim = null; + mAttachToWindowFadeAnim = null; } }); - mAttachToWindowAnim.setInterpolator(ACCEL_DEACCEL); - mAttachToWindowAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0); - mAttachToWindowAnim.start(); + mAttachToWindowFadeAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0); + mAttachToWindowFadeAnim.start(); } }; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index c7841d98e..7d17f85f6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -21,7 +21,6 @@ import static com.android.launcher3.Utilities.SINGLE_FRAME_MS; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.anim.Interpolators.ACCEL_1_5; import static com.android.launcher3.anim.Interpolators.DEACCEL; -import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; @@ -218,7 +217,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> Math.min(1 / MIN_PROGRESS_FOR_OVERVIEW, 1 / (1 - MIN_PROGRESS_FOR_OVERVIEW)); private static final String SCREENSHOT_CAPTURED_EVT = "ScreenshotCaptured"; - private static final long SHELF_ANIM_DURATION = 120; + private static final long SHELF_ANIM_DURATION = 240; public static final long RECENTS_ATTACH_DURATION = 300; // Start resisting when swiping past this factor of mTransitionDragLength. @@ -602,7 +601,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> } public void onMotionPauseChanged(boolean isPaused) { - setShelfState(isPaused ? PEEK : HIDE, FAST_OUT_SLOW_IN, SHELF_ANIM_DURATION); + setShelfState(isPaused ? PEEK : HIDE, OVERSHOOT_1_2, SHELF_ANIM_DURATION); } public void maybeUpdateRecentsAttachedState() { @@ -625,7 +624,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> : mRecentsAnimationWrapper.targetSet.findTask(mRunningTaskId); final boolean recentsAttachedToAppWindow; int runningTaskIndex = mRecentsView.getRunningTaskIndex(); - if (mContinuingLastGesture) { + if (mGestureEndTarget != null) { + recentsAttachedToAppWindow = mGestureEndTarget.recentsAttachedToAppWindow; + } else if (mContinuingLastGesture + && mRecentsView.getRunningTaskIndex() != mRecentsView.getNextPage()) { recentsAttachedToAppWindow = true; animate = false; } else if (runningTaskTarget != null && isNotInRecents(runningTaskTarget)) { @@ -633,17 +635,16 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> recentsAttachedToAppWindow = true; animate = false; } else { - if (mGestureEndTarget != null) { - recentsAttachedToAppWindow = mGestureEndTarget.recentsAttachedToAppWindow; - } else { - recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask; - } + recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask; if (animate) { // Only animate if an adjacent task view is visible on screen. TaskView adjacentTask1 = mRecentsView.getTaskViewAt(runningTaskIndex + 1); TaskView adjacentTask2 = mRecentsView.getTaskViewAt(runningTaskIndex - 1); + float prevTranslationX = mRecentsView.getTranslationX(); + mRecentsView.setTranslationX(0); animate = (adjacentTask1 != null && adjacentTask1.getGlobalVisibleRect(TEMP_RECT)) || (adjacentTask2 != null && adjacentTask2.getGlobalVisibleRect(TEMP_RECT)); + mRecentsView.setTranslationX(prevTranslationX); } } mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate); @@ -701,13 +702,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController(); if (controller != null) { - float offsetX = 0; - if (mRecentsView != null) { - int startScroll = mRecentsView.getScrollForPage(mRecentsView.indexOfChild( - mRecentsView.getRunningTaskView())); - offsetX = startScroll - mRecentsView.getScrollX(); - offsetX *= mRecentsView.getScaleX(); - } + float offsetX = mRecentsView == null ? 0 : mRecentsView.getScrollOffset(); float offsetScale = getTaskCurveScaleForOffsetX(offsetX, mClipAnimationHelper.getTargetRect().width()); mTransformParams.setProgress(shift).setOffsetX(offsetX).setOffsetScale(offsetScale); @@ -1217,6 +1212,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> if (mRecentsView != null) { mRecentsView.post(mRecentsView::resetTaskVisuals); } + // Make sure recents is in its final state + maybeUpdateRecentsAttachedState(false); + mActivityControlHelper.onSwipeUpToHomeComplete(mActivity); } }); return anim; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index e38a315f8..90e123e84 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -1676,6 +1676,16 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl return mClearAllButton; } + /** + * @return How many pixels the running task is offset on the x-axis due to the current scrollX. + */ + public float getScrollOffset() { + int startScroll = getScrollForPage(getRunningTaskIndex()); + int offsetX = startScroll - getScrollX(); + offsetX *= getScaleX(); + return offsetX; + } + public Consumer<MotionEvent> getEventDispatcher(RotationMode rotationMode) { if (rotationMode.isTransposed) { Matrix transform = new Matrix(); |