Merge "Fix a couple of issues with app close" into ub-launcher3-master
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index bdc7c36..d8504f1 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -29,7 +29,7 @@
     <dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
     <dimen name="quickstep_fling_min_velocity">250dp</dimen>
 
-    <dimen name="workspace_overview_offset_x">-30dp</dimen>
+    <dimen name="workspace_overview_offset_x">-24dp</dimen>
 
     <!-- TODO: This can be calculated using other resource values -->
     <dimen name="all_apps_search_box_full_height">90dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index f9da000..a4bdd84 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -421,8 +421,9 @@
                                          Runnable finishedCallback) {
                 Handler handler = mLauncher.getWindow().getDecorView().getHandler();
                 postAtFrontOfQueueAsynchronously(handler, () -> {
-                    // We use a separate transition for Overview mode.
-                    if (mLauncher.isInState(LauncherState.OVERVIEW)) {
+                    if (Utilities.getPrefs(mLauncher).getBoolean("pref_use_screenshot_animation",
+                            true) && mLauncher.isInState(LauncherState.OVERVIEW)) {
+                        // We use a separate transition for Overview mode.
                         setCurrentAnimator(null);
                         finishedCallback.run();
                         return;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
index 92a09dd..8533502 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
@@ -76,7 +76,7 @@
         mTranslateXPage0 = scale[1];
         mTranslateXPage1 = OverviewState
                 .getScaleAndTranslationForPageRect(mLauncher,
-                        getResources().getDimension(R.dimen.workspace_overview_offset_x),
+                        getResources().getDimension(R.dimen.workspace_overview_offset_x) / scale[0],
                         mTempRect)[1];
 
         mExtraScrollShift = 0;
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 944804b..e2abd59 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -92,7 +92,7 @@
     // animated to 1, so allow for a smooth transition.
     private final AnimatedFloat mActivityMultiplier = new AnimatedFloat(this::updateFinalShift);
 
-    private final Task mRunningTask;
+    private final int mRunningTaskId;
     private final Context mContext;
 
     private final MultiStateCallback mStateCallback;
@@ -116,13 +116,9 @@
 
     NavBarSwipeInteractionHandler(RunningTaskInfo runningTaskInfo, Context context,
             @InteractionType int interactionType) {
-        // TODO: We need a better way for this
-        TaskKey taskKey = new TaskKey(runningTaskInfo.id, 0, null, UserHandle.myUserId(), 0);
-        mRunningTask = new Task(taskKey, null, null, "", "", Color.BLACK, Color.BLACK,
-                true, false, false, false, null, 0, null, false);
-
         mContext = context;
         mInteractionType = interactionType;
+        mRunningTaskId = runningTaskInfo.id;
         WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
 
         DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
@@ -192,7 +188,7 @@
         launcher.setOnResumeCallback(this);
         mLauncher = launcher;
         mRecentsView = launcher.getOverviewPanel();
-        mRecentsView.showTask(mRunningTask);
+        mRecentsView.showTask(mRunningTaskId);
         mHotseat = mLauncher.getHotseat();
         mWasLauncherAlreadyVisible = alreadyOnHome;
 
@@ -340,18 +336,15 @@
 
     @UiThread
     private void resumeLastTask() {
-        // TODO: We need a better way for this
-        TaskKey key = mRunningTask.key;
         RecentsTaskLoadPlan loadPlan = RecentsModel.getInstance(mContext).getLastLoadPlan();
         if (loadPlan != null) {
-            Task task = loadPlan.getTaskStack().findTaskWithId(key.id);
+            Task task = loadPlan.getTaskStack().findTaskWithId(mRunningTaskId);
             if (task != null) {
-                key = task.key;
+                ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
+                ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(task.key, opts,
+                        null, null);
             }
         }
-
-        ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
-        ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(key, opts, null, null);
     }
 
     public void reset() {
@@ -380,8 +373,7 @@
         if (mInteractionType == INTERACTION_QUICK_SWITCH) {
             for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
                 TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
-                // TODO: Match the keys directly
-                if (taskView.getTask().key.id != mRunningTask.key.id) {
+                if (taskView.getTask().key.id != mRunningTaskId) {
                     mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION);
                     taskView.postDelayed(() -> {taskView.launchTask(true);},
                             QUICK_SWITCH_SNAP_DURATION);
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 6937c1f..8e03f37 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -98,7 +98,8 @@
     private final RecentsModel mModel;
     private int mLoadPlanId = -1;
 
-    private Task mFirstTask;
+    // Only valid until the launcher state changes to NORMAL
+    private int mRunningTaskId = -1;
 
     private Bitmap mScrim;
     private Paint mFadePaint;
@@ -241,13 +242,6 @@
         final ArrayList<Task> tasks = new ArrayList<>(stack.getTasks());
         setLayoutTransition(null);
 
-        if (mFirstTask != null) {
-            // TODO: Handle this case here once we have a valid implementation for mFirstTask
-            if (tasks.isEmpty() || !keysEquals(tasks.get(tasks.size() - 1), mFirstTask)) {
-                // tasks.add(mFirstTask);
-            }
-        }
-
         final int requiredChildCount = tasks.size() + mFirstTaskIndex;
         for (int i = getChildCount(); i < requiredChildCount; i++) {
             final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false);
@@ -394,7 +388,7 @@
     }
 
     public void reset() {
-        mFirstTask = null;
+        mRunningTaskId = -1;
         setCurrentPage(0);
     }
 
@@ -407,11 +401,7 @@
      */
     public void reloadIfNeeded() {
         if (!mModel.isLoadPlanValid(mLoadPlanId)) {
-            int taskId = -1;
-            if (mFirstTask != null) {
-                taskId = mFirstTask.key.id;
-            }
-            mLoadPlanId = mModel.loadTasks(taskId, this::applyLoadPlan);
+            mLoadPlanId = mModel.loadTasks(mRunningTaskId, this::applyLoadPlan);
         }
     }
 
@@ -423,41 +413,30 @@
      * is called.
      * Also scrolls the view to this task
      */
-    public void showTask(Task task) {
+    public void showTask(int runningTaskId) {
         boolean needsReload = false;
-        boolean inflateFirstChild = true;
-        if (getTaskCount() > 0) {
-            TaskView tv = (TaskView) getChildAt(mFirstTaskIndex);
-            inflateFirstChild = !keysEquals(tv.getTask(), task);
-        }
-        if (inflateFirstChild) {
+        if (getTaskCount() == 0) {
             needsReload = true;
-            setLayoutTransition(null);
             // Add an empty view for now
+            setLayoutTransition(null);
             final TaskView taskView = (TaskView) LayoutInflater.from(getContext())
                     .inflate(R.layout.task, this, false);
             addView(taskView, mFirstTaskIndex);
-            taskView.bind(task);
             setLayoutTransition(mLayoutTransition);
         }
         if (!needsReload) {
             needsReload = !mModel.isLoadPlanValid(mLoadPlanId);
         }
         if (needsReload) {
-            mLoadPlanId = mModel.loadTasks(task.key.id, this::applyLoadPlan);
+            mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
         }
-        mFirstTask = task;
+        mRunningTaskId = runningTaskId;
         setCurrentPage(mFirstTaskIndex);
         if (mCurrentPage >= mFirstTaskIndex) {
             ((TaskView) getPageAt(mCurrentPage)).setIconScale(0);
         }
     }
 
-    private static boolean keysEquals(Task t1, Task t2) {
-        // TODO: Match the keys directly
-        return t1.key.id == t2.key.id;
-    }
-
     public QuickScrubController getQuickScrubController() {
         return mQuickScrubController;
     }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index a760b75..0490832 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -58,6 +58,7 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.model.ModelPreload;
 import com.android.launcher3.util.TraceHelper;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -195,6 +196,7 @@
         mEventQueue = new MotionEventQueue(Choreographer.getInstance(), mNoOpTouchConsumer);
         sConnected = true;
 
+        new ModelPreload().start(this);
         initBackgroundChoreographer();
     }
 
@@ -241,6 +243,19 @@
                 mDownPos.set(ev.getX(), ev.getY());
                 mLastPos.set(mDownPos);
                 mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
+                mTouchThresholdCrossed = false;
+
+                // Clean up the old interaction handler
+                if (mInteractionHandler != null) {
+                    final BaseSwipeInteractionHandler handler = mInteractionHandler;
+                    mMainThreadExecutor.execute(handler::reset);
+                    mInteractionHandler = null;
+                }
+
+                // Start the window animation on down to give more time for launcher to draw
+                if (!isUsingScreenShot()) {
+                    startTouchTrackingForWindowAnimation();
+                }
 
                 if (mVelocityTracker == null) {
                     mVelocityTracker = VelocityTracker.obtain();
@@ -248,12 +263,6 @@
                     mVelocityTracker.clear();
                 }
                 mVelocityTracker.addMovement(ev);
-                if (mInteractionHandler != null) {
-                    final BaseSwipeInteractionHandler handler = mInteractionHandler;
-                    mMainThreadExecutor.execute(handler::reset);
-                    mInteractionHandler = null;
-                }
-                mTouchThresholdCrossed = false;
 
                 Display display = getSystemService(WindowManager.class).getDefaultDisplay();
                 mDisplayRotation = display.getRotation();
@@ -293,7 +302,11 @@
                     if (mTouchThresholdCrossed) {
                         mStartDisplacement = Math.signum(displacement) * mTouchSlop;
 
-                        startTouchTracking();
+                        if (isUsingScreenShot()) {
+                            startTouchTrackingForScreenshotAnimation();
+                        }
+
+                        // Notify the handler that the gesture has actually started
                         mInteractionHandler.onGestureStarted();
 
                         // Notify the system that we have started tracking the event
@@ -334,77 +347,76 @@
     /**
      * Called when the gesture has started.
      */
-    private void startTouchTracking() {
-        if (isUsingScreenShot()) {
-            // Create the shared handler
-            final NavBarSwipeInteractionHandler handler =
-                    new NavBarSwipeInteractionHandler(mRunningTask, this, INTERACTION_NORMAL);
+    private void startTouchTrackingForScreenshotAnimation() {
+        // Create the shared handler
+        final NavBarSwipeInteractionHandler handler =
+                new NavBarSwipeInteractionHandler(mRunningTask, this, INTERACTION_NORMAL);
 
-            TraceHelper.partitionSection("TouchInt", "Thershold crossed ");
+        TraceHelper.partitionSection("TouchInt", "Thershold crossed ");
 
-            // Start the recents activity on a background thread
-            BackgroundExecutor.get().submit(() -> {
-                // Get the snap shot before
-                handler.setTaskSnapshot(getCurrentTaskSnapshot());
+        // Start the recents activity on a background thread
+        BackgroundExecutor.get().submit(() -> {
+            // Get the snap shot before
+            handler.setTaskSnapshot(getCurrentTaskSnapshot());
 
-                // Start the launcher activity with our custom handler
-                Intent homeIntent = handler.addToIntent(new Intent(mHomeIntent));
-                startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, 0).toBundle());
-                TraceHelper.partitionSection("TouchInt", "Home started");
-            });
+            // Start the launcher activity with our custom handler
+            Intent homeIntent = handler.addToIntent(new Intent(mHomeIntent));
+            startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, 0).toBundle());
+            TraceHelper.partitionSection("TouchInt", "Home started");
+        });
 
-            // Preload the plan
-            mRecentsModel.loadTasks(mRunningTask.id, null);
-            mInteractionHandler = handler;
-            mInteractionHandler.setGestureEndCallback(() ->  mInteractionHandler = null);
-        } else {
+        // Preload the plan
+        mRecentsModel.loadTasks(mRunningTask.id, null);
+        mInteractionHandler = handler;
+        mInteractionHandler.setGestureEndCallback(() ->  mInteractionHandler = null);
+    }
 
-            // Create the shared handler
-            final WindowTransformSwipeHandler handler =
-                    new WindowTransformSwipeHandler(mRunningTask, this);
-            BackgroundExecutor.get().submit(() -> {
-                ActivityManagerWrapper.getInstance().startRecentsActivity(mHomeIntent,
-                        new AssistDataReceiver() {
-                            @Override
-                            public void onHandleAssistData(Bundle bundle) {
-                                // Pass to AIAI
+    private void startTouchTrackingForWindowAnimation() {
+        // Create the shared handler
+        final WindowTransformSwipeHandler handler =
+                new WindowTransformSwipeHandler(mRunningTask, this);
+        BackgroundExecutor.get().submit(() -> {
+            ActivityManagerWrapper.getInstance().startRecentsActivity(mHomeIntent,
+                    new AssistDataReceiver() {
+                        @Override
+                        public void onHandleAssistData(Bundle bundle) {
+                            // Pass to AIAI
+                        }
+                    },
+                    new RecentsAnimationListener() {
+                        public void onAnimationStart(
+                                RecentsAnimationControllerCompat controller,
+                                RemoteAnimationTargetCompat[] apps) {
+                            if (mInteractionHandler == handler) {
+                                handler.setRecentsAnimation(controller, apps);
+
+                            } else {
+                                controller.finish(false /* toHome */);
                             }
-                        },
-                        new RecentsAnimationListener() {
-                            public void onAnimationStart(
-                                    RecentsAnimationControllerCompat controller,
-                                    RemoteAnimationTargetCompat[] apps) {
-                                if (mInteractionHandler == handler) {
-                                    handler.setRecentsAnimation(controller, apps);
+                        }
 
-                                } else {
-                                    controller.finish(false /* toHome */);
-                                }
+                        public void onAnimationCanceled() {
+                            if (mInteractionHandler == handler) {
+                                handler.setRecentsAnimation(null, null);
                             }
+                        }
+                    }, null, null);
+        });
 
-                            public void onAnimationCanceled() {
-                                if (mInteractionHandler == handler) {
-                                    handler.setRecentsAnimation(null, null);
-                                }
-                            }
-                        }, null, null);
-            });
-
-            // Preload the plan
-            mRecentsModel.loadTasks(mRunningTask.id, null);
-            mInteractionHandler = handler;
-            handler.setGestureEndCallback(() -> {
-                if (handler == mInteractionHandler) {
-                    mInteractionHandler = null;
-                }
-            });
-            handler.setLauncherOnDrawCallback(() -> {
-                if (handler == mInteractionHandler) {
-                    mEventQueue.setInterimChoreographer(null);
-                }
-            });
-            mMainThreadExecutor.execute(handler::initWhenReady);
-        }
+        // Preload the plan
+        mRecentsModel.loadTasks(mRunningTask.id, null);
+        mInteractionHandler = handler;
+        handler.setGestureEndCallback(() -> {
+            if (handler == mInteractionHandler) {
+                mInteractionHandler = null;
+            }
+        });
+        handler.setLauncherOnDrawCallback(() -> {
+            if (handler == mInteractionHandler) {
+                mEventQueue.setInterimChoreographer(null);
+            }
+        });
+        mMainThreadExecutor.execute(handler::initWhenReady);
     }
 
     private void updateTouchTracking(@InteractionType int interactionType) {
@@ -425,6 +437,11 @@
                     : isNavBarOnLeft() ? -mVelocityTracker.getXVelocity(mActivePointerId)
                     : mVelocityTracker.getYVelocity(mActivePointerId);
             mInteractionHandler.onGestureEnded(velocity);
+        } else if (!isUsingScreenShot()) {
+            // Since we start touch tracking on DOWN, we may reach this state without actually
+            // starting the gesture. In that case, just cleanup immediately.
+            final BaseSwipeInteractionHandler handler = mInteractionHandler;
+            mMainThreadExecutor.execute(handler::reset);
         }
         mVelocityTracker.recycle();
         mVelocityTracker = null;
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 16b34f9..1351973 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -15,8 +15,6 @@
  */
 package com.android.quickstep;
 
-import static android.view.MotionEvent.ACTION_UP;
-
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.quickstep.TouchInteractionService.INTERACTION_NORMAL;
@@ -33,12 +31,10 @@
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Looper;
-import android.os.UserHandle;
 import android.support.annotation.UiThread;
 import android.support.annotation.WorkerThread;
 import android.view.View;
@@ -59,10 +55,7 @@
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.TraceHelper;
 import com.android.quickstep.TouchInteractionService.InteractionType;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.Task.TaskKey;
 import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.system.TransactionCompat;
@@ -107,8 +100,10 @@
     // visible.
     private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
 
-    private final Task mRunningTask;
+    private final MainThreadExecutor mMainExecutor = new MainThreadExecutor();
+
     private final Context mContext;
+    private final int mRunningTaskId;
 
     private MultiStateCallback mStateCallback;
     private boolean mControllerStateAnimation;
@@ -131,22 +126,9 @@
     private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper();
     private Matrix mTmpMatrix = new Matrix();
 
-    private final InputConsumerController mInputConsumerController;
-    private final InputConsumerController.TouchListener mInputConsumerTouchListener =
-            (ev) -> {
-                if (ev.getActionMasked() == ACTION_UP) {
-                    // TODO: Handle touch event while the transition is in progress.
-                }
-                return true;
-            };
-
     WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context) {
-        // TODO: We need a better way for this
-        TaskKey taskKey = new TaskKey(runningTaskInfo.id, 0, null, UserHandle.myUserId(), 0);
-        mRunningTask = new Task(taskKey, null, null, "", "", Color.BLACK, Color.BLACK,
-                true, false, false, false, null, 0, null, false);
         mContext = context;
-        mInputConsumerController = InputConsumerController.getRecentsAnimationInputConsumer();
+        mRunningTaskId = runningTaskInfo.id;
 
         WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
 
@@ -181,6 +163,10 @@
                 mLauncherDrawnCallback);
     }
 
+    private void setStateOnUiThread(int stateFlag) {
+        mMainExecutor.execute(() -> mStateCallback.setState(stateFlag));
+    }
+
     public void setLauncherOnDrawCallback(Runnable callback) {
         mLauncherDrawnCallback = callback;
         mStateCallback.addCallback(STATE_LAUNCHER_READY | STATE_LAUNCHER_DRAWN,
@@ -264,7 +250,7 @@
         }
 
         mRecentsView = mLauncher.getOverviewPanel();
-        mRecentsView.showTask(mRunningTask);
+        mRecentsView.showTask(mRunningTaskId);
         mWasLauncherAlreadyVisible = alreadyOnHome;
         mLauncherLayoutListener = new LauncherLayoutListener(mLauncher, this);
         mLauncher.getDragLayer().addView(mLauncherLayoutListener);
@@ -307,7 +293,7 @@
         }
     }
 
-    @UiThread
+    @WorkerThread
     public void updateDisplacement(float displacement) {
         mCurrentDisplacement = displacement;
 
@@ -359,9 +345,6 @@
                     AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
             mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
         }
-
-        // In case the transition length changed (which should never happen, redo everything
-        updateDisplacement(mCurrentDisplacement);
     }
 
     @WorkerThread
@@ -397,9 +380,12 @@
             }
         }
 
-        if (Looper.getMainLooper() == Looper.myLooper()) {
-            if (mLauncherTransitionController != null) {
+        if (mLauncherTransitionController != null) {
+            if (Looper.getMainLooper() == Looper.myLooper()) {
                 mLauncherTransitionController.setPlayFraction(shift);
+            } else {
+                // The fling operation completed even before the launcher was drawn
+                mMainExecutor.execute(() -> mLauncherTransitionController.setPlayFraction(shift));
             }
         }
     }
@@ -407,18 +393,12 @@
     public void setRecentsAnimation(RecentsAnimationControllerCompat controller,
             RemoteAnimationTargetCompat[] apps) {
         mRecentsAnimationWrapper.setController(controller, apps);
-        mStateCallback.setState(STATE_APP_CONTROLLER_RECEIVED);
+        setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
     }
 
-    public void onGestureStarted() {
-        mInputConsumerController.unregisterInputConsumer();
-        mInputConsumerController.registerInputConsumer();
-        mInputConsumerController.setTouchListener(mInputConsumerTouchListener);
+    public void onGestureStarted() { }
 
-        mRecentsAnimationWrapper.enableInputConsumer();
-    }
-
-    @UiThread
+    @WorkerThread
     public void onGestureEnded(float endVelocity) {
         Resources res = mContext.getResources();
         float flingThreshold = res.getDimension(R.dimen.quickstep_fling_threshold_velocity);
@@ -451,9 +431,8 @@
         anim.addListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationSuccess(Animator animator) {
-                new MainThreadExecutor().execute(() -> mStateCallback.setState(
-                        (Float.compare(mCurrentShift.value, 0) == 0)
-                                ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS));
+                setStateOnUiThread((Float.compare(mCurrentShift.value, 0) == 0)
+                        ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS);
             }
         });
         anim.start();
@@ -470,12 +449,13 @@
         if (mGestureEndCallback != null) {
             mGestureEndCallback.run();
         }
-        mInputConsumerController.unregisterInputConsumer();
 
-        // TODO: These should be done as part of ActivityOptions#OnAnimationStarted
-        mLauncher.getStateManager().reapplyState();
-        mLauncher.setOnResumeCallback(() -> mLauncherLayoutListener.close(false));
-        mLauncherTransitionController.setPlayFraction(1);
+        if (mLauncher != null) {
+            // TODO: These should be done as part of ActivityOptions#OnAnimationStarted
+            mLauncher.getStateManager().reapplyState();
+            mLauncher.setOnResumeCallback(() -> mLauncherLayoutListener.close(false));
+            mLauncherTransitionController.setPlayFraction(1);
+        }
         clearReference();
     }
 
@@ -495,7 +475,7 @@
             for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
                 TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
                 // TODO: Match the keys directly
-                if (taskView.getTask().key.id != mRunningTask.key.id) {
+                if (taskView.getTask().key.id != mRunningTaskId) {
                     mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION);
                     taskView.postDelayed(() -> {taskView.launchTask(true);},
                             QUICK_SWITCH_SNAP_DURATION);
diff --git a/res/color/all_apps_work_tab_text.xml b/res/color/all_apps_work_tab_text.xml
deleted file mode 100644
index 7279bf8..0000000
--- a/res/color/all_apps_work_tab_text.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/work_profile_color" android:state_selected="true"/>
-    <item android:color="?android:attr/textColorTertiary"/>
-</selector>
\ No newline at end of file
diff --git a/res/layout/all_apps_floating_header.xml b/res/layout/all_apps_floating_header.xml
index 166725d..c4240f8 100644
--- a/res/layout/all_apps_floating_header.xml
+++ b/res/layout/all_apps_floating_header.xml
@@ -52,7 +52,7 @@
             android:fontFamily="sans-serif-medium"
             android:text="@string/all_apps_work_tab"
             android:textAllCaps="true"
-            android:textColor="@color/all_apps_work_tab_text"
+            android:textColor="@color/all_apps_tab_text"
             android:textSize="14sp" />
     </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
 </com.android.launcher3.allapps.FloatingHeaderView>
diff --git a/res/layout/system_shortcut_icon_only.xml b/res/layout/system_shortcut_icon_only.xml
index c59cb53..b8b5b8c 100644
--- a/res/layout/system_shortcut_icon_only.xml
+++ b/res/layout/system_shortcut_icon_only.xml
@@ -20,5 +20,6 @@
     android:layout_height="@dimen/system_shortcut_header_icon_touch_size"
     android:background="?android:attr/selectableItemBackgroundBorderless"
     android:tint="?android:attr/textColorHint"
+    android:tintMode="src_in"
     android:padding="@dimen/system_shortcut_header_icon_padding"
     android:theme="@style/PopupItem" />
diff --git a/res/layout/work_tab_footer.xml b/res/layout/work_tab_footer.xml
index dc0fdd4..21ff55e 100644
--- a/res/layout/work_tab_footer.xml
+++ b/res/layout/work_tab_footer.xml
@@ -38,8 +38,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentEnd="true"
-        android:layout_below="@id/work_footer_divider"
-        android:theme="@style/WorkModeSwitchTheme"/>
+        android:layout_below="@id/work_footer_divider"/>
 
     <TextView
         android:id="@android:id/title"
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 4abdfd6..eb207af 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -38,6 +38,4 @@
 
     <color name="all_apps_bg_hand_fill">#E5E5E5</color>
     <color name="all_apps_bg_hand_fill_dark">#9AA0A6</color>
-
-    <color name="work_profile_color">#FF6D00</color>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index c714841..8cc4743 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -168,8 +168,4 @@
         <item name="android:colorControlHighlight">#DFE1E5</item>
         <item name="android:colorForeground">@color/all_apps_bg_hand_fill_dark</item>
     </style>
-
-    <style name="WorkModeSwitchTheme" parent="@style/LauncherTheme">
-        <item name="android:colorAccent">@color/work_profile_color</item>
-    </style>
 </resources>
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 1b169f5..929606e 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -20,7 +20,6 @@
 import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
 
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -40,21 +39,18 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
 import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.LauncherIcons;
 import com.android.launcher3.model.AddWorkspaceItemsTask;
+import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.CacheDataUpdatedTask;
-import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.LoaderResults;
 import com.android.launcher3.model.LoaderTask;
 import com.android.launcher3.model.ModelWriter;
 import com.android.launcher3.model.PackageInstallStateChangedTask;
-import com.android.launcher3.model.PackageItemInfo;
 import com.android.launcher3.model.PackageUpdatedTask;
 import com.android.launcher3.model.ShortcutsChangedTask;
 import com.android.launcher3.model.UserLockStateChangedTask;
-import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.provider.LauncherDbUtils;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index dc3de18..338bdf3 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -538,7 +538,7 @@
 
     public void onScrollUpEnd() {
         if (mUsingTabs) {
-            ((PersonalWorkSlidingTabStrip) findViewById(R.id.tabs)).peekWorkTabIfNecessary();
+            ((PersonalWorkSlidingTabStrip) findViewById(R.id.tabs)).highlightWorkTabIfNecessary();
         }
     }
 
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index 393884e..05cd655 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.allapps;
 
-import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.graphics.Canvas;
@@ -30,7 +29,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.util.Themes;
 
 /**
@@ -39,13 +37,10 @@
 public class PersonalWorkSlidingTabStrip extends LinearLayout {
     private static final int POSITION_PERSONAL = 0;
     private static final int POSITION_WORK = 1;
-    private static final int PEEK_DURATION = 1000;
-    private static final float PEAK_OFFSET = 0.4f;
 
     private static final String KEY_SHOWED_PEEK_WORK_TAB = "showed_peek_work_tab";
 
-    private final Paint mPersonalTabIndicatorPaint;
-    private final Paint mWorkTabIndicatorPaint;
+    private final Paint mSelectedIndicatorPaint;
     private final Paint mDividerPaint;
     private final SharedPreferences mSharedPreferences;
 
@@ -55,7 +50,6 @@
     private int mIndicatorPosition = 0;
     private float mIndicatorOffset;
     private int mSelectedPosition = 0;
-    private boolean mIsRtl;
 
     public PersonalWorkSlidingTabStrip(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
@@ -65,15 +59,10 @@
         mSelectedIndicatorHeight =
                 getResources().getDimensionPixelSize(R.dimen.all_apps_tabs_indicator_height);
 
-        mPersonalTabIndicatorPaint = new Paint();
-        mPersonalTabIndicatorPaint.setColor(
+        mSelectedIndicatorPaint = new Paint();
+        mSelectedIndicatorPaint.setColor(
                 Themes.getAttrColor(context, android.R.attr.colorAccent));
 
-        mWorkTabIndicatorPaint = new Paint();
-        mWorkTabIndicatorPaint.setColor(getResources().getColor(R.color.work_profile_color));
-
-        mIsRtl = Utilities.isRtl(getResources());
-
         mDividerPaint = new Paint();
         mDividerPaint.setColor(Themes.getAttrColor(context, android.R.attr.colorControlHighlight));
         mDividerPaint.setStrokeWidth(
@@ -142,40 +131,26 @@
         canvas.drawLine(getPaddingLeft(), y, getWidth() - getPaddingRight(), y, mDividerPaint);
 
         final float middleX = getWidth() / 2.0f;
-        if (mIndicatorLeft <= middleX) {
-            canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
-                    middleX, getHeight(), getPaint(true /* firstHalf */));
-        }
-        if (mIndicatorRight > middleX) {
-            canvas.drawRect(middleX, getHeight() - mSelectedIndicatorHeight,
-                    mIndicatorRight, getHeight(), getPaint(false /* firstHalf */));
-        }
+        canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
+            mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
     }
 
-    private Paint getPaint(boolean firstHalf) {
-        boolean isPersonal = mIsRtl ^ firstHalf;
-        return isPersonal ? mPersonalTabIndicatorPaint : mWorkTabIndicatorPaint;
-    }
-
-    public void peekWorkTabIfNecessary() {
+    public void highlightWorkTabIfNecessary() {
         if (mSharedPreferences.getBoolean(KEY_SHOWED_PEEK_WORK_TAB, false)) {
             return;
         }
         if (mIndicatorPosition != POSITION_PERSONAL) {
             return;
         }
-        peekWorkTab();
+        highlightWorkTab();
         mSharedPreferences.edit().putBoolean(KEY_SHOWED_PEEK_WORK_TAB, true).apply();
     }
 
-    private void peekWorkTab() {
-        final boolean isRtl = Utilities.isRtl(getResources());
-        ValueAnimator animator = ValueAnimator.ofFloat(0, isRtl ? 1 - PEAK_OFFSET : PEAK_OFFSET, 0);
-        animator.setDuration(PEEK_DURATION);
-        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        animator.addUpdateListener(
-                animation -> updateIndicatorPosition(mIndicatorPosition,
-                        (float) animation.getAnimatedValue()));
-        animator.start();
+    private void highlightWorkTab() {
+        View v = getChildAt(POSITION_WORK);
+        v.post(() -> {
+            v.setPressed(true);
+            v.setPressed(false);
+        });
     }
 }
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 883c33d..00dd3aa 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -54,7 +54,6 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIconPreviewVerifier;
-import com.android.launcher3.graphics.IconNormalizer;
 import com.android.launcher3.graphics.LauncherIcons;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.provider.ImportDataTask;
diff --git a/src/com/android/launcher3/model/ModelPreload.java b/src/com/android/launcher3/model/ModelPreload.java
new file mode 100644
index 0000000..6f33bed
--- /dev/null
+++ b/src/com/android/launcher3/model/ModelPreload.java
@@ -0,0 +1,70 @@
+/*
+ * 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.launcher3.model;
+
+import android.content.Context;
+import android.support.annotation.WorkerThread;
+import android.util.Log;
+
+import com.android.launcher3.AllAppsList;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Utility class to preload LauncherModel
+ */
+public class ModelPreload implements ModelUpdateTask {
+
+    private static final String TAG = "ModelPreload";
+
+    private LauncherAppState mApp;
+    private LauncherModel mModel;
+    private BgDataModel mBgDataModel;
+    private AllAppsList mAllAppsList;
+
+    @Override
+    public final void init(LauncherAppState app, LauncherModel model, BgDataModel dataModel,
+            AllAppsList allAppsList, Executor uiExecutor) {
+        mApp = app;
+        mModel = model;
+        mBgDataModel = dataModel;
+        mAllAppsList = allAppsList;
+    }
+
+    @Override
+    public final void run() {
+        if (!mModel.isModelLoaded()) {
+            Log.d(TAG, "Workspace not loaded, loading now");
+            mModel.startLoaderForResults(
+                    new LoaderResults(mApp, mBgDataModel, mAllAppsList, 0, null));
+        }
+        Log.d(TAG, "Preload completed : " + mModel.isModelLoaded());
+        onComplete(mModel.isModelLoaded());
+    }
+
+    /**
+     * Called when the task is complete
+     */
+    @WorkerThread
+    public void onComplete(boolean isSuccess) { }
+
+    public void start(Context context) {
+        LauncherAppState.getInstance(context).getModel().enqueueModelUpdateTask(this);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/util/VerticalSwipeController.java b/src/com/android/launcher3/util/VerticalSwipeController.java
index 5d47cd2..29477e3 100644
--- a/src/com/android/launcher3/util/VerticalSwipeController.java
+++ b/src/com/android/launcher3/util/VerticalSwipeController.java
@@ -259,7 +259,7 @@
         });
 
         float nextFrameProgress = Utilities.boundToRange(
-                progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
+                progress + velocity * SINGLE_FRAME_MS * mProgressMultiplier, 0f, 1f);
 
         ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
         anim.setFloatValues(nextFrameProgress, targetState == mToState ? 1f : 0f);