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

Commit 50876bfa authored by Tony's avatar Tony
Browse files

FeatureFlag: quick scrub is now quick switch

- Scale down current task and translate it to the left
- Translate previous task in from the left
- This is a toggle; quick switch again returns to the first task

Currently this is implemented by repurposing onQuickScrub(progress) to update the positions
of the first two pages. This makes tracking velocity a bit difficult; if we want to go down
this path in the long run we should probably track velocity properly on MotionEvents.

Change-Id: I4445b5f08b6e88e71cbb5e30b1f1d45c5f1edc68
parent f107c9ef
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -14,3 +14,4 @@ local.properties
gradle/
build/
gradlew*
.DS_Store
+8 −2
Original line number Diff line number Diff line
@@ -178,6 +178,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
    @Override
    public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
        if (hasControlRemoteAppTransitionPermission()) {
            boolean fromRecents = mLauncher.getStateManager().getState().overviewUi
                    && findTaskViewToLaunch(launcher, v, null) != null;
            RecentsView recentsView = mLauncher.getOverviewPanel();
            if (fromRecents && recentsView.getQuickScrubController().isQuickSwitch()) {
                return ActivityOptions.makeCustomAnimation(mLauncher, R.anim.no_anim,
                        R.anim.no_anim);
            }

            RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler,
                    true /* startAtFrontOfQueue */) {

@@ -218,8 +226,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
                }
            };

            boolean fromRecents = mLauncher.getStateManager().getState().overviewUi
                    && findTaskViewToLaunch(launcher, v, null) != null;
            int duration = fromRecents
                    ? RECENTS_LAUNCH_DURATION
                    : APP_LAUNCH_DURATION;
+14 −4
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ public class FastOverviewState extends OverviewState {
     * Vertical transition of the task previews relative to the full container.
     */
    public static final float OVERVIEW_TRANSLATION_FACTOR = 0.4f;
    public static final float OVERVIEW_CENTERED_TRANSLATION_FACTOR = 0.5f;

    private static final int STATE_FLAGS = FLAG_DISABLE_RESTORE | FLAG_DISABLE_INTERACTION
            | FLAG_OVERVIEW_UI | FLAG_HIDE_BACK_BUTTON | FLAG_DISABLE_ACCESSIBILITY;
@@ -60,12 +61,17 @@ public class FastOverviewState extends OverviewState {
        RecentsView recentsView = launcher.getOverviewPanel();
        recentsView.getTaskSize(sTempRect);

        return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher),
                OVERVIEW_TRANSLATION_FACTOR};
        boolean isQuickSwitch = recentsView.getQuickScrubController().isQuickSwitch();
        float translationYFactor = isQuickSwitch
                ? OVERVIEW_CENTERED_TRANSLATION_FACTOR
                : OVERVIEW_TRANSLATION_FACTOR;
        return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher,
                isQuickSwitch), translationYFactor};
    }

    public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context) {
        if (dp.isVerticalBarLayout()) {
    public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context,
            boolean isQuickSwitch) {
        if (dp.isVerticalBarLayout() && !isQuickSwitch) {
            return 1f;
        }

@@ -73,6 +79,10 @@ public class FastOverviewState extends OverviewState {
        float usedHeight = taskRect.height() + res.getDimension(R.dimen.task_thumbnail_top_margin);
        float usedWidth = taskRect.width() + 2 * (res.getDimension(R.dimen.recents_page_spacing)
                + res.getDimension(R.dimen.quickscrub_adjacent_visible_width));
        if (isQuickSwitch) {
            usedWidth = taskRect.width();
            return Math.max(dp.availableHeightPx / usedHeight, dp.availableWidthPx / usedWidth);
        }
        return Math.min(Math.min(dp.availableHeightPx / usedHeight,
                dp.availableWidthPx / usedWidth), MAX_PREVIEW_SCALE_UP);
    }
+3 −2
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
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;
@@ -58,6 +57,7 @@ import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.uioverrides.FastOverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -192,7 +192,8 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
                @InteractionType int interactionType, TransformedRect outRect) {
            LayoutUtils.calculateLauncherTaskSize(context, dp, outRect.rect);
            if (interactionType == INTERACTION_QUICK_SCRUB) {
                outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context);
                outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context,
                        FeatureFlags.QUICK_SWITCH.get());
            }
            if (dp.isVerticalBarLayout()) {
                Rect targetInsets = dp.getInsets();
+134 −8
Original line number Diff line number Diff line
@@ -16,8 +16,18 @@

package com.android.quickstep;

import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.os.Build;
import android.util.FloatProperty;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.animation.Interpolator;
@@ -37,8 +47,10 @@ import com.android.quickstep.views.TaskView;
 * The behavior is to evenly divide the progress into sections, each of which scrolls one page.
 * The first and last section set an alarm to auto-advance backwards or forwards, respectively.
 */
@TargetApi(Build.VERSION_CODES.P)
public class QuickScrubController implements OnAlarmListener {

    public static final int QUICK_SWITCH_FROM_APP_START_DURATION = 0;
    public static final int QUICK_SCRUB_FROM_APP_START_DURATION = 240;
    public static final int QUICK_SCRUB_FROM_HOME_START_DURATION = 200;
    // We want the translation y to finish faster than the rest of the animation.
@@ -52,6 +64,19 @@ public class QuickScrubController implements OnAlarmListener {
            0.05f, 0.20f, 0.35f, 0.50f, 0.65f, 0.80f, 0.95f
    };

    private static final FloatProperty<QuickScrubController> PROGRESS
            = new FloatProperty<QuickScrubController>("progress") {
        @Override
        public void setValue(QuickScrubController quickScrubController, float progress) {
            quickScrubController.onQuickScrubProgress(progress);
        }

        @Override
        public Float get(QuickScrubController quickScrubController) {
            return quickScrubController.mEndProgress;
        }
    };

    private static final String TAG = "QuickScrubController";
    private static final boolean ENABLE_AUTO_ADVANCE = true;
    private static final long AUTO_ADVANCE_DELAY = 500;
@@ -72,6 +97,13 @@ public class QuickScrubController implements OnAlarmListener {
    private ActivityControlHelper mActivityControlHelper;
    private TouchInteractionLog mTouchInteractionLog;

    private boolean mIsQuickSwitch;
    private float mStartProgress;
    private float mEndProgress;
    private float mPrevProgressDelta;
    private float mPrevPrevProgressDelta;
    private boolean mShouldSwitchToNext;

    public QuickScrubController(BaseActivity activity, RecentsView recentsView) {
        mActivity = activity;
        mRecentsView = recentsView;
@@ -91,17 +123,26 @@ public class QuickScrubController implements OnAlarmListener {
        mActivityControlHelper = controlHelper;
        mTouchInteractionLog = touchInteractionLog;

        if (mIsQuickSwitch) {
            mShouldSwitchToNext = true;
            mPrevProgressDelta = 0;
            if (mRecentsView.getTaskViewCount() > 0) {
                mRecentsView.getTaskViewAt(0).setFullscreen(true);
            }
            if (mRecentsView.getTaskViewCount() > 1) {
                mRecentsView.getTaskViewAt(1).setFullscreen(true);
            }
        }

        snapToNextTaskIfAvailable();
        mActivity.getUserEventDispatcher().resetActionDurationMillis();
    }

    public void onQuickScrubEnd() {
        mInQuickScrub = false;
        if (ENABLE_AUTO_ADVANCE) {
            mAutoAdvanceAlarm.cancelAlarm();
        }
        int page = mRecentsView.getNextPage();

        Runnable launchTaskRunnable = () -> {
            int page = mRecentsView.getPageNearestToCenterOfScreen();
            TaskView taskView = mRecentsView.getTaskViewAt(page);
            if (taskView != null) {
                mWaitingForTaskLaunch = true;
@@ -118,12 +159,49 @@ public class QuickScrubController implements OnAlarmListener {
                                TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key));
                    }
                    mWaitingForTaskLaunch = false;
                    if (mIsQuickSwitch) {
                        mIsQuickSwitch = false;
                        if (mRecentsView.getTaskViewCount() > 0) {
                            mRecentsView.getTaskViewAt(0).setFullscreen(false);
                        }
                        if (mRecentsView.getTaskViewCount() > 1) {
                            mRecentsView.getTaskViewAt(1).setFullscreen(false);
                        }
                    }

                }, taskView.getHandler());
            } else {
                breakOutOfQuickScrub();
            }
            mActivityControlHelper = null;
        };

        if (mIsQuickSwitch) {
            float progressVelocity = mPrevPrevProgressDelta / SINGLE_FRAME_MS;
            // Move to the next frame immediately, then start the animation from the
            // following frame since it starts a frame later.
            float singleFrameProgress = progressVelocity * SINGLE_FRAME_MS;
            float fromProgress = mEndProgress + singleFrameProgress;
            onQuickScrubProgress(fromProgress);
            fromProgress += singleFrameProgress;
            float toProgress = mShouldSwitchToNext ? 1 : 0;
            int duration = (int) Math.abs((toProgress - fromProgress) / progressVelocity);
            duration = Utilities.boundToRange(duration, 80, 300);
            Animator anim = ObjectAnimator.ofFloat(this, PROGRESS, fromProgress, toProgress);
            anim.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    launchTaskRunnable.run();
                }
            });
            anim.setDuration(duration).start();
            return;
        }

        if (ENABLE_AUTO_ADVANCE) {
            mAutoAdvanceAlarm.cancelAlarm();
        }
        int page = mRecentsView.getNextPage();
        int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
                * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
        if (mRecentsView.getChildCount() > 0 && mRecentsView.snapToPage(page, snapDuration)) {
@@ -151,19 +229,28 @@ public class QuickScrubController implements OnAlarmListener {
        mLaunchingTaskId = 0;
    }

    public boolean prepareQuickScrub(String tag) {
        return prepareQuickScrub(tag, mIsQuickSwitch);
    }

    /**
     * Initializes the UI for quick scrub, returns true if success.
     */
    public boolean prepareQuickScrub(String tag) {
    public boolean prepareQuickScrub(String tag, boolean isQuickSwitch) {
        if (mWaitingForTaskLaunch || mInQuickScrub) {
            Log.d(tag, "Waiting for last scrub to finish, will skip this interaction");
            return false;
        }
        mOnFinishedTransitionToQuickScrubRunnable = null;
        mRecentsView.setNextPageSwitchRunnable(null);
        mIsQuickSwitch = isQuickSwitch;
        return true;
    }

    public boolean isQuickSwitch() {
        return mIsQuickSwitch;
    }

    public boolean isWaitingForTaskLaunch() {
        return mWaitingForTaskLaunch;
    }
@@ -179,6 +266,40 @@ public class QuickScrubController implements OnAlarmListener {
    }

    public void onQuickScrubProgress(float progress) {
        if (mIsQuickSwitch) {
            TaskView currentPage = mRecentsView.getTaskViewAt(0);
            TaskView nextPage = mRecentsView.getTaskViewAt(1);
            if (currentPage == null || nextPage == null) {
                return;
            }
            if (!mFinishedTransitionToQuickScrub) {
                mStartProgress = mEndProgress = progress;
            } else {
                float progressDelta = progress - mEndProgress;
                mEndProgress = progress;
                progress = Utilities.boundToRange(progress, mStartProgress, 1);
                progress = Utilities.mapToRange(progress, mStartProgress, 1, 0, 1, LINEAR);
                if (mInQuickScrub) {
                    mShouldSwitchToNext = mPrevProgressDelta > 0.007f || progressDelta > 0.007f
                            || progress >= 0.5f;
                }
                mPrevPrevProgressDelta = mPrevProgressDelta;
                mPrevProgressDelta = progressDelta;
                float scrollDiff = nextPage.getWidth() + mRecentsView.getPageSpacing();
                int scrollDir = mRecentsView.isRtl() ? -1 : 1;
                int linearScrollDiff = (int) (progress * scrollDiff * scrollDir);
                float accelScrollDiff = ACCEL.getInterpolation(progress) * scrollDiff * scrollDir;
                currentPage.setZoomScale(1 - DEACCEL_3.getInterpolation(progress)
                        * TaskView.EDGE_SCALE_DOWN_FACTOR);
                currentPage.setTranslationX(linearScrollDiff + accelScrollDiff);
                nextPage.setTranslationZ(1);
                nextPage.setTranslationY(currentPage.getTranslationY());
                int startScroll = mRecentsView.isRtl() ? mRecentsView.getMaxScrollX() : 0;
                mRecentsView.setScrollX(startScroll + linearScrollDiff);
            }
            return;
        }

        int quickScrubSection = 0;
        for (float threshold : QUICK_SCRUB_THRESHOLDS) {
            if (progress < threshold) {
@@ -228,9 +349,14 @@ public class QuickScrubController implements OnAlarmListener {

    public void snapToNextTaskIfAvailable() {
        if (mInQuickScrub && mRecentsView.getChildCount() > 0) {
            int duration = mStartedFromHome ? QUICK_SCRUB_FROM_HOME_START_DURATION
            int duration = mIsQuickSwitch
                    ? QUICK_SWITCH_FROM_APP_START_DURATION
                    : mStartedFromHome
                        ? QUICK_SCRUB_FROM_HOME_START_DURATION
                        : QUICK_SCRUB_FROM_APP_START_DURATION;
            int pageToGoTo = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1;
            int pageToGoTo = mStartedFromHome || mIsQuickSwitch
                    ? 0
                    : mRecentsView.getNextPage() + 1;
            goToPageWithHaptic(pageToGoTo, duration, true /* forceHaptic */,
                    QUICK_SCRUB_START_INTERPOLATOR);
        }
Loading