Merge "Always place notification dots directly on adaptive icon path" into ub-launcher3-qt-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index 624b3dc..5e77e0a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -68,7 +68,7 @@
      * @param wasVisible true if it was visible before
      */
     boolean onActivityReady(T activity, Boolean wasVisible) {
-        activity.<RecentsView>getOverviewPanel().setCurrentTask(mTargetTaskId);
+        activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTaskId);
         AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
         ActivityControlHelper.AnimationFactory factory =
                 mHelper.prepareRecentsUI(activity, wasVisible,
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
index 7fc5d50..db377b0 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
@@ -21,7 +21,6 @@
 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.Utilities.EDGE_NAV_BAR;
 import static com.android.launcher3.util.RaceConditionTracker.ENTER;
 import static com.android.launcher3.util.RaceConditionTracker.EXIT;
@@ -44,6 +43,8 @@
 import android.view.ViewConfiguration;
 import android.view.WindowManager;
 
+import androidx.annotation.UiThread;
+
 import com.android.launcher3.R;
 import com.android.launcher3.graphics.RotationMode;
 import com.android.launcher3.util.Preconditions;
@@ -62,8 +63,6 @@
 
 import java.util.function.Consumer;
 
-import androidx.annotation.UiThread;
-
 /**
  * Input consumer for handling events originating from an activity other than Launcher
  */
@@ -108,7 +107,6 @@
 
     // Might be displacement in X or Y, depending on the direction we are swiping from the nav bar.
     private float mStartDisplacement;
-    private float mStartDisplacementX;
 
     private Handler mMainThreadHandler;
     private Runnable mCancelRecentsAnimationRunnable = () -> {
@@ -227,7 +225,6 @@
                         if (Math.abs(displacement) > mDragSlop) {
                             mPassedDragSlop = true;
                             mStartDisplacement = displacement;
-                            mStartDisplacementX = displacementX;
                         }
                     }
                 }
@@ -244,19 +241,20 @@
                         if (!mPassedDragSlop) {
                             mPassedDragSlop = true;
                             mStartDisplacement = displacement;
-                            mStartDisplacementX = displacementX;
                         }
                         notifyGestureStarted();
                     }
                 }
 
-                if (mPassedDragSlop && mInteractionHandler != null) {
-                    // Move
-                    mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
+                if (mInteractionHandler != null) {
+                    if (mPassedDragSlop) {
+                        // Move
+                        mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
+                    }
 
                     if (mMode == Mode.NO_BUTTON) {
-                        float horizontalDist = Math.abs(displacementX - mStartDisplacementX);
-                        float upDist = -(displacement - mStartDisplacement);
+                        float horizontalDist = Math.abs(displacementX);
+                        float upDist = -displacement;
                         boolean isLikelyToStartNewTask = horizontalDist > upDist;
                         mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement
                                 || isLikelyToStartNewTask);
@@ -382,7 +380,7 @@
             mSwipeSharedState.canGestureBeContinued = endTarget != null && endTarget.canBeContinued;
             mSwipeSharedState.goingToLauncher = endTarget != null && endTarget.isLauncher;
             if (mSwipeSharedState.canGestureBeContinued) {
-                mInteractionHandler.cancelCurrentAnimation();
+                mInteractionHandler.cancelCurrentAnimation(mSwipeSharedState);
             } else {
                 mInteractionHandler.reset();
             }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java
index ced9afa..96d2dca 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -59,6 +59,10 @@
         mInputProxySupplier = inputProxySupplier;
     }
 
+    public boolean hasTargets() {
+        return targetSet != null && targetSet.hasTargets();
+    }
+
     @UiThread
     public synchronized void setController(SwipeAnimationTargetSet targetSet) {
         Preconditions.assertUIThread();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java
index f393387..194d073 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java
@@ -38,6 +38,8 @@
 
     public boolean canGestureBeContinued;
     public boolean goingToLauncher;
+    public boolean recentsAnimationFinishInterrupted;
+    public int nextRunningTaskId = -1;
 
     public SwipeSharedState(OverviewComponentObserver overviewComponentObserver) {
         mOverviewComponentObserver = overviewComponentObserver;
@@ -114,9 +116,22 @@
         }
     }
 
+    /**
+     * Called when a recents animation has finished, but was interrupted before the next task was
+     * launched. The given {@param runningTaskId} should be used as the running task for the
+     * continuing input consumer.
+     */
+    public void setRecentsAnimationFinishInterrupted(int runningTaskId) {
+        recentsAnimationFinishInterrupted = true;
+        nextRunningTaskId = runningTaskId;
+        mLastAnimationTarget = mLastAnimationTarget.cloneWithoutTargets();
+    }
+
     public void clearAllState() {
         clearListenerState();
         canGestureBeContinued = false;
+        recentsAnimationFinishInterrupted = false;
+        nextRunningTaskId = -1;
         goingToLauncher = false;
     }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
index f95f9c2..d0ea73a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
@@ -150,6 +150,7 @@
 
             @Override
             public void onUpdate(float percent) {
+                // TODO: Take into account the current fullscreen progress for animating the insets
                 params.setProgress(1 - percent);
                 RectF taskBounds = inOutHelper.applyTransform(targetSet, params);
                 if (!skipViewChanges) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index b25865e..61ae880 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -26,6 +26,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 
 import android.annotation.TargetApi;
+import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.KeyguardManager;
 import android.app.Service;
@@ -456,7 +457,7 @@
             return new DeviceLockedInputConsumer(this);
         }
 
-        RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0);
+        final RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0);
         if (!useSharedState) {
             mSwipeSharedState.clearAllState();
         }
@@ -465,8 +466,15 @@
                 mOverviewComponentObserver.getActivityControlHelper();
 
         InputConsumer base;
-        if (runningTaskInfo == null && !mSwipeSharedState.goingToLauncher) {
+        if (runningTaskInfo == null && !mSwipeSharedState.goingToLauncher
+                && !mSwipeSharedState.recentsAnimationFinishInterrupted) {
             base = InputConsumer.NO_OP;
+        } else if (mSwipeSharedState.recentsAnimationFinishInterrupted) {
+            // If the finish animation was interrupted, then continue using the other activity input
+            // consumer but with the next task as the running task
+            RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
+            info.id = mSwipeSharedState.nextRunningTaskId;
+            base = createOtherActivityInputConsumer(event, info);
         } else if (mSwipeSharedState.goingToLauncher || activityControl.isResumed()) {
             base = OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false);
         } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() &&
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 0caef6f..936f0aa 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -256,7 +256,9 @@
     private AnimationFactory mAnimationFactory = (t) -> { };
     private LiveTileOverlay mLiveTileOverlay = new LiveTileOverlay();
 
+    private boolean mCanceled;
     private boolean mWasLauncherAlreadyVisible;
+    private int mFinishingRecentsAnimationForNewTaskId = -1;
 
     private boolean mPassedOverviewThreshold;
     private boolean mGestureStarted;
@@ -412,7 +414,6 @@
             mRecentsAnimationWrapper.runOnInit(() ->
                     mRecentsAnimationWrapper.targetSet.addDependentTransactionApplier(applier));
             });
-        mRecentsView.setEnableFreeScroll(false);
 
         mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
             if (mGestureEndTarget != HOME) {
@@ -500,10 +501,7 @@
         if (mContinuingLastGesture) {
             return;
         }
-        mRecentsView.setEnableDrawingLiveTile(false);
-        mRecentsView.showTask(mRunningTaskId);
-        mRecentsView.setRunningTaskHidden(true);
-        mRecentsView.setRunningTaskIconScaledDown(true);
+        mRecentsView.onGestureAnimationStart(mRunningTaskId);
     }
 
     private void launcherFrameDrawn() {
@@ -679,7 +677,7 @@
         int runningTaskIndex = mRecentsView == null ? -1 : mRecentsView.getRunningTaskIndex();
         if (runningTaskIndex >= 0) {
             for (int i = 0; i < mRecentsView.getTaskViewCount(); i++) {
-                if (i != runningTaskIndex) {
+                if (i != runningTaskIndex || !mRecentsAnimationWrapper.hasTargets()) {
                     mRecentsView.getTaskViewAt(i).setFullscreenProgress(1 - mCurrentShift.value);
                 }
             }
@@ -838,9 +836,15 @@
         Interpolator interpolator = DEACCEL;
         final boolean goingToNewTask;
         if (mRecentsView != null) {
-            final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
-            final int taskToLaunch = mRecentsView.getNextPage();
-            goingToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex;
+            if (!mRecentsAnimationWrapper.hasTargets()) {
+                // If there are no running tasks, then we can assume that this is a continuation of
+                // the last gesture, but after the recents animation has finished
+                goingToNewTask = true;
+            } else {
+                final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
+                final int taskToLaunch = mRecentsView.getNextPage();
+                goingToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex;
+            }
         } else {
             goingToNewTask = false;
         }
@@ -1124,14 +1128,22 @@
             mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false /* animate */,
                     true /* freezeTaskList */);
         } else {
+            int taskId = mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).getTask().key.id;
+            mFinishingRecentsAnimationForNewTaskId = taskId;
             mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
-                mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(
-                        false /* animate */, true /* freezeTaskList */);
+                if (!mCanceled) {
+                    TaskView nextTask = mRecentsView.getTaskView(taskId);
+                    if (nextTask != null) {
+                        nextTask.launchTask(false /* animate */, true /* freezeTaskList */);
+                        doLogGesture(NEW_TASK);
+                    }
+                    reset();
+                }
+                mCanceled = false;
+                mFinishingRecentsAnimationForNewTaskId = -1;
             });
         }
         TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", true);
-        doLogGesture(NEW_TASK);
-        reset();
     }
 
     public void reset() {
@@ -1142,12 +1154,26 @@
      * Cancels any running animation so that the active target can be overriden by a new swipe
      * handle (in case of quick switch).
      */
-    public void cancelCurrentAnimation() {
+    public void cancelCurrentAnimation(SwipeSharedState sharedState) {
+        mCanceled = true;
         mCurrentShift.cancelAnimation();
         if (mLauncherTransitionController != null && mLauncherTransitionController
                 .getAnimationPlayer().isStarted()) {
             mLauncherTransitionController.getAnimationPlayer().cancel();
         }
+
+        if (mFinishingRecentsAnimationForNewTaskId != -1) {
+            // If we are canceling mid-starting a new task, switch to the screenshot since the
+            // recents animation has finished
+            switchToScreenshot();
+            TaskView newRunningTaskView = mRecentsView.getTaskView(
+                    mFinishingRecentsAnimationForNewTaskId);
+            int newRunningTaskId = newRunningTaskView != null
+                    ? newRunningTaskView.getTask().key.id
+                    : -1;
+            mRecentsView.setCurrentTask(newRunningTaskId);
+            sharedState.setRecentsAnimationFinishInterrupted(newRunningTaskId);
+        }
     }
 
     private void invalidateHandler() {
@@ -1169,11 +1195,7 @@
             mLauncherTransitionController = null;
         }
 
-        mRecentsView.setEnableFreeScroll(true);
-        mRecentsView.setRunningTaskIconScaledDown(false);
-        mRecentsView.setOnScrollChangeListener(null);
-        mRecentsView.setRunningTaskHidden(false);
-        mRecentsView.setEnableDrawingLiveTile(true);
+        mRecentsView.onGestureAnimationEnd();
 
         mActivity.getRootView().setOnApplyWindowInsetsListener(null);
         mActivity.getRootView().getOverlay().remove(mLiveTileOverlay);
@@ -1194,6 +1216,9 @@
     private void switchToScreenshot() {
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
+        } else if (!mRecentsAnimationWrapper.hasTargets()) {
+            // If there are no targets, then we don't need to capture anything
+            setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
         } else {
             boolean finishTransitionPosted = false;
             SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController();
@@ -1241,6 +1266,9 @@
     private void finishCurrentTransitionToRecents() {
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
+        } else if (!mRecentsAnimationWrapper.hasTargets()) {
+            // If there are no targets, then there is nothing to finish
+            setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
         } else {
             synchronized (mRecentsAnimationWrapper) {
                 mRecentsAnimationWrapper.finish(true /* toRecents */,
@@ -1267,10 +1295,7 @@
         }
         mActivityControlHelper.onSwipeUpComplete(mActivity);
         mRecentsAnimationWrapper.setCancelWithDeferredScreenshot(true);
-
-        // Animate the first icon.
-        mRecentsView.animateUpRunningTaskIconScale(mLiveTileOverlay.cancelIconAnimation());
-        mRecentsView.setSwipeDownShouldLaunchApp(true);
+        mRecentsView.onSwipeUpAnimationSuccess();
 
         RecentsModel.INSTANCE.get(mContext).onOverviewShown(false, TAG);
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
index 83973fa..f5a9e8a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
@@ -53,6 +53,20 @@
         this.mOnFinishListener = onFinishListener;
     }
 
+    public boolean hasTargets() {
+        return unfilteredApps.length != 0;
+    }
+
+    /**
+     * Clones the target set without any actual targets. Used only when continuing a gesture after
+     * the actual recents animation has finished.
+     */
+    public SwipeAnimationTargetSet cloneWithoutTargets() {
+        return new SwipeAnimationTargetSet(controller, new RemoteAnimationTargetCompat[0],
+                homeContentInsets, minimizedHomeBounds, mShouldMinimizeSplitScreen,
+                mOnFinishListener);
+    }
+
     public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) {
         mOnFinishListener.accept(this);
         BACKGROUND_EXECUTOR.execute(() -> {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index b5f90a5..525ead8 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -744,9 +744,7 @@
     public abstract void startHome();
 
     public void reset() {
-        setRunningTaskViewShowScreenshot(false);
-        mRunningTaskId = -1;
-        mRunningTaskTileHidden = false;
+        setCurrentTask(-1);
         mIgnoreResetTaskId = -1;
         mTaskListChangeId = -1;
 
@@ -757,6 +755,15 @@
         setCurrentPage(0);
     }
 
+    public @Nullable TaskView getRunningTaskView() {
+        return getTaskView(mRunningTaskId);
+    }
+
+    public int getRunningTaskIndex() {
+        TaskView tv = getRunningTaskView();
+        return tv == null ? -1 : indexOfChild(tv);
+    }
+
     /**
      * Reloads the view if anything in recents changed.
      */
@@ -767,14 +774,50 @@
     }
 
     /**
-     * Ensures that the first task in the view represents {@param task} and reloads the view
-     * if needed. This allows the swipe-up gesture to assume that the first tile always
-     * corresponds to the correct task.
-     * All subsequent calls to reload will keep the task as the first item until {@link #reset()}
-     * is called.
-     * Also scrolls the view to this task
+     * Called when a gesture from an app is starting.
      */
-    public void showTask(int runningTaskId) {
+    public void onGestureAnimationStart(int runningTaskId) {
+        // This needs to be called before the other states are set since it can create the task view
+        showCurrentTask(runningTaskId);
+        setEnableFreeScroll(false);
+        setEnableDrawingLiveTile(false);
+        setRunningTaskHidden(true);
+        setRunningTaskIconScaledDown(true);
+    }
+
+    /**
+     * Called only when a swipe-up gesture from an app has completed. Only called after
+     * {@link #onGestureAnimationStart} and {@link #onGestureAnimationEnd()}.
+     */
+    public void onSwipeUpAnimationSuccess() {
+        if (getRunningTaskView() != null) {
+            float startProgress = ENABLE_QUICKSTEP_LIVE_TILE.get()
+                    ? mLiveTileOverlay.cancelIconAnimation()
+                    : 0f;
+            animateUpRunningTaskIconScale(startProgress);
+        }
+        setSwipeDownShouldLaunchApp(true);
+    }
+
+    /**
+     * Called when a gesture from an app has finished.
+     */
+    public void onGestureAnimationEnd() {
+        setEnableFreeScroll(true);
+        setEnableDrawingLiveTile(true);
+        setOnScrollChangeListener(null);
+        setRunningTaskViewShowScreenshot(true);
+        setRunningTaskHidden(false);
+        animateUpRunningTaskIconScale();
+    }
+
+    /**
+     * Creates a task view (if necessary) to represent the task with the {@param runningTaskId}.
+     *
+     * All subsequent calls to reload will keep the task as the first item until {@link #reset()}
+     * is called.  Also scrolls the view to this task.
+     */
+    public void showCurrentTask(int runningTaskId) {
         if (getChildCount() == 0) {
             // Add an empty view for now until the task plan is loaded and applied
             final TaskView taskView = mTaskViewPool.getView();
@@ -789,16 +832,33 @@
                     new ComponentName("", ""), false);
             taskView.bind(mTmpRunningTask);
         }
+
+        boolean runningTaskTileHidden = mRunningTaskTileHidden;
         setCurrentTask(runningTaskId);
+        setCurrentPage(getRunningTaskIndex());
+        setRunningTaskViewShowScreenshot(false);
+        setRunningTaskHidden(runningTaskTileHidden);
+
+        // Reload the task list
+        mTaskListChangeId = mModel.getTasks(this::applyLoadPlan);
     }
 
-    public @Nullable TaskView getRunningTaskView() {
-        return getTaskView(mRunningTaskId);
-    }
+    /**
+     * Sets the running task id, cleaning up the old running task if necessary.
+     * @param runningTaskId
+     */
+    public void setCurrentTask(int runningTaskId) {
+        if (mRunningTaskId == runningTaskId) {
+            return;
+        }
 
-    public int getRunningTaskIndex() {
-        TaskView tv = getRunningTaskView();
-        return tv == null ? -1 : indexOfChild(tv);
+        if (mRunningTaskId != -1) {
+            // Reset the state on the old running task view
+            setRunningTaskIconScaledDown(false);
+            setRunningTaskViewShowScreenshot(true);
+            setRunningTaskHidden(false);
+        }
+        mRunningTaskId = runningTaskId;
     }
 
     /**
@@ -812,27 +872,6 @@
         }
     }
 
-    /**
-     * Similar to {@link #showTask(int)} but does not put any restrictions on the first tile.
-     */
-    public void setCurrentTask(int runningTaskId) {
-        boolean runningTaskTileHidden = mRunningTaskTileHidden;
-        boolean runningTaskIconScaledDown = mRunningTaskIconScaledDown;
-
-        setRunningTaskIconScaledDown(false);
-        setRunningTaskHidden(false);
-        setRunningTaskViewShowScreenshot(true);
-        mRunningTaskId = runningTaskId;
-        setRunningTaskViewShowScreenshot(false);
-        setRunningTaskIconScaledDown(runningTaskIconScaledDown);
-        setRunningTaskHidden(runningTaskTileHidden);
-
-        setCurrentPage(getRunningTaskIndex());
-
-        // Load the tasks (if the loading is already
-        mTaskListChangeId = mModel.getTasks(this::applyLoadPlan);
-    }
-
     private void setRunningTaskViewShowScreenshot(boolean showScreenshot) {
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             TaskView runningTaskView = getRunningTaskView();
@@ -1520,7 +1559,9 @@
     public abstract boolean shouldUseMultiWindowTaskSizeStrategy();
 
     protected void onTaskLaunched(boolean success) {
-        resetTaskVisuals();
+        if (success) {
+            resetTaskVisuals();
+        }
     }
 
     @Override
diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml
new file mode 100644
index 0000000..82b0b8d
--- /dev/null
+++ b/res/layout/hotseat.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<com.android.launcher3.Hotseat
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/hotseat"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:theme="@style/HomeScreenElementTheme"
+    android:importantForAccessibility="no"
+    launcher:containerType="hotseat" />
\ No newline at end of file
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 6ecc1f5..cca899b 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -39,13 +39,9 @@
             launcher:pageIndicator="@+id/page_indicator" />
 
         <!-- DO NOT CHANGE THE ID -->
-        <com.android.launcher3.Hotseat
+        <include
             android:id="@+id/hotseat"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:theme="@style/HomeScreenElementTheme"
-            android:importantForAccessibility="no"
-            launcher:containerType="hotseat" />
+            layout="@layout/hotseat" />
 
         <include
             android:id="@+id/overview_panel"
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index b640430..80e17c9 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1072,6 +1072,10 @@
 
 
     public void setEnableFreeScroll(boolean freeScroll) {
+        if (mFreeScroll == freeScroll) {
+            return;
+        }
+
         boolean wasFreeScroll = mFreeScroll;
         mFreeScroll = freeScroll;
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index f5c5a8d..87ef044 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -374,16 +374,6 @@
                     event -> true,
                     "Pressing Home didn't produce any events");
             mDevice.waitForIdle();
-
-            // Temporarily press home twice as the first click sometimes gets ignored  (b/124239413)
-            executeAndWaitForEvent(
-                    () -> {
-                        log("LauncherInstrumentation.pressHome before clicking");
-                        waitForSystemUiObject("home").click();
-                    },
-                    event -> true,
-                    "Pressing Home didn't produce any events");
-            mDevice.waitForIdle();
         }
         try (LauncherInstrumentation.Closable c = addContextLayer(
                 "performed action to switch to Home - " + action)) {