Merge "Enable FileLog for release devices" into ub-launcher3-qt-future-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 50cfac8..468b8af 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -19,7 +19,6 @@
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.quickstep.util.LayoutUtils;
@@ -69,8 +68,16 @@
         if (taskCount == 0) {
             return super.getOverviewScaleAndTranslation(launcher);
         }
-        TaskView dummyTask = recentsView.getTaskViewAt(Utilities.boundToRange(
-                recentsView.getCurrentPage(), 0, taskCount - 1));
+        TaskView dummyTask;
+        if (recentsView.getCurrentPage() >= 0) {
+            if (recentsView.getCurrentPage() <= taskCount - 1) {
+                dummyTask = recentsView.getCurrentPageTaskView();
+            } else {
+                dummyTask = recentsView.getTaskViewAt(taskCount - 1);
+            }
+        } else {
+            dummyTask = recentsView.getTaskViewAt(0);
+        }
         return recentsView.getTempClipAnimationHelper().updateForFullscreenOverview(dummyTask)
                 .getScaleAndTranslation();
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
index 20a2487..03862db 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
@@ -47,9 +47,9 @@
      * @return true if we should intercept the motion event
      */
     boolean canInterceptTouch(MotionEvent ev) {
-        if (mRecentsView.getChildCount() > 0) {
+        if (mRecentsView.getTaskViewCount() > 0) {
             // Allow swiping up in the gap between the hotseat and overview.
-            return ev.getY() >= mRecentsView.getChildAt(0).getBottom();
+            return ev.getY() >= mRecentsView.getTaskViewAt(0).getBottom();
         } else {
             // If there are no tasks, we only intercept if we're below the hotseat height.
             return isTouchOverHotseat(mLauncher, ev);
@@ -63,7 +63,7 @@
      * @return true if going back should take the user to the currently running task
      */
     boolean shouldSwipeDownReturnToApp() {
-        TaskView taskView = mRecentsView.getTaskViewAt(mRecentsView.getNextPage());
+        TaskView taskView = mRecentsView.getNextPageTaskView();
         return taskView != null && mRecentsView.shouldSwipeDownLaunchApp();
     }
 
@@ -76,7 +76,7 @@
      */
     PendingAnimation createSwipeDownToTaskAppAnimation(long duration) {
         mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen());
-        TaskView taskView = mRecentsView.getTaskViewAt(mRecentsView.getCurrentPage());
+        TaskView taskView = mRecentsView.getCurrentPageTaskView();
         if (taskView == null) {
             throw new IllegalStateException("There is no task view to animate to.");
         }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index eb571f6..6576ec5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -50,7 +50,6 @@
 import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
-import com.android.systemui.shared.system.QuickStepContract;
 
 /**
  * Handles quick switching to a recent task from the home screen.
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 676ea69..7196f7c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -227,10 +227,10 @@
         // Launch the task user scrolled to (mRecentsView.getNextPage()).
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             // We finish recents animation inside launchTask() when live tile is enabled.
-            mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false /* animate */,
+            mRecentsView.getNextPageTaskView().launchTask(false /* animate */,
                     true /* freezeTaskList */);
         } else {
-            int taskId = mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).getTask().key.id;
+            int taskId = mRecentsView.getNextPageTaskView().getTask().key.id;
             mFinishingRecentsAnimationForNewTaskId = taskId;
             mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
                 if (!mCanceled) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 25cc33d..c17b2fe 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -268,7 +268,7 @@
                         INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
 
                 int runningTaskIndex = recentsView.getRunningTaskIndex();
-                if (runningTaskIndex == 0) {
+                if (runningTaskIndex == recentsView.getTaskViewStartIndex()) {
                     // If we are on the first task (we haven't quick switched), translate recents in
                     // from the side. Calculate the start translation based on current scale/scroll.
                     float currScale = recentsView.getScaleX();
@@ -351,8 +351,7 @@
     private void playScaleDownAnim(AnimatorSet anim, Launcher launcher, LauncherState fromState,
             LauncherState endState) {
         RecentsView recentsView = launcher.getOverviewPanel();
-        TaskView v = recentsView.getTaskViewAt(recentsView.getCurrentPage());
-        if (v == null) {
+        if (recentsView.getCurrentPageTaskView() == null) {
             return;
         }
 
@@ -380,7 +379,7 @@
             // recents as a whole needs to translate further to keep up with the app window.
             TaskView runningTaskView = recentsView.getRunningTaskView();
             if (runningTaskView == null) {
-                runningTaskView = recentsView.getTaskViewAt(recentsView.getCurrentPage());
+                runningTaskView = recentsView.getCurrentPageTaskView();
             }
             TimeInterpolator oldInterpolator = translateY.getInterpolator();
             Rect fallbackInsets = launcher.getDeviceProfile().getInsets();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
index c18b604..79273ea 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
@@ -109,7 +109,7 @@
                 TaskView taskView = rv.getNextTaskView();
                 if (taskView == null) {
                     if (rv.getTaskViewCount() > 0) {
-                        taskView = (TaskView) rv.getPageAt(0);
+                        taskView = rv.getTaskViewAt(0);
                         taskView.requestFocus();
                     } else {
                         rv.requestFocus();
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 a3bd348..411a808 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -479,8 +479,8 @@
             recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask;
             if (animate) {
                 // Only animate if an adjacent task view is visible on screen.
-                TaskView adjacentTask1 = mRecentsView.getTaskViewAt(runningTaskIndex + 1);
-                TaskView adjacentTask2 = mRecentsView.getTaskViewAt(runningTaskIndex - 1);
+                TaskView adjacentTask1 = mRecentsView.getNextTaskView();
+                TaskView adjacentTask2 = mRecentsView.getPreviousTaskView();
                 float prevTranslationX = mRecentsView.getTranslationX();
                 mRecentsView.setTranslationX(0);
                 animate = (adjacentTask1 != null && adjacentTask1.getGlobalVisibleRect(TEMP_RECT))
@@ -590,8 +590,7 @@
      */
     private void updateSysUiFlags(float windowProgress) {
         if (mRecentsView != null) {
-            TaskView centermostTask = mRecentsView.getTaskViewAt(mRecentsView
-                    .getPageNearestToCenterOfScreen());
+            TaskView centermostTask = mRecentsView.getTaskViewNearestToCenterOfScreen();
             int centermostTaskFlags = centermostTask == null ? 0
                     : centermostTask.getThumbnail().getSysUiStatusNavFlags();
             boolean useHomeScreenFlags = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 2e9c0a3..7f1aae5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -176,7 +176,7 @@
     protected void applyLoadPlan(ArrayList<Task> tasks) {
         // When quick-switching on 3p-launcher, we add a "dummy" tile corresponding to Launcher
         // as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
-        // track the index of the next task appropriately, as it we are switching on any other app.
+        // track the index of the next task appropriately, as if we are switching on any other app.
         if (mRunningTaskInfo != null && mRunningTaskInfo.taskId == mRunningTaskId) {
             // Check if the task list has running task
             boolean found = false;
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 9464bd1..804d1e0 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
@@ -306,6 +306,9 @@
     private Layout mEmptyTextLayout;
     private LiveTileOverlay mLiveTileOverlay;
 
+    // Keeps track of the index where the first TaskView should be
+    private int mTaskViewStartIndex = 0;
+
     private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
             (inMultiWindowMode) -> {
         if (!inMultiWindowMode && mOverviewStateEnabled) {
@@ -329,7 +332,6 @@
         mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
                 .inflate(R.layout.overview_clear_all_button, this, false);
         mClearAllButton.setOnClickListener(this::dismissAllTasks);
-
         mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
                 10 /* initial size */);
 
@@ -430,7 +432,7 @@
         super.onViewRemoved(child);
 
         // Clear the task data for the removed child if it was visible
-        if (child != mClearAllButton) {
+        if (child instanceof TaskView) {
             TaskView taskView = (TaskView) child;
             mHasVisibleTaskData.delete(taskView.getTask().key.id);
             mTaskViewPool.recycle(taskView);
@@ -444,7 +446,7 @@
 
     public TaskView getTaskView(int taskId) {
         for (int i = 0; i < getTaskViewCount(); i++) {
-            TaskView tv = (TaskView) getChildAt(i);
+            TaskView tv = getTaskViewAt(i);
             if (tv.getTask() != null && tv.getTask().key != null && tv.getTask().key.id == taskId) {
                 return tv;
             }
@@ -536,28 +538,26 @@
         }
 
         if (tasks == null || tasks.isEmpty()) {
-            removeAllViews();
+            removeTasksViewsAndClearAllButton();
             onTaskStackUpdated();
             return;
         }
 
-        int oldChildCount = getChildCount();
-
         // Unload existing visible task data
         unloadVisibleTaskData();
 
-        TaskView ignoreRestTaskView =
+        TaskView ignoreResetTaskView =
                 mIgnoreResetTaskId == -1 ? null : getTaskView(mIgnoreResetTaskId);
 
         final int requiredTaskCount = tasks.size();
         if (getTaskViewCount() != requiredTaskCount) {
-            if (oldChildCount > 0) {
+            if (indexOfChild(mClearAllButton) != -1) {
                 removeView(mClearAllButton);
             }
-            for (int i = getChildCount(); i < requiredTaskCount; i++) {
+            for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
                 addView(mTaskViewPool.getView());
             }
-            while (getChildCount() > requiredTaskCount) {
+            while (getTaskViewCount() > requiredTaskCount) {
                 removeView(getChildAt(getChildCount() - 1));
             }
             if (requiredTaskCount > 0) {
@@ -567,17 +567,20 @@
 
         // Rebind and reset all task views
         for (int i = requiredTaskCount - 1; i >= 0; i--) {
-            final int pageIndex = requiredTaskCount - i - 1;
+            final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
             final Task task = tasks.get(i);
             final TaskView taskView = (TaskView) getChildAt(pageIndex);
             taskView.bind(task);
         }
+
         TaskView runningTaskView = getRunningTaskView();
         if (runningTaskView != null) {
             setCurrentPage(indexOfChild(runningTaskView));
+        } else if (getTaskViewCount() > 0) {
+            setCurrentPage(indexOfChild(getTaskViewAt(0)));
         }
 
-        if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreRestTaskView) {
+        if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreResetTaskView) {
             // If the taskView mapping is changing, do not preserve the visuals. Since we are
             // mostly preserving the first task, and new taskViews are added to the end, it should
             // generally map to the same task.
@@ -588,17 +591,28 @@
         updateEnabledOverlays();
     }
 
+    private void removeTasksViewsAndClearAllButton() {
+        for (int i = getTaskViewCount() - 1; i >= 0; i--) {
+            removeView(getTaskViewAt(i));
+        }
+        if (indexOfChild(mClearAllButton) != -1) {
+            removeView(mClearAllButton);
+        }
+    }
+
     public int getTaskViewCount() {
-        // Account for the clear all button.
-        int childCount = getChildCount();
-        return childCount == 0 ? 0 : childCount - 1;
+        int taskViewCount = getChildCount() - mTaskViewStartIndex;
+        if (indexOfChild(mClearAllButton) != -1) {
+            taskViewCount--;
+        }
+        return taskViewCount;
     }
 
     protected void onTaskStackUpdated() { }
 
     public void resetTaskVisuals() {
         for (int i = getTaskViewCount() - 1; i >= 0; i--) {
-            TaskView taskView = (TaskView) getChildAt(i);
+            TaskView taskView = getTaskViewAt(i);
             if (mIgnoreResetTaskId != taskView.getTask().key.id) {
                 taskView.resetVisualProperties();
                 taskView.setStableAlpha(mContentAlpha);
@@ -704,7 +718,7 @@
     }
 
     /**
-     * Iterates through all thet asks, and loads the associated task data for newly visible tasks,
+     * Iterates through all the tasks, and loads the associated task data for newly visible tasks,
      * and unloads the associated task data for tasks that are no longer visible.
      */
     public void loadVisibleTaskData() {
@@ -715,15 +729,16 @@
         }
 
         int centerPageIndex = getPageNearestToCenterOfScreen();
-        int numChildren = getTaskViewCount();
+        int numChildren = getChildCount();
         int lower = Math.max(0, centerPageIndex - 2);
         int upper = Math.min(centerPageIndex + 2, numChildren - 1);
 
         // Update the task data for the in/visible children
-        for (int i = 0; i < numChildren; i++) {
-            TaskView taskView = (TaskView) getChildAt(i);
+        for (int i = 0; i < getTaskViewCount(); i++) {
+            TaskView taskView = getTaskViewAt(i);
             Task task = taskView.getTask();
-            boolean visible = lower <= i && i <= upper;
+            int index = indexOfChild(taskView);
+            boolean visible = lower <= index && index <= upper;
             if (visible) {
                 if (task == mTmpRunningTask) {
                     // Skip loading if this is the task that we are animating into
@@ -798,6 +813,10 @@
         return tv == null ? -1 : indexOfChild(tv);
     }
 
+    public int getTaskViewStartIndex() {
+        return mTaskViewStartIndex;
+    }
+
     /**
      * Reloads the view if anything in recents changed.
      */
@@ -853,10 +872,10 @@
      */
     public void showCurrentTask(int runningTaskId) {
         if (getTaskView(runningTaskId) == null) {
-            boolean wasEmpty = getChildCount() == 0;
+            boolean wasEmpty = getTaskViewCount() == 0;
             // Add an empty view for now until the task plan is loaded and applied
             final TaskView taskView = mTaskViewPool.getView();
-            addView(taskView, 0);
+            addView(taskView, mTaskViewStartIndex);
             if (wasEmpty) {
                 addView(mClearAllButton);
             }
@@ -922,14 +941,13 @@
         if (runningTaskView == null) {
             // Launch the first task
             if (getTaskViewCount() > 0) {
-                getTaskViewAt(0).launchTask(true /* animate */);
+                getTaskViewAt(0).launchTask(true);
             }
         } else {
-            TaskView nextTaskView = getNextTaskView();
-            if (nextTaskView != null) {
-                nextTaskView.launchTask(true /* animate */);
+            if (getNextTaskView() != null) {
+                getNextTaskView().launchTask(true);
             } else {
-                runningTaskView.launchTask(true /* animate */);
+                runningTaskView.launchTask(true);
             }
         }
     }
@@ -1189,7 +1207,7 @@
 
         int count = getTaskViewCount();
         for (int i = 0; i < count; i++) {
-            addDismissedTaskAnimations(getChildAt(i), anim, duration);
+            addDismissedTaskAnimations(getTaskViewAt(i), anim, duration);
         }
 
         mPendingAnimation = pendingAnimation;
@@ -1197,7 +1215,7 @@
             if (onEndListener.isSuccess) {
                 // Remove all the task views now
                 ActivityManagerWrapper.getInstance().removeAllRecentTasks();
-                removeAllViews();
+                removeTasksViewsAndClearAllButton();
                 startHome();
             }
             mPendingAnimation = null;
@@ -1344,26 +1362,50 @@
         child.setAlpha(mContentAlpha);
     }
 
-    /**
-     * @return The most recent task that is older than the currently running task. If there is
-     * currently no running task or there is no task older than it, then return null.
-     */
     @Nullable
     public TaskView getNextTaskView() {
-        TaskView runningTaskView = getRunningTaskView();
-        if (runningTaskView == null) {
-            return null;
-        }
-        return getTaskViewAt(indexOfChild(runningTaskView) + 1);
+        return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() + 1);
     }
 
+    @Nullable
+    public TaskView getPreviousTaskView() {
+        return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() - 1);
+    }
+
+    @Nullable
+    public TaskView getCurrentPageTaskView() {
+        return getTaskViewAtByAbsoluteIndex(getCurrentPage());
+    }
+
+    @Nullable
+    public TaskView getNextPageTaskView() {
+        return getTaskViewAtByAbsoluteIndex(getNextPage());
+    }
+
+    @Nullable
+    public TaskView getTaskViewNearestToCenterOfScreen() {
+        return getTaskViewAtByAbsoluteIndex(getPageNearestToCenterOfScreen());
+    }
+
+    /**
+     * Returns null instead of indexOutOfBoundsError when index is not in range
+     */
+    @Nullable
     public TaskView getTaskViewAt(int index) {
-        View child = getChildAt(index);
-        return child == mClearAllButton ? null : (TaskView) child;
+        return getTaskViewAtByAbsoluteIndex(index + mTaskViewStartIndex);
+    }
+
+    @Nullable
+    private TaskView getTaskViewAtByAbsoluteIndex(int index) {
+        if (index < getChildCount() && index >= 0) {
+            View child = getChildAt(index);
+            return child instanceof TaskView ? (TaskView) child : null;
+        }
+        return null;
     }
 
     public void updateEmptyMessage() {
-        boolean isEmpty = getChildCount() == 0;
+        boolean isEmpty = getTaskViewCount() == 0;
         boolean hasSizeChanged = mLastMeasureSize.x != getWidth()
                 || mLastMeasureSize.y != getHeight();
         if (isEmpty == mShowEmptyMessage && !hasSizeChanged) {
@@ -1497,7 +1539,7 @@
             throw new IllegalStateException("Another pending animation is still running");
         }
 
-        int count = getChildCount();
+        int count = getTaskViewCount();
         if (count == 0) {
             return new PendingAnimation(new AnimatorSet());
         }
@@ -1670,18 +1712,38 @@
 
     @Override
     protected int computeMinScrollX() {
-        if (mIsRtl && mDisallowScrollToClearAll) {
-            // We aren't showing the clear all button, so use the leftmost task as the min scroll.
-            return getScrollForPage(getTaskViewCount() - 1);
+        if (getTaskViewCount() > 0) {
+            if (mDisallowScrollToClearAll) {
+                // We aren't showing the clear all button,
+                // so use the leftmost task as the min scroll.
+                if (mIsRtl) {
+                    return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
+                }
+                return getScrollForPage(mTaskViewStartIndex);
+            }
+            if (mIsRtl) {
+                return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
+            }
+            return getScrollForPage(mTaskViewStartIndex);
         }
         return super.computeMinScrollX();
     }
 
     @Override
     protected int computeMaxScrollX() {
-        if (!mIsRtl && mDisallowScrollToClearAll) {
-            // We aren't showing the clear all button, so use the rightmost task as the max scroll.
-            return getScrollForPage(getTaskViewCount() - 1);
+        if (getTaskViewCount() > 0) {
+            if (mDisallowScrollToClearAll) {
+                // We aren't showing the clear all button,
+                // so use the rightmost task as the min scroll.
+                if (mIsRtl) {
+                    return getScrollForPage(mTaskViewStartIndex);
+                }
+                return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
+            }
+            if (mIsRtl) {
+                return getScrollForPage(mTaskViewStartIndex);
+            }
+            return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
         }
         return super.computeMaxScrollX();
     }
@@ -1733,7 +1795,7 @@
         int overlayEnabledPage = mOverlayEnabled ? getNextPage() : -1;
         int taskCount = getTaskViewCount();
         for (int i = 0; i < taskCount; i++) {
-            ((TaskView) getChildAt(i)).setOverlayEnabled(i == overlayEnabledPage);
+            getTaskViewAt(i).setOverlayEnabled(i == overlayEnabledPage);
         }
     }
 
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index d942e9e..0396df6 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"ስራ"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"መተግበሪያ አልተጫነም።"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"መተግበሪያ አይገኝም"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 5528a19..7c1ce84 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"İş"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Tətbiq quraşdırılmayıb."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Tətbiq əlçatmazdır"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 5650457..65ad91e 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Posao"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikacija nije instalirana."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikacija nije dostupna"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 50f92da..4ef9ec3 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Feina"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"L\'aplicació no s\'ha instal·lat."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"L\'aplicació no està disponible."</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 2363e61..d80e905 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Εργασία"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Η εφαρμογή δεν έχει εγκατασταθεί."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Η εφαρμογή δεν είναι διαθέσιμη"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 0c48b5d..7adc218 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"App isn\'t installed."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"App isn\'t available"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 0c48b5d..7adc218 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"App isn\'t installed."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"App isn\'t available"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 0c48b5d..7adc218 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"App isn\'t installed."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"App isn\'t available"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 9ba46c1..10aebe7 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Lana"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikazioa instalatu gabe dago."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Ez dago erabilgarri aplikazioa"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 7b4bcb1..65db47e 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Android Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"L\'application n\'est pas installée."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Application indisponible"</string>
@@ -136,7 +135,7 @@
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Retrouvez ici vos applications professionnelles"</string>
     <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Les applications professionnelles sont accompagnées d\'un badge et sont sécurisées par votre organisation. Vous pouvez les déplacer vers votre écran d\'accueil pour y accéder plus facilement."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Géré par votre organisation"</string>
-    <string name="work_mode_off_label" msgid="3194894777601421047">"Les notifications et les applications sont désactivées"</string>
+    <string name="work_mode_off_label" msgid="3194894777601421047">"Notifications et applications désactivées"</string>
     <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Fermer"</string>
     <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Fermé"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index e115a72..ca5ba3c 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Traballo"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"A aplicación non está instalada"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"A aplicación non está dispoñible"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 7def3ac..3228dea 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"કાર્યાલય"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"ઍપ્લિકેશન ઇન્સ્ટોલ થઈ નથી."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"ઍપ્લિકેશન ઉપલબ્ધ નથી"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 1caa27f..b738bc0 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Posao"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikacija nije instalirana."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikacija nije dostupna"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 211f735..92c7acc 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Kantor"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikasi tidak dipasang."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikasi tidak tersedia"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 14c8300..67ea6a8 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"ಕೆಲಸ"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"ಅಪ್ಲಿಕೇಶನ್ ಲಭ್ಯವಿಲ್ಲ"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 9550a5f..ab14e89 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Стартер3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Работа"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Апликацијата не е инсталирана."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Апликацијата не е достапна"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index fd1f7d9..78856f6 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"ဖွင့်တင်စက်၃"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"အလုပ်"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"အက်ပ်မထည့်သွင်းထားပါ"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"အက်ပ်လက်လှမ်း မမှီပါ"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index e88ff18..bb4834f 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Tela de início 3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Trabalho"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"O app não está instalado."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"O app não está disponível"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 1251d7e..f8a61f1 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplicația nu este instalată."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplicația nu este disponibilă"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 340a128..5bbf7c3 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Pracovné"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikácia nie je nainštalovaná."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikácia nie je k dispozícii"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 6f33c4f..445e382 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Kazini"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Programu haijasakinishwa."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Programu haipatikani"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index c926bc1..6e933a1 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"பணியிடம்"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"ஆப்ஸ் நிறுவப்படவில்லை."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"ஆப்ஸ் இல்லை"</string>
@@ -36,7 +35,7 @@
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"நீங்களே சேர்க்க, தொட்டுப் பிடித்திருக்கவும்"</string>
     <string name="place_automatically" msgid="8064208734425456485">"தானாகவே சேர்"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"பயன்பாடுகளில் தேடுக"</string>
-    <string name="all_apps_loading_message" msgid="5813968043155271636">"பயன்பாடுகளை ஏற்றுகிறது…"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"ஆப்ஸை ஏற்றுகிறது…"</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"கூடுதல் பயன்பாடுகளைத் தேடு"</string>
     <string name="label_application" msgid="8531721983832654978">"ஆப்ஸ்"</string>
@@ -45,7 +44,7 @@
     <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ஷார்ட்கட்டைச் சேர்க்க, இருமுறை தட்டிப் பிடித்திருக்கவும் (அ) தனிப்பயன் செயல்களைப் பயன்படுத்தவும்."</string>
     <string name="out_of_space" msgid="4691004494942118364">"முகப்புத் திரையில் இடமில்லை."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"பிடித்தவை ட்ரேயில் இடமில்லை"</string>
-    <string name="all_apps_button_label" msgid="8130441508702294465">"பயன்பாடுகளின் பட்டியல்"</string>
+    <string name="all_apps_button_label" msgid="8130441508702294465">"ஆப்ஸின் பட்டியல்"</string>
     <string name="all_apps_button_personal_label" msgid="1315764287305224468">"தனிப்பட்ட ஆப்ஸ் பட்டியல்"</string>
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"பணி ஆப்ஸ் பட்டியல்"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"முகப்பு"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 03c02ad..5ab9b86 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"งาน"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"ไม่ได้ติดตั้งแอป"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"แอปไม่พร้อมใช้งาน"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 83178fe..b937764 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -20,7 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Isiqalisi3"</string>
-    <string name="folder_name" msgid="7371454440695724752"></string>
     <string name="work_folder_name" msgid="3753320833950115786">"Umsebenzi"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Uhlelo lokusebenza alufakiwe."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Uhlelo lokusebenza alutholakali"</string>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 61d05c1..2df4adc 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -332,8 +332,8 @@
         UiFactory.onCreate(this);
 
         mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
-
-        mAppWidgetHost = new LauncherAppWidgetHost(this);
+        mAppWidgetHost = new LauncherAppWidgetHost(this,
+                appWidgetId -> getWorkspace().removeWidget(appWidgetId));
         mAppWidgetHost.startListening();
 
         mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index ffdd6b7..80c5c3e 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -35,6 +35,7 @@
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 import java.util.ArrayList;
+import java.util.function.IntConsumer;
 
 
 /**
@@ -56,9 +57,17 @@
     private final Context mContext;
     private int mFlags = FLAG_RESUMED;
 
+    private IntConsumer mAppWidgetRemovedCallback = null;
+
     public LauncherAppWidgetHost(Context context) {
+        this(context, null);
+    }
+
+    public LauncherAppWidgetHost(Context context,
+            IntConsumer appWidgetRemovedCallback) {
         super(context, APPWIDGET_HOST_ID);
         mContext = context;
+        mAppWidgetRemovedCallback = appWidgetRemovedCallback;
     }
 
     @Override
@@ -211,7 +220,7 @@
                 }
                 view.setAppWidget(appWidgetId, appWidget);
                 view.switchToErrorView();
-                return  view;
+                return view;
             }
         }
     }
@@ -229,6 +238,15 @@
         info.initSpans(mContext);
     }
 
+    //TODO: make this override when SDK is updated
+    //@Override
+    protected void onAppWidgetRemoved(int appWidgetId) {
+        if (mAppWidgetRemovedCallback == null) {
+            return;
+        }
+        mAppWidgetRemovedCallback.accept(appWidgetId);
+    }
+
     @Override
     public void deleteAppWidgetId(int appWidgetId) {
         super.deleteAppWidgetId(appWidgetId);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 56a8966..f9201d0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2802,6 +2802,23 @@
     }
 
     /**
+     * Removed widget from workspace by appWidgetId
+     * @param appWidgetId
+     */
+    public void removeWidget(int appWidgetId) {
+        mapOverItems((info, view) -> {
+            if (info instanceof LauncherAppWidgetInfo) {
+                LauncherAppWidgetInfo appWidgetInfo = (LauncherAppWidgetInfo) info;
+                if (appWidgetInfo.appWidgetId == appWidgetId) {
+                    mLauncher.removeItem(view, appWidgetInfo, true);
+                    return true;
+                }
+            }
+            return false;
+        });
+    }
+
+    /**
      * Removes all folder listeners
      */
     public void removeFolderListeners() {
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 3145893..3912b44 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -720,7 +720,7 @@
      */
     @UiThread
     public static IconLoadResult fetchIcon(Launcher l, View v, ItemInfo info, boolean isOpening) {
-        IconLoadResult result = new IconLoadResult();
+        IconLoadResult result = new IconLoadResult(info);
         MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(() -> {
             RectF position = new RectF();
             getLocationBoundsForView(l, v, isOpening, position);
@@ -749,10 +749,13 @@
 
         // Get the drawable on the background thread
         boolean shouldLoadIcon = originalView.getTag() instanceof ItemInfo && hideOriginal;
-        view.mIconLoadResult = sIconLoadResult;
-        if (shouldLoadIcon && view.mIconLoadResult == null) {
-            view.mIconLoadResult = fetchIcon(launcher, originalView,
-                    (ItemInfo) originalView.getTag(), isOpening);
+        if (shouldLoadIcon) {
+            if (sIconLoadResult != null && sIconLoadResult.itemInfo == originalView.getTag()) {
+                view.mIconLoadResult = sIconLoadResult;
+            } else {
+                view.mIconLoadResult = fetchIcon(launcher, originalView,
+                        (ItemInfo) originalView.getTag(), isOpening);
+            }
         }
         sIconLoadResult = null;
 
@@ -894,10 +897,15 @@
     }
 
     private static class IconLoadResult {
+        final ItemInfo itemInfo;
         Drawable drawable;
         Drawable badge;
         int iconOffset;
         Runnable onIconLoaded;
         boolean isIconLoaded;
+
+        public IconLoadResult(ItemInfo itemInfo) {
+            this.itemInfo = itemInfo;
+        }
     }
 }