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

Commit 18759647 authored by Tony Wickham's avatar Tony Wickham
Browse files

Swipe up to go home, swipe and hold to go to overview

- Pause (swipe and hold) detection based on velocity and acceleration,
  so it feels immediately responsive
- Don't show shelf during swipe; peek when swipe pauses
- Disallow long swipe
- If swiping to go home (we didn't detect a pause), animate window and
  launcher together (not final animation, but mechanism is in place)
- Guarded by SWIPE_HOME flag

Bug: 111926330
Change-Id: Ie4af04517c6688e3d649c2971a1aad197837cb3b
parent 7eebfc56
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -30,9 +30,16 @@
             loading full resolution screenshots. -->
    <dimen name="recents_fast_fling_velocity">600dp</dimen>

    <!-- These velocities are in dp / s -->
    <dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
    <dimen name="quickstep_fling_min_velocity">250dp</dimen>

    <!-- These speeds are in dp / ms -->
    <dimen name="motion_pause_detector_speed_very_slow">0.0285dp</dimen>
    <dimen name="motion_pause_detector_speed_somewhat_fast">0.285dp</dimen>
    <dimen name="motion_pause_detector_speed_fast">0.5dp</dimen>
    <dimen name="motion_pause_detector_min_displacement">48dp</dimen>

    <!-- Launcher app transition -->
    <dimen name="content_trans_y">50dp</dimen>
    <dimen name="workspace_trans_y">50dp</dimen>
+137 −9
Original line number Diff line number Diff line
@@ -16,10 +16,12 @@
package com.android.quickstep;

import static android.view.View.TRANSLATION_Y;

import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS_SPRING;
import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -31,6 +33,7 @@ import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ROTATION;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
@@ -44,6 +47,9 @@ import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.view.animation.Interpolator;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;

@@ -56,6 +62,7 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.TestProtocol;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.SpringObjectAnimator;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -105,6 +112,8 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {

    void onSwipeUpComplete(T activity);

    @NonNull HomeAnimationFactory prepareHomeUI(T activity);

    AnimationFactory prepareRecentsUI(T activity, boolean activityVisible,
            boolean animateActivity, Consumer<AnimatorPlaybackController> callback);

@@ -234,6 +243,32 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
            DiscoveryBounce.showForOverviewIfNeeded(activity);
        }

        @NonNull
        @Override
        public HomeAnimationFactory prepareHomeUI(Launcher activity) {
            DeviceProfile dp = activity.getDeviceProfile();

            return new HomeAnimationFactory() {
                @NonNull
                @Override
                public RectF getWindowTargetRect() {
                    int halfIconSize = dp.iconSizePx / 2;
                    float targetCenterX = dp.availableWidthPx / 2;
                    float targetCenterY = dp.availableHeightPx - dp.hotseatBarSizePx;
                    return new RectF(targetCenterX - halfIconSize, targetCenterY - halfIconSize,
                            targetCenterX + halfIconSize, targetCenterY + halfIconSize);
                }

                @NonNull
                @Override
                public Animator createActivityAnimationToHome() {
                    long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
                    return activity.getStateManager().createAnimationToNewWorkspace(
                            NORMAL, accuracy).getTarget();
                }
            };
        }

        @Override
        public AnimationFactory prepareRecentsUI(Launcher activity, boolean activityVisible,
                boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
@@ -263,6 +298,9 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
            }

            return new AnimationFactory() {
                private Animator mShelfAnim;
                private ShelfAnimState mShelfState;

                @Override
                public void createActivityController(long transitionLength,
                        @InteractionType int interactionType) {
@@ -274,6 +312,40 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
                public void onTransitionCancelled() {
                    activity.getStateManager().goToState(startState, false /* animate */);
                }

                @Override
                public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator,
                        long duration) {
                    if (mShelfState == shelfState) {
                        return;
                    }
                    mShelfState = shelfState;
                    if (mShelfAnim != null) {
                        mShelfAnim.cancel();
                    }
                    if (mShelfState == ShelfAnimState.CANCEL) {
                        return;
                    }
                    float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(activity);
                    float shelfOverviewProgress = OVERVIEW.getVerticalProgress(activity);
                    float shelfPeekingProgress = shelfHiddenProgress
                            - (shelfHiddenProgress - shelfOverviewProgress) * 0.25f;
                    float toProgress = mShelfState == ShelfAnimState.HIDE
                            ? shelfHiddenProgress
                            : mShelfState == ShelfAnimState.PEEK
                                    ? shelfPeekingProgress
                                    : shelfOverviewProgress;
                    mShelfAnim = createShelfAnim(activity, toProgress);
                    mShelfAnim.addListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            mShelfAnim = null;
                        }
                    });
                    mShelfAnim.setInterpolator(interpolator);
                    mShelfAnim.setDuration(duration);
                    mShelfAnim.start();
                }
            };
        }

@@ -295,13 +367,12 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
            }

            AnimatorSet anim = new AnimatorSet();
            if (!activity.getDeviceProfile().isVerticalBarLayout()) {
                Animator shiftAnim = new SpringObjectAnimator<>(activity.getAllAppsController(),
                        ALL_APPS_PROGRESS_SPRING, "allAppsSpringFromACH",
                        activity.getAllAppsController().getShiftRange(),
            if (!activity.getDeviceProfile().isVerticalBarLayout()
                    && !FeatureFlags.SWIPE_HOME.get()) {
                // Don't animate the shelf when SWIPE_HOME is true, because we update it atomically.
                Animator shiftAnim = createShelfAnim(activity,
                        fromState.getVerticalProgress(activity),
                        endState.getVerticalProgress(activity));
                shiftAnim.setInterpolator(LINEAR);
                anim.play(shiftAnim);
            }

@@ -322,6 +393,14 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
            callback.accept(controller);
        }

        private Animator createShelfAnim(Launcher activity, float ... progressValues) {
            Animator shiftAnim = new SpringObjectAnimator(activity.getAllAppsController(),
                    ALL_APPS_PROGRESS_SPRING, "allAppsSpringFromACH",
                    activity.getAllAppsController().getShiftRange(), progressValues);
            shiftAnim.setInterpolator(LINEAR);
            return shiftAnim;
        }

        /**
         * Scale down recents from the center task being full screen to being in overview.
         */
@@ -512,6 +591,35 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
            // TODO:
        }

        @NonNull
        @Override
        public HomeAnimationFactory prepareHomeUI(RecentsActivity activity) {
            RecentsView recentsView = activity.getOverviewPanel();

            return new HomeAnimationFactory() {
                @NonNull
                @Override
                public RectF getWindowTargetRect() {
                    float centerX = recentsView.getPivotX();
                    float centerY = recentsView.getPivotY();
                    return new RectF(centerX, centerY, centerX, centerY);
                }

                @NonNull
                @Override
                public Animator createActivityAnimationToHome() {
                    Animator anim = ObjectAnimator.ofFloat(recentsView, CONTENT_ALPHA, 0);
                    anim.addListener(new AnimationSuccessListener() {
                        @Override
                        public void onAnimationSuccess(Animator animator) {
                            recentsView.startHome();
                        }
                    });
                    return anim;
                }
            };
        }

        @Override
        public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible,
                boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
@@ -524,12 +632,12 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {

            return new AnimationFactory() {

                boolean isAnimatingHome = false;
                boolean isAnimatingToRecents = false;

                @Override
                public void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) {
                    isAnimatingHome = targets != null && targets.isAnimatingHome();
                    if (!isAnimatingHome) {
                    isAnimatingToRecents = targets != null && targets.isAnimatingHome();
                    if (!isAnimatingToRecents) {
                        rv.setContentAlpha(1);
                    }
                    createActivityController(getSwipeUpDestinationAndLength(
@@ -539,7 +647,7 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {

                @Override
                public void createActivityController(long transitionLength, int interactionType) {
                    if (!isAnimatingHome) {
                    if (!isAnimatingToRecents) {
                        return;
                    }

@@ -667,10 +775,30 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {

    interface AnimationFactory {

        enum ShelfAnimState {
            HIDE(true), PEEK(true), OVERVIEW(false), CANCEL(false);

            ShelfAnimState(boolean shouldPreformHaptic) {
                this.shouldPreformHaptic = shouldPreformHaptic;
            }

            public final boolean shouldPreformHaptic;
        }

        default void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { }

        void createActivityController(long transitionLength, @InteractionType int interactionType);

        default void onTransitionCancelled() { }

        default void setShelfState(ShelfAnimState animState, Interpolator interpolator,
                long duration) { }
    }

    interface HomeAnimationFactory {

        @NonNull RectF getWindowTargetRect();

        @NonNull Animator createActivityAnimationToHome();
    }
}
+12 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;

import static com.android.launcher3.util.RaceConditionTracker.ENTER;
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -47,8 +48,10 @@ import android.view.ViewConfiguration;
import android.view.WindowManager;

import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.RaceConditionTracker;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.AssistDataReceiver;
@@ -99,6 +102,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
    private Rect mStableInsets = new Rect();

    private VelocityTracker mVelocityTracker;
    private MotionPauseDetector mMotionPauseDetector;
    private MotionEventQueue mEventQueue;
    private boolean mIsGoingToLauncher;

@@ -114,6 +118,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
        mRecentsModel = recentsModel;
        mHomeIntent = homeIntent;
        mVelocityTracker = velocityTracker;
        mMotionPauseDetector = new MotionPauseDetector(base);
        mActivityControlHelper = activityControl;
        mMainThreadExecutor = mainThreadExecutor;
        mBackgroundThreadChoreographer = backgroundThreadChoreographer;
@@ -192,6 +197,10 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
                if (mPassedInitialSlop && mInteractionHandler != null) {
                    // Move
                    dispatchMotion(ev, displacement - mStartDisplacement);

                    if (FeatureFlags.SWIPE_HOME.get()) {
                        mMotionPauseDetector.addPosition(displacement);
                    }
                }
                break;
            }
@@ -250,6 +259,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
        mRecentsModel.getTasks(null);
        mInteractionHandler = handler;
        handler.setGestureEndCallback(mEventQueue::reset);
        mMotionPauseDetector.setOnMotionPauseListener(handler::onMotionPauseChanged);

        CountDownLatch drawWaitLock = new CountDownLatch(1);
        handler.setLauncherOnDrawCallback(() -> {
@@ -336,7 +346,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
        if (mInteractionHandler != null) {
            final WindowTransformSwipeHandler handler = mInteractionHandler;
            mInteractionHandler = null;
            mIsGoingToLauncher = handler.mIsGoingToRecents;
            mIsGoingToLauncher = handler.mIsGoingToRecents || handler.mIsGoingToHome;
            mMainThreadExecutor.execute(handler::reset);
        }
    }
@@ -414,6 +424,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
           mVelocityTracker.addMovement(ev);
           if (ev.getActionMasked() == ACTION_POINTER_UP) {
               mVelocityTracker.clear();
               mMotionPauseDetector.clear();
           }
        }
    }
+2 −2
Original line number Diff line number Diff line
@@ -20,12 +20,12 @@ import android.os.Build;
import android.view.Choreographer;
import android.view.MotionEvent;

import androidx.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.function.Consumer;

import androidx.annotation.IntDef;

@TargetApi(Build.VERSION_CODES.O)
@FunctionalInterface
public interface TouchConsumer extends Consumer<MotionEvent> {
+244 −73

File changed.

Preview size limit exceeded, changes collapsed.

Loading