Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03c38c5c authored by Tony Wickham's avatar Tony Wickham
Browse files

Rewrite long swipe resistance ("pullback") logic

- Rename "pullback" to "resistance" to reduce confusion.
- Remove mDragLengthFactorStartPullback & mDragLengthFactorMaxPullback
- Add AnimatorControllerWithResistance, which has 2 controllers, one
  for the normal shift to overview, then one to apply the resistance
  when swiping beyond that.
- Don't hack animator interpolators/progress; insteaad, allow progress
  to go > 1 (which will run the separate resistance animator).
- Don't start launcher controller separately from window controller;
  instead, both are controlled by mCurrentShift in updateFinalShift().
- The resistance animation logic is shared by both the active window
  and launcher (RecentsView).

Bug: 149934536
Change-Id: Ib0f9da18e10cc9ddf1a2f82ed767f237c89d3a41
parent 707727b6
Loading
Loading
Loading
Loading
+12 −46
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL;
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;
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
@@ -48,7 +47,6 @@ import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHO
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;

import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager;
@@ -75,7 +73,6 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
@@ -93,6 +90,7 @@ import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.InputConsumerProxy;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ShelfPeekAnim;
@@ -214,8 +212,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
    private ThumbnailData mTaskSnapshot;

    // Used to control launcher components throughout the swipe gesture.
    private AnimatorPlaybackController mLauncherTransitionController;
    private boolean mHasLauncherTransitionControllerStarted;
    private AnimatorControllerWithResistance mLauncherTransitionController;

    private AnimationFactory mAnimationFactory = (t) -> { };

@@ -564,11 +561,11 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends

    /**
     * We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
     * (it has its own animation) or if we're already animating the current controller.
     * (it has its own animation).
     * @return Whether we can create the launcher controller or update its progress.
     */
    private boolean canCreateNewOrUpdateExistingLauncherTransitionController() {
        return mGestureState.getEndTarget() != HOME && !mHasLauncherTransitionControllerStarted;
        return mGestureState.getEndTarget() != HOME;
    }

    @Override
@@ -578,10 +575,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
        return result;
    }

    private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
    private void onAnimatorPlaybackControllerCreated(AnimatorControllerWithResistance anim) {
        mLauncherTransitionController = anim;
        mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor);
        mLauncherTransitionController.dispatchOnStart();
        mLauncherTransitionController.getNormalController().dispatchOnStart();
        updateLauncherTransitionProgress();
    }

@@ -621,10 +617,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
                || !canCreateNewOrUpdateExistingLauncherTransitionController()) {
            return;
        }
        // Normalize the progress to 0 to 1, as the animation controller will clamp it to that
        // anyway. The controller mimics the drag length factor by applying it to its interpolators.
        float progress = mCurrentShift.value / mDragLengthFactor;
        mLauncherTransitionController.setPlayFraction(progress);
        mLauncherTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
    }

    /**
@@ -1112,31 +1105,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
            windowAnim.start();
            mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
        }
        // Always play the entire launcher animation when going home, since it is separate from
        // the animation that has been controlled thus far.
        if (mGestureState.getEndTarget() == HOME) {
            start = 0;
        }

        // We want to use the same interpolator as the window, but need to adjust it to
        // interpolate over the remaining progress (end - start).
        TimeInterpolator adjustedInterpolator = Interpolators.mapToProgress(
                interpolator, start, end);
        if (mLauncherTransitionController == null) {
            return;
        }
        if (start == end || duration <= 0) {
            mLauncherTransitionController.dispatchSetInterpolator(t -> end);
        } else {
            mLauncherTransitionController.dispatchSetInterpolator(adjustedInterpolator);
        }
        mLauncherTransitionController.getAnimationPlayer().setDuration(Math.max(0, duration));

        if (UNSTABLE_SPRINGS.get()) {
            mLauncherTransitionController.dispatchOnStart();
        }
        mLauncherTransitionController.getAnimationPlayer().start();
        mHasLauncherTransitionControllerStarted = true;
    }

    private void computeRecentsScrollIfInvisible() {
@@ -1261,10 +1229,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
    private void cancelCurrentAnimation() {
        mCanceled = true;
        mCurrentShift.cancelAnimation();
        if (mLauncherTransitionController != null && mLauncherTransitionController
                .getAnimationPlayer().isStarted()) {
            mLauncherTransitionController.getAnimationPlayer().cancel();
        }
    }

    private void invalidateHandler() {
@@ -1290,7 +1254,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
    private void endLauncherTransitionController() {
        setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
        if (mLauncherTransitionController != null) {
            mLauncherTransitionController.getAnimationPlayer().end();
            // End the animation, but stay at the same visual progress.
            mLauncherTransitionController.getNormalController().dispatchSetInterpolator(
                    t -> Utilities.boundToRange(mCurrentShift.value, 0, 1));
            mLauncherTransitionController.getNormalController().getAnimationPlayer().end();
            mLauncherTransitionController = null;
        }
    }
@@ -1572,8 +1539,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
     */
    protected void applyWindowTransform() {
        if (mWindowTransitionController != null) {
            float progress = mCurrentShift.value / mDragLengthFactor;
            mWindowTransitionController.setPlayFraction(progress);
            mWindowTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
        }
        if (mRecentsAnimationTargets != null) {
            if (mRecentsViewScrollLinked) {
+2 −2
Original line number Diff line number Diff line
@@ -79,8 +79,8 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
        BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI(
                mDeviceState,
                wasVisible, (controller) -> {
                    controller.dispatchOnStart();
                    controller.getAnimationPlayer().end();
                    controller.getNormalController().dispatchOnStart();
                    controller.getNormalController().getAnimationPlayer().end();
                });
        factory.createActivityInterface(RECENTS_LAUNCH_DURATION);
        factory.setRecentsAttachedToAppWindow(true, false);
+2 −2
Original line number Diff line number Diff line
@@ -27,11 +27,11 @@ import androidx.annotation.Nullable;

import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;

@@ -84,7 +84,7 @@ public final class FallbackActivityInterface extends
    /** 6 */
    @Override
    public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
            boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
            boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback) {
        DefaultAnimationFactory factory = new DefaultAnimationFactory(callback);
        factory.initUI();
        return factory;
+2 −2
Original line number Diff line number Diff line
@@ -39,7 +39,6 @@ import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
@@ -49,6 +48,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
import com.android.quickstep.views.RecentsView;
@@ -118,7 +118,7 @@ public final class LauncherActivityInterface extends

    @Override
    public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
            boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
            boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback) {
        notifyRecentsOfOrientation(deviceState.getRotationTouchHelper());
        DefaultAnimationFactory factory = new DefaultAnimationFactory(callback) {
            @Override
+10 −25
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@
package com.android.quickstep;

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.LINEAR;

import android.animation.Animator;
import android.content.Context;
@@ -24,7 +24,6 @@ import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.animation.Interpolator;

import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
@@ -35,6 +34,7 @@ import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
@@ -45,7 +45,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.
public abstract class SwipeUpAnimationLogic {

    protected static final Rect TEMP_RECT = new Rect();
    private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;

    protected DeviceProfile mDp;

@@ -66,12 +65,8 @@ public abstract class SwipeUpAnimationLogic {
    protected int mTransitionDragLength;
    // How much further we can drag past recents, as a factor of mTransitionDragLength.
    protected float mDragLengthFactor = 1;
    // Start resisting when swiping past this factor of mTransitionDragLength.
    private float mDragLengthFactorStartPullback = 1f;
    // This is how far down we can scale down, where 0f is full screen and 1f is recents.
    private float mDragLengthFactorMaxPullback = 1f;

    protected AnimatorPlaybackController mWindowTransitionController;
    protected AnimatorControllerWithResistance mWindowTransitionController;

    public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState,
            GestureState gestureState, TransformParams transformParams) {
@@ -97,19 +92,16 @@ public abstract class SwipeUpAnimationLogic {
        if (mDeviceState.isFullyGesturalNavMode()) {
            // We can drag all the way to the top of the screen.
            mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;

            float startScale = mTaskViewSimulator.getFullScreenScale();
            // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
            mDragLengthFactorStartPullback = (0.75f - startScale) / (1 - startScale);
            mDragLengthFactorMaxPullback = (0.5f - startScale) / (1 - startScale);
        } else {
            mDragLengthFactor = 1;
            mDragLengthFactorStartPullback = mDragLengthFactorMaxPullback = 1;
            mDragLengthFactor = 1 + AnimatorControllerWithResistance.TWO_BUTTON_EXTRA_DRAG_FACTOR;
        }

        PendingAnimation pa = new PendingAnimation(mTransitionDragLength * 2);
        mTaskViewSimulator.addAppToOverviewAnim(pa, t -> t * mDragLengthFactor);
        mWindowTransitionController = pa.createPlaybackController();
        mTaskViewSimulator.addAppToOverviewAnim(pa, LINEAR);
        AnimatorPlaybackController normalController = pa.createPlaybackController();
        mWindowTransitionController = AnimatorControllerWithResistance.createForRecents(
                normalController, mContext, mTaskViewSimulator.getOrientationState(),
                mDp, mTaskViewSimulator.recentsViewScale, AnimatedFloat.VALUE);
    }

    @UiThread
@@ -122,13 +114,6 @@ public abstract class SwipeUpAnimationLogic {
        } else {
            float translation = Math.max(displacement, 0);
            shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
            if (shift > mDragLengthFactorStartPullback) {
                float pullbackProgress = Utilities.getProgress(shift,
                        mDragLengthFactorStartPullback, mDragLengthFactor);
                pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
                shift = mDragLengthFactorStartPullback + pullbackProgress
                        * (mDragLengthFactorMaxPullback - mDragLengthFactorStartPullback);
            }
        }

        mCurrentShift.updateValue(shift);
@@ -183,7 +168,7 @@ public abstract class SwipeUpAnimationLogic {
            HomeAnimationFactory homeAnimationFactory) {
        final RectF targetRect = homeAnimationFactory.getWindowTargetRect();

        mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor);
        mCurrentShift.updateValue(startProgress);
        mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress));
        RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect());

Loading