Merge "Adding a back stack to go to overview from all-apps" into ub-launcher3-master
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 9069698..b3025ff 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 989803a..2e5e75e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -18,6 +18,7 @@
 import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 
+import android.content.Context;
 import android.graphics.Rect;
 import android.view.View;
 
@@ -74,15 +75,7 @@
 
     @Override
     public float getVerticalProgress(Launcher launcher) {
-        DeviceProfile grid = launcher.getDeviceProfile();
-        if (!grid.isVerticalBarLayout()) {
-            return 1f;
-        }
-
-        float total = grid.heightPx;
-        float searchHeight = total - grid.availableHeightPx +
-                launcher.getResources().getDimension(R.dimen.all_apps_search_box_full_height);
-        return 1 - (searchHeight / total);
+        return getVerticalProgress(launcher.getDeviceProfile(), launcher);
     }
 
     @Override
@@ -125,4 +118,15 @@
 
         return new float[] {scale, translationX, translationY};
     }
+
+    public static float getVerticalProgress(DeviceProfile grid, Context context) {
+        if (!grid.isVerticalBarLayout()) {
+            return 1f;
+        }
+
+        float total = grid.heightPx;
+        float searchHeight = total - grid.availableHeightPx +
+                context.getResources().getDimension(R.dimen.all_apps_search_box_full_height);
+        return 1 - (searchHeight / total);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index d657e4e..1465822 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -15,6 +15,9 @@
  */
 package com.android.launcher3.uioverrides;
 
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -31,9 +34,6 @@
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.RecentsView;
 
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
 public class RecentsViewStateController implements StateHandler {
 
     private final Launcher mLauncher;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
index 3a3b51d..2481c32 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
@@ -279,10 +279,8 @@
                     onRecentsPlanLoaded(recentsModel.getLastLoadPlan());
                 } else {
                     mDragPauseDetector.addDisabledFlags(FLAG_RECENTS_PLAN_LOADING);
+                    recentsModel.loadTasks(-1, this::onRecentsPlanLoaded);
                 }
-                // Reload again so that we get the latest list
-                // TODO: Use callback instead of polling everytime
-                recentsModel.loadTasks(-1, this::onRecentsPlanLoaded);
             } else {
                 mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED);
             }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
index ed60b84..4816e2a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
@@ -77,6 +77,7 @@
 
         mWorkspaceClickTarget.setOnClickListener(this);
         mWidgetsButton.setOnClickListener(this);
+        setOnClickListener(this);
     }
 
     @Override
@@ -168,7 +169,7 @@
 
     @Override
     public void onClick(View view) {
-        if (view == mWorkspaceClickTarget) {
+        if (view == mWorkspaceClickTarget || view == this) {
             mLauncher.getStateManager().goToState(NORMAL);
         } else if (view == mWidgetsButton) {
             WidgetsFullSheet.show(mLauncher, true);
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 3ca1865..ce528e3 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -33,14 +33,15 @@
 import android.view.ViewTreeObserver.OnPreDrawListener;
 
 import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.states.InternalStateHandler;
 import com.android.launcher3.uioverrides.RecentsViewStateController;
 import com.android.launcher3.util.TraceHelper;
@@ -66,6 +67,7 @@
     private static final long RECENTS_VIEW_VISIBILITY_DURATION = 150;
     private static final long MAX_SWIPE_DURATION = 200;
     private static final long MIN_SWIPE_DURATION = 80;
+    private static final int QUICK_SWITCH_SNAP_DURATION = 120;
 
     // Ideal velocity for a smooth transition
     private static final float PIXEL_PER_MS = 2f;
@@ -97,6 +99,7 @@
     private SnapshotDragView mDragView;
     private RecentsView mRecentsView;
     private RecentsViewStateController mStateController;
+    private QuickScrubController mQuickScrubController;
     private Hotseat mHotseat;
     private AllAppsScrim mAllAppsScrim;
     private RecentsTaskLoadPlan mLoadPlan;
@@ -104,14 +107,27 @@
     private boolean mLauncherReady;
     private boolean mTouchEndHandled;
     private float mCurrentDisplacement;
+    private @TouchInteractionService.InteractionType int mInteractionType;
+    private boolean mStartedQuickScrubFromHome;
 
     private Bitmap mTaskSnapshot;
 
-    NavBarSwipeInteractionHandler(RunningTaskInfo runningTaskInfo, Context context) {
+    NavBarSwipeInteractionHandler(RunningTaskInfo runningTaskInfo, Context context,
+            @TouchInteractionService.InteractionType int interactionType) {
         mRunningTaskId = runningTaskInfo.id;
         mContext = context;
+        mInteractionType = interactionType;
         WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
 
+        DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
+        // TODO: If in multi window mode, dp = dp.getMultiWindowProfile()
+        dp = dp.copy(mContext);
+        // TODO: Use different insets for multi-window mode
+        dp.updateInsets(mStableInsets);
+        RecentsView.getPageRect(dp, mContext, mTargetRect);
+        mSourceRect.set(0, 0, dp.widthPx - mStableInsets.left - mStableInsets.right,
+                dp.heightPx - mStableInsets.top - mStableInsets.bottom);
+
         // Build the state callback
         mStateCallback = new MultiStateCallback();
         mStateCallback.addCallback(STATE_LAUNCHER_READY, this::onLauncherReady);
@@ -181,11 +197,24 @@
         mLauncher.getDragLayer().addView(mDragView);
         mDragView.setPivotX(0);
         mDragView.setPivotY(0);
-        mRecentsView = mLauncher.getOverviewPanel();
+        mRecentsView = launcher.getOverviewPanel();
         mStateController = mRecentsView.getStateController();
         mHotseat = mLauncher.getHotseat();
         mAllAppsScrim = mLauncher.findViewById(R.id.all_apps_scrim);
 
+        boolean interactionIsQuick
+                = mInteractionType == TouchInteractionService.INTERACTION_QUICK_SCRUB
+                || mInteractionType == TouchInteractionService.INTERACTION_QUICK_SWITCH;
+        mStartedQuickScrubFromHome = alreadyOnHome && interactionIsQuick;
+        if (interactionIsQuick) {
+            mQuickScrubController = mRecentsView.getQuickScrubController();
+            mQuickScrubController.onQuickScrubStart(mStartedQuickScrubFromHome);
+            animateToProgress(1f, MAX_SWIPE_DURATION);
+            if (mStartedQuickScrubFromHome) {
+                mDragView.setVisibility(View.INVISIBLE);
+            }
+        }
+
         // Optimization
         if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
             // All-apps search box is visible in vertical bar layout.
@@ -214,17 +243,10 @@
 
     @UiThread
     private void updateFinalShift() {
-        if (!mLauncherReady) {
+        if (!mLauncherReady || mStartedQuickScrubFromHome) {
             return;
         }
 
-        if (mTargetRect.isEmpty()) {
-            RecentsView.getPageRect(mLauncher, mTargetRect);
-            DragLayer dl = mLauncher.getDragLayer();
-            mSourceRect.set(0, 0, dl.getWidth() - mStableInsets.left - mStableInsets.right,
-                    dl.getHeight() - mStableInsets.top - mStableInsets.bottom);
-        }
-
         float shift = mCurrentShift.value * mActivityMultiplier.value;
         int hotseatSize = getHotseatSize();
 
@@ -258,7 +280,7 @@
 
     private void setTaskPlanToUi() {
         mRecentsView.update(mLoadPlan);
-        mRecentsView.initToPage(mRecentsView.getFirstTaskIndex());
+        mRecentsView.initToPage(mStartedQuickScrubFromHome ? 0 : mRecentsView.getFirstTaskIndex());
         ObjectAnimator anim = mStateController.animateVisibility(true /* isVisible */)
                 .setDuration(RECENTS_VIEW_VISIBILITY_DURATION);
         anim.addListener(new AnimationSuccessListener() {
@@ -298,7 +320,12 @@
             }
         }
 
-        ObjectAnimator anim = mCurrentShift.animateToValue(endShift).setDuration(duration);
+        animateToProgress(endShift, duration);
+    }
+
+    /** Animates to the given progress, where 0 is the current app and 1 is overview. */
+    private void animateToProgress(float progress, long duration) {
+        ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
         anim.setInterpolator(Interpolators.SCROLL);
         anim.addListener(new AnimationSuccessListener() {
             @Override
@@ -342,5 +369,32 @@
         if (currentRecentsPage instanceof TaskView) {
             ((TaskView) currentRecentsPage).animateIconToScale(1f);
         }
+        if (mInteractionType == TouchInteractionService.INTERACTION_QUICK_SWITCH) {
+            for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
+                TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
+                if (taskView.getTask().key.id != mRunningTaskId) {
+                    mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION);
+                    taskView.postDelayed(() -> {taskView.launchTask(true);},
+                            QUICK_SWITCH_SNAP_DURATION);
+                    break;
+                }
+            }
+        } else if (mInteractionType == TouchInteractionService.INTERACTION_QUICK_SCRUB) {
+            if (mQuickScrubController != null) {
+                mQuickScrubController.snapToPageForCurrentQuickScrubSection();
+            }
+        }
+    }
+
+    public void onQuickScrubEnd() {
+        if (mQuickScrubController != null) {
+            mQuickScrubController.onQuickScrubEnd();
+        }
+    }
+
+    public void onQuickScrubProgress(float progress) {
+        if (mQuickScrubController != null) {
+            mQuickScrubController.onQuickScrubProgress(progress);
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
new file mode 100644
index 0000000..f4c2055
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import android.view.HapticFeedbackConstants;
+
+import com.android.launcher3.Alarm;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.OnAlarmListener;
+
+/**
+ * Responds to quick scrub callbacks to page through and launch recent tasks.
+ *
+ * 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.
+ */
+public class QuickScrubController implements OnAlarmListener {
+
+    private static final int NUM_QUICK_SCRUB_SECTIONS = 5;
+    private static final long AUTO_ADVANCE_DELAY = 500;
+    private static final int QUICKSCRUB_END_SNAP_DURATION_PER_PAGE = 60;
+
+    private Launcher mLauncher;
+    private Alarm mAutoAdvanceAlarm;
+    private RecentsView mRecentsView;
+
+    private int mQuickScrubSection;
+    private int mStartPage;
+
+    public QuickScrubController(Launcher launcher) {
+        mLauncher = launcher;
+        mAutoAdvanceAlarm = new Alarm();
+        mAutoAdvanceAlarm.setOnAlarmListener(this);
+    }
+
+    public void onQuickScrubStart(boolean startingFromHome) {
+        mRecentsView = mLauncher.getOverviewPanel();
+        mStartPage = startingFromHome ? 0 : mRecentsView.getFirstTaskIndex();
+        mQuickScrubSection = 0;
+    }
+
+    public void onQuickScrubEnd() {
+        mAutoAdvanceAlarm.cancelAlarm();
+        if (mRecentsView != null) {
+            int page = mRecentsView.getNextPage();
+            // Settle on the page then launch it.
+            int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
+                    * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
+            mRecentsView.snapToPage(page, snapDuration);
+            mRecentsView.postDelayed(() -> {
+                if (page < mRecentsView.getFirstTaskIndex()) {
+                    mRecentsView.getPageAt(page).performClick();
+                } else {
+                    ((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
+                }
+            }, snapDuration);
+        }
+    }
+
+    public void onQuickScrubProgress(float progress) {
+        int quickScrubSection = Math.round(progress * NUM_QUICK_SCRUB_SECTIONS);
+        if (quickScrubSection != mQuickScrubSection) {
+            int pageToGoTo = mRecentsView.getNextPage() + quickScrubSection - mQuickScrubSection;
+            goToPageWithHaptic(pageToGoTo);
+            if (quickScrubSection == NUM_QUICK_SCRUB_SECTIONS || quickScrubSection == 0) {
+                mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY);
+            } else {
+                mAutoAdvanceAlarm.cancelAlarm();
+            }
+            mQuickScrubSection = quickScrubSection;
+        }
+    }
+
+    public void snapToPageForCurrentQuickScrubSection() {
+        goToPageWithHaptic(mRecentsView.getCurrentPage() + mQuickScrubSection);
+    }
+
+    private void goToPageWithHaptic(int pageToGoTo) {
+        if (pageToGoTo != mRecentsView.getNextPage()) {
+            mRecentsView.snapToPage(pageToGoTo);
+            mRecentsView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP,
+                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+        }
+    }
+
+    @Override
+    public void onAlarm(Alarm alarm) {
+        int currPage = mRecentsView.getNextPage();
+        if (mQuickScrubSection == NUM_QUICK_SCRUB_SECTIONS
+                && currPage < mRecentsView.getPageCount() - 1) {
+            goToPageWithHaptic(currPage + 1);
+        } else if (mQuickScrubSection == 0 && currPage > mStartPage) {
+            goToPageWithHaptic(currPage - 1);
+        }
+        mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index e7e794f..09003b2 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -16,6 +16,8 @@
 
 package com.android.quickstep;
 
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
 import android.animation.LayoutTransition;
 import android.content.Context;
 import android.graphics.Rect;
@@ -29,6 +31,7 @@
 import com.android.launcher3.PagedView;
 import com.android.launcher3.R;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.uioverrides.OverviewState;
 import com.android.launcher3.uioverrides.RecentsViewStateController;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.shared.recents.model.RecentsTaskLoader;
@@ -41,8 +44,6 @@
 
 import java.util.ArrayList;
 
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
 /**
  * A list of recent tasks.
  */
@@ -52,6 +53,8 @@
     public static final int SCROLL_TYPE_TASK = 1;
     public static final int SCROLL_TYPE_WORKSPACE = 2;
 
+    private final Launcher mLauncher;
+    private QuickScrubController mQuickScrubController;
     private final ScrollState mScrollState = new ScrollState();
     private boolean mOverviewStateEnabled;
     private boolean mTaskStackListenerRegistered;
@@ -88,6 +91,9 @@
         setClipChildren(true);
         setupLayoutTransition();
 
+        mLauncher = Launcher.getLauncher(context);
+        mQuickScrubController = new QuickScrubController(mLauncher);
+
         mScrollState.isRtl = mIsRtl;
     }
 
@@ -106,7 +112,8 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        Rect padding = getPadding(Launcher.getLauncher(getContext()));
+        Rect padding =
+                getPadding(Launcher.getLauncher(getContext()).getDeviceProfile(), getContext());
         setPadding(padding.left, padding.top, padding.right, padding.bottom);
 
         mFirstTaskIndex = getPageCount();
@@ -213,8 +220,7 @@
         }
     }
 
-    private static Rect getPadding(Launcher launcher) {
-        DeviceProfile profile = launcher.getDeviceProfile();
+    private static Rect getPadding(DeviceProfile profile, Context context) {
         Rect stableInsets = new Rect();
         WindowManagerWrapper.getInstance().getStableInsets(stableInsets);
         Rect padding = new Rect(profile.workspacePadding);
@@ -228,7 +234,7 @@
             float availableWidth = taskWidth - 2 * Math.max(padding.left, padding.right);
             float availableHeight = profile.availableHeightPx - padding.top - padding.bottom
                     - stableInsets.top
-                    - profile.heightPx * (1 - OVERVIEW.getVerticalProgress(launcher));
+                    - profile.heightPx * (1 - OverviewState.getVerticalProgress(profile, context));
 
             float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
             overviewHeight = taskHeight * scaledRatio;
@@ -247,15 +253,18 @@
     }
 
     public static void getPageRect(Launcher launcher, Rect outRect) {
-        DragLayer dl = launcher.getDragLayer();
-        Rect targetPadding = getPadding(launcher);
-        Rect insets = dl.getInsets();
+        getPageRect(launcher.getDeviceProfile(), launcher, outRect);
+    }
+
+    public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) {
+        Rect targetPadding = getPadding(grid, context);
+        Rect insets = grid.getInsets();
         outRect.set(
                 targetPadding.left + insets.left,
                 targetPadding.top + insets.top,
-                dl.getWidth() - targetPadding.right - insets.right,
-                dl.getHeight() - targetPadding.bottom - insets.bottom);
-        outRect.top += launcher.getResources()
+                grid.widthPx - targetPadding.right - insets.right,
+                grid.heightPx - targetPadding.bottom - insets.bottom);
+        outRect.top += context.getResources()
                 .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
     }
 
@@ -294,10 +303,14 @@
         ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
         removeView(taskView);
         if (getChildCount() == mFirstTaskIndex) {
-            Launcher.getLauncher(getContext()).getStateManager().goToState(LauncherState.NORMAL);
+            mLauncher.getStateManager().goToState(LauncherState.NORMAL);
         }
     }
 
+    public QuickScrubController getQuickScrubController() {
+        return mQuickScrubController;
+    }
+
     public interface PageCallbacks {
 
         /**
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index c72fbf4..56f0e89 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -37,6 +37,7 @@
 import android.os.Build;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.support.annotation.IntDef;
 import android.util.Log;
 import android.view.Choreographer;
 import android.view.Display;
@@ -56,6 +57,8 @@
 import com.android.systemui.shared.system.BackgroundExecutor;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.function.Consumer;
 
 /**
@@ -68,6 +71,17 @@
 
     private static final String TAG = "TouchInteractionService";
 
+    @IntDef(flag = true, value = {
+            INTERACTION_NORMAL,
+            INTERACTION_QUICK_SWITCH,
+            INTERACTION_QUICK_SCRUB
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InteractionType {}
+    public static final int INTERACTION_NORMAL = 0;
+    public static final int INTERACTION_QUICK_SWITCH = 1;
+    public static final int INTERACTION_QUICK_SCRUB = 2;
+
     private final IBinder mMyBinder = new IOverviewProxy.Stub() {
 
         @Override
@@ -79,6 +93,30 @@
         public void onBind(ISystemUiProxy iSystemUiProxy) throws RemoteException {
             mISystemUiProxy = iSystemUiProxy;
         }
+
+        @Override
+        public void onQuickSwitch() {
+            startTouchTracking(INTERACTION_QUICK_SWITCH);
+        }
+
+        @Override
+        public void onQuickScrubStart() {
+            startTouchTracking(INTERACTION_QUICK_SCRUB);
+        }
+
+        @Override
+        public void onQuickScrubEnd() {
+            if (mInteractionHandler != null) {
+                mInteractionHandler.onQuickScrubEnd();
+            }
+        }
+
+        @Override
+        public void onQuickScrubProgress(float progress) {
+            if (mInteractionHandler != null) {
+                mInteractionHandler.onQuickScrubProgress(progress);
+            }
+        }
     };
 
     private final Consumer<MotionEvent> mOtherActivityTouchConsumer
@@ -216,7 +254,7 @@
                 if (mInteractionHandler == null) {
                     if (Math.abs(displacement) >= mTouchSlop) {
                         mStartDisplacement = Math.signum(displacement) * mTouchSlop;
-                        startTouchTracking();
+                        startTouchTracking(INTERACTION_NORMAL);
                     }
                 } else {
                     // Move
@@ -244,10 +282,10 @@
         return mDisplayRotation == Surface.ROTATION_270 && mStableInsets.left > 0;
     }
 
-    private void startTouchTracking() {
+    private void startTouchTracking(@InteractionType int interactionType) {
         // Create the shared handler
         final NavBarSwipeInteractionHandler handler =
-                new NavBarSwipeInteractionHandler(mRunningTask, this);
+                new NavBarSwipeInteractionHandler(mRunningTask, this, interactionType);
 
         TraceHelper.partitionSection("TouchInt", "Thershold crossed ");
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 75e2f70..7a6a244 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -214,6 +214,11 @@
         mBadgeRenderer = new BadgeRenderer(iconSizePx);
     }
 
+    public DeviceProfile copy(Context context) {
+        Point size = new Point(availableWidthPx, availableHeightPx);
+        return new DeviceProfile(context, inv, size, size, widthPx, heightPx, isLandscape);
+    }
+
     DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
         // We take the minimum sizes of this profile and it's multi-window variant to ensure that
         // the system decor is always excluded.
@@ -376,6 +381,10 @@
         updateWorkspacePadding();
     }
 
+    public Rect getInsets() {
+        return mInsets;
+    }
+
     public void updateAppsViewNumCols() {
         allAppsNumCols = allAppsNumPredictiveCols = inv.numColumns;
     }
@@ -509,6 +518,5 @@
         Configuration context = new Configuration(c.getResources().getConfiguration());
         context.orientation = orientation;
         return c.createConfigurationContext(context);
-
     }
 }
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index c590953..3a660dc 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -149,7 +149,6 @@
     private void goToState(LauncherState state, boolean animated, long delay,
             Runnable onCompleteRunnable) {
         if (mLauncher.isInState(state) && mConfig.mCurrentAnimation == null) {
-
             // Run any queued runnable
             if (onCompleteRunnable != null) {
                 onCompleteRunnable.run();