Merge "Adding support for LauncherAppWidgetHostView in CellLayout" into tm-dev
diff --git a/go/quickstep/src/com/android/launcher3/AppSharing.java b/go/quickstep/src/com/android/launcher3/AppSharing.java
index c287446..e717937 100644
--- a/go/quickstep/src/com/android/launcher3/AppSharing.java
+++ b/go/quickstep/src/com/android/launcher3/AppSharing.java
@@ -39,6 +39,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.views.ActivityContext;
 
 import java.io.File;
 
@@ -191,9 +192,14 @@
         }
 
         private void showCannotShareToast(Context context) {
+            ActivityContext activityContext = ActivityContext.lookupContext(context);
+            String blockedByMessage = activityContext.getStringCache() != null
+                    ? activityContext.getStringCache().disabledByAdminMessage
+                    : context.getString(R.string.blocked_by_policy);
+
             CharSequence text = (mSharingEnabledForUser)
                     ? context.getText(R.string.toast_p2p_app_not_shareable)
-                    : context.getText(R.string.blocked_by_policy);
+                    : blockedByMessage;
             int duration = Toast.LENGTH_SHORT;
             Toast.makeText(context, text, duration).show();
         }
diff --git a/quickstep/res/layout/taskbar_all_apps.xml b/quickstep/res/layout/taskbar_all_apps.xml
index 34d4b23..d402469 100644
--- a/quickstep/res/layout/taskbar_all_apps.xml
+++ b/quickstep/res/layout/taskbar_all_apps.xml
@@ -34,10 +34,6 @@
             android:visibility="gone" />
 
         <include
-            layout="@layout/search_results_rv_layout"
-            android:visibility="gone" />
-
-        <include
             layout="@layout/all_apps_rv_layout"
             android:visibility="gone" />
 
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index f4fb8fa..c58a42d 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -70,7 +70,7 @@
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Ferdig"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Ferdig"</string>
     <string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Innstillinger"</string>
-    <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Prøv igjen"</string>
+    <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Prøv på nytt"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bra!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Veiledning <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"Alt er klart!"</string>
diff --git a/quickstep/res/values-sw600dp-land/dimens.xml b/quickstep/res/values-sw600dp-land/dimens.xml
index 4e3c02c..2cd48d5 100644
--- a/quickstep/res/values-sw600dp-land/dimens.xml
+++ b/quickstep/res/values-sw600dp-land/dimens.xml
@@ -15,8 +15,7 @@
 */
 -->
 <resources>
-    <dimen name="overview_actions_top_margin_gesture">19.1dp</dimen>
-    <dimen name="overview_actions_bottom_margin_gesture">10dp</dimen>
+    <dimen name="overview_actions_top_margin">12dp</dimen>
     <dimen name="overview_grid_side_margin">52dp</dimen>
     <dimen name="overview_page_spacing">38dp</dimen>
 </resources>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
index 223a5e9..5153afa 100644
--- a/quickstep/res/values-sw600dp/dimens.xml
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -20,8 +20,6 @@
     <dimen name="overview_task_margin">12dp</dimen>
     <dimen name="overview_task_margin_grid">4dp</dimen>
     <dimen name="overview_actions_button_spacing">36dp</dimen>
-    <dimen name="overview_actions_top_margin_gesture">19.37dp</dimen>
-    <dimen name="overview_actions_bottom_margin_gesture">22dp</dimen>
     <dimen name="overview_grid_side_margin">60dp</dimen>
     <dimen name="overview_grid_row_spacing">36dp</dimen>
     <dimen name="overview_page_spacing">36dp</dimen>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 3f08cf3..4210052 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -35,13 +35,12 @@
     <dimen name="overview_task_margin">16dp</dimen>
     <dimen name="overview_task_margin_grid">0dp</dimen>
     <item name="overview_max_scale" format="float" type="dimen">0.7</item>
+    <item name="overview_modal_max_scale" format="float" type="dimen">1.1</item>
 
     <!-- Overrideable in overlay that provides the Overview Actions. -->
     <dimen name="overview_actions_height">48dp</dimen>
     <dimen name="overview_actions_button_spacing">32dp</dimen>
-    <dimen name="overview_actions_top_margin_gesture">28dp</dimen>
-    <dimen name="overview_actions_bottom_margin_gesture">28dp</dimen>
-    <dimen name="overview_actions_margin_three_button">8dp</dimen>
+    <dimen name="overview_actions_top_margin">24dp</dimen>
     <dimen name="overview_actions_horizontal_margin">16dp</dimen>
 
     <dimen name="overview_page_spacing">16dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index f80deeb..81b0dd2 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -109,6 +109,8 @@
     <string name="back_gesture_intro_title">Swipe to go back</string>
     <!-- Introduction subtitle for the Back gesture tutorial. [CHAR LIMIT=200] -->
     <string name="back_gesture_intro_subtitle">To go back to the last screen, swipe from the left or right edge to the middle of the screen.</string>
+    <!-- Introduction subtitle for the Back gesture tutorial that will be spoken by screen readers. [CHAR LIMIT=200] -->
+    <string name="back_gesture_spoken_intro_subtitle">To go back to the last screen, swipe with 2 fingers from the left or right edge to the middle of the screen.</string>
 
     <string name="home_gesture_feedback_swipe_too_far_from_edge">Make sure you swipe up from the bottom edge of the screen.</string>
     <!-- Feedback shown during interactive parts of Home gesture tutorial when the Overview gesture is detected. [CHAR LIMIT=100] -->
@@ -123,6 +125,8 @@
     <string name="home_gesture_intro_title">Swipe to go home</string>
     <!-- Introduction subtitle for the Home gesture tutorial. [CHAR LIMIT=100] -->
     <string name="home_gesture_intro_subtitle">Swipe up from the bottom of your screen. This gesture always takes you to the Home screen.</string>
+    <!-- Introduction subtitle for the Home gesture tutorial that will be spoken by screen readers. [CHAR LIMIT=100] -->
+    <string name="home_gesture_spoken_intro_subtitle">Swipe up with 2 fingers from the bottom of the screen. This gesture always takes you to the Home screen.</string>
 
     <!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is started too far from the edge. [CHAR LIMIT=100] -->
     <string name="overview_gesture_feedback_swipe_too_far_from_edge">Make sure you swipe up from the bottom edge of the screen.</string>
@@ -138,6 +142,8 @@
     <string name="overview_gesture_intro_title">Swipe to switch apps</string>
     <!-- Introduction subtitle for the Overview gesture tutorial. [CHAR LIMIT=100] -->
     <string name="overview_gesture_intro_subtitle">To switch between apps, swipe up from the bottom of your screen, hold, then release.</string>
+    <!-- Introduction subtitle for the Overview gesture tutorial that will be spoken by screen readers. [CHAR LIMIT=100] -->
+    <string name="overview_gesture_spoken_intro_subtitle">To switch between apps, swipe up with 2 fingers from the bottom of your screen, hold, then release.</string>
 
     <!-- Title shown during interactive part of Assistant gesture tutorial. [CHAR LIMIT=30] -->
     <string name="assistant_gesture_tutorial_playground_title" translatable="false">Tutorial: Assistant</string>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index fe24c4b..2239102 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -24,6 +24,9 @@
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE;
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
+import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX;
+import static com.android.launcher3.taskbar.LauncherTaskbarUIController.MINUS_ONE_PAGE_PROGRESS_INDEX;
+import static com.android.launcher3.taskbar.LauncherTaskbarUIController.WIDGETS_PAGE_PROGRESS_INDEX;
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.NavigationMode.TWO_BUTTONS;
@@ -229,6 +232,28 @@
     public void onScrollChanged(float progress) {
         super.onScrollChanged(progress);
         mDepthController.onOverlayScrollChanged(progress);
+        onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX);
+    }
+
+    @Override
+    public void onAllAppsTransition(float progress) {
+        super.onAllAppsTransition(progress);
+        onTaskbarInAppDisplayProgressUpdate(progress, ALL_APPS_PAGE_PROGRESS_INDEX);
+    }
+
+    @Override
+    public void onWidgetsTransition(float progress) {
+        super.onWidgetsTransition(progress);
+        onTaskbarInAppDisplayProgressUpdate(progress, WIDGETS_PAGE_PROGRESS_INDEX);
+    }
+
+    private void onTaskbarInAppDisplayProgressUpdate(float progress, int flag) {
+        if (mTaskbarManager == null
+                || mTaskbarManager.getCurrentActivityContext() == null
+                || mTaskbarUIController == null) {
+            return;
+        }
+        mTaskbarUIController.onTaskbarInAppDisplayProgressUpdate(progress, flag);
     }
 
     @Override
@@ -296,7 +321,7 @@
                 new SplitSelectStateController(this, mHandler, getStateManager(),
                         getDepthController());
         overviewPanel.init(mActionsView, controller);
-        mActionsView.setDp(getDeviceProfile());
+        mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize());
         mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this));
 
         mAppTransitionManager = new QuickstepTransitionManager(this);
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 0f3474e..9f35401 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1354,7 +1354,7 @@
      */
     private RectFSpringAnim getClosingWindowAnimators(AnimatorSet animation,
             RemoteAnimationTargetCompat[] targets, View launcherView, PointF velocityPxPerS,
-            RectF closingWindowStartRect) {
+            RectF closingWindowStartRect, float startWindowCornerRadius) {
         FloatingIconView floatingIconView = null;
         FloatingWidgetView floatingWidget = null;
         RectF targetRect = new RectF();
@@ -1403,7 +1403,7 @@
             final float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
 
             RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect,
-                    windowTargetBounds) {
+                    windowTargetBounds, startWindowCornerRadius) {
                 @Override
                 public void onUpdate(RectF currentRectF, float progress) {
                     finalFloatingIconView.update(1f, 255 /* fgAlpha */, currentRectF, progress,
@@ -1421,7 +1421,7 @@
             final float floatingWidgetAlpha = isTransluscent ? 0 : 1;
             FloatingWidgetView finalFloatingWidget = floatingWidget;
             RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect,
-                    windowTargetBounds) {
+                    windowTargetBounds, startWindowCornerRadius) {
                 @Override
                 public void onUpdate(RectF currentRectF, float progress) {
                     final float fallbackBackgroundAlpha =
@@ -1438,7 +1438,8 @@
         } else {
             // If no floating icon or widget is present, animate the to the default window
             // target rect.
-            anim.addOnUpdateListener(new SpringAnimRunner(targets, targetRect, windowTargetBounds));
+            anim.addOnUpdateListener(new SpringAnimRunner(
+                    targets, targetRect, windowTargetBounds, startWindowCornerRadius));
         }
 
         // Use a fixed velocity to start the animation.
@@ -1580,7 +1581,8 @@
             RemoteAnimationTargetCompat[] appTargets,
             RemoteAnimationTargetCompat[] wallpaperTargets,
             boolean fromUnlock,
-            RectF startRect) {
+            RectF startRect,
+            float startWindowCornerRadius) {
         AnimatorSet anim = null;
         RectFSpringAnim rectFSpringAnim = null;
 
@@ -1612,7 +1614,8 @@
                         .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
                 PointF velocity = new PointF(0, -velocityPxPerS);
                 rectFSpringAnim = getClosingWindowAnimators(
-                        anim, appTargets, launcherView, velocity, startRect);
+                        anim, appTargets, launcherView, velocity, startRect,
+                        startWindowCornerRadius);
                 if (!mLauncher.isInState(LauncherState.ALL_APPS)) {
                     anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
                             true /* animateOverviewScrim */, launcherView).getAnimators());
@@ -1711,7 +1714,8 @@
 
             Pair<RectFSpringAnim, AnimatorSet> pair = createWallpaperOpenAnimations(
                     appTargets, wallpaperTargets, mFromUnlock,
-                    new RectF(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx));
+                    new RectF(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx),
+                    QuickStepContract.getWindowCornerRadius(mLauncher));
 
             mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
             result.setAnimation(pair.second, mLauncher);
@@ -1874,9 +1878,9 @@
         private final Rect mTmpRect = new Rect();
 
         SpringAnimRunner(RemoteAnimationTargetCompat[] appTargets, RectF targetRect,
-                Rect windowTargetBounds) {
+                Rect windowTargetBounds, float startWindowCornerRadius) {
             mAppTargets = appTargets;
-            mStartRadius = QuickStepContract.getWindowCornerRadius(mLauncher);
+            mStartRadius = startWindowCornerRadius;
             mEndRadius = Math.max(1, targetRect.width()) / 2f;
             mSurfaceApplier = new SurfaceTransactionApplier(mDragLayer);
             mWindowTargetBounds.set(windowTargetBounds);
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 62a8da7..05b8167 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -55,13 +55,13 @@
 import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.uioverrides.PredictedAppIcon;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.OnboardingPrefs;
 import com.android.launcher3.views.Snackbar;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 /**
@@ -480,8 +480,8 @@
      *
      * @param matcher filter matching items that have been removed
      */
-    public void onModelItemsRemoved(ItemInfoMatcher matcher) {
-        if (mPredictedItems.removeIf(matcher::matchesInfo)) {
+    public void onModelItemsRemoved(Predicate<ItemInfo> matcher) {
+        if (mPredictedItems.removeIf(matcher)) {
             fillGapsWithPrediction(true);
         }
     }
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index 5c66944..9f3be69 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -62,6 +62,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
+import com.android.launcher3.Utilities;
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
 import com.android.launcher3.logger.LauncherAtom.FolderContainer;
@@ -116,7 +117,8 @@
     @AnyThread
     private void sendEvent(AppTarget target, LauncherAtom.ItemInfo locationInfo, int eventId,
             int targetPredictor) {
-        if (target != null) {
+        // TODO: remove the running test check when b/231648228 is fixed.
+        if (target != null && !Utilities.IS_RUNNING_IN_TEST_HARNESS) {
             AppTargetEvent event = new AppTargetEvent.Builder(target, eventId)
                     .setLaunchLocation(getContainer(locationInfo))
                     .build();
diff --git a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
index 86310fa..4e59790 100644
--- a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
+++ b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
@@ -70,7 +70,8 @@
 
             RecentsView recentsView = mTarget.getOverviewPanel();
             recentsView.initiateSplitSelect(
-                    new SplitSelectSource(view, new BitmapDrawable(bitmap), intent, mPosition));
+                    new SplitSelectSource(mOriginalView, new BitmapDrawable(bitmap), intent,
+                            mPosition));
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/search/SearchSessionManager.java b/quickstep/src/com/android/launcher3/search/SearchSessionManager.java
deleted file mode 100644
index da85793..0000000
--- a/quickstep/src/com/android/launcher3/search/SearchSessionManager.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2022 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.search;
-
-import android.app.search.SearchSession;
-import android.content.Context;
-
-import androidx.annotation.IntDef;
-import androidx.annotation.UiThread;
-
-import com.android.launcher3.R;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.util.ResourceBasedOverride;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-
-/** Manages an all apps search session. */
-public class SearchSessionManager implements ResourceBasedOverride {
-
-    /** Entry state for the search session (e.g. from all apps). */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = {ZERO_ALLAPPS, ZERO_QSB})
-    public @interface ZeroEntryState {}
-    public static final int ZERO_ALLAPPS = 1;
-    public static final int ZERO_QSB = 2;
-
-    /** Creates a {@link SearchSessionManager} instance. */
-    public static SearchSessionManager newInstance(Context context) {
-        return Overrides.getObject(
-                SearchSessionManager.class, context, R.string.search_session_manager_class);
-    }
-
-    /** The current {@link SearchSession}. */
-    @UiThread
-    public void setSearchSession(SearchSession session) {}
-
-    /** {@code true} if IME is shown. */
-    public void setIsImeShown(boolean value) {}
-
-    /** Returns {@code true} if IME is enabled. */
-    public boolean getIsImeEnabled() {
-        return false;
-    }
-
-    /** The current entry state for search. */
-    public @ZeroEntryState int getEntryState() {
-        return ZERO_ALLAPPS;
-    }
-
-    /**
-     * When user enters all apps surface via tap on home widget, set the state to
-     * {@code #ZERO_QSB}. When user exits, reset to {@code #ZERO_ALLAPPS}
-     */
-    public void setEntryState(@ZeroEntryState int state) {}
-
-    /** This will be called before opening all apps, to prepare zero state suggestions. */
-    public void prepareZeroState() {}
-
-    /** Apply predicted items for the search zero state. */
-    public void setZeroStatePredictedItems(List<ItemInfo> items) {}
-
-    /** Returns {@code true} if the session is valid and should be enabled. */
-    public boolean isValidSession() {
-        return false;
-    }
-
-    /** Called when the search session is destroyed. */
-    public void onDestroy() {}
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
index cf56248..e2359c0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
@@ -39,4 +39,10 @@
     protected void onDestroy() {
         mLauncher.getHotseat().setIconsAlpha(1f);
     }
+
+    @Override
+    /** Disable taskbar stashing in desktop environment. */
+    public boolean supportsVisualStashing() {
+        return false;
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 793d987..a3e8b5c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -22,6 +22,7 @@
 import android.annotation.ColorInt;
 import android.os.RemoteException;
 import android.util.Log;
+import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.TaskTransitionSpec;
 import android.view.WindowManagerGlobal;
@@ -43,6 +44,7 @@
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.RecentsAnimationCallbacks;
 
+import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.stream.Stream;
@@ -54,10 +56,22 @@
 
     private static final String TAG = "TaskbarUIController";
 
+    public static final int MINUS_ONE_PAGE_PROGRESS_INDEX = 0;
+    public static final int ALL_APPS_PAGE_PROGRESS_INDEX = 1;
+    public static final int WIDGETS_PAGE_PROGRESS_INDEX = 2;
+    public static final int SYSUI_SURFACE_PROGRESS_INDEX = 3;
+
+    private final SparseArray<Float> mTaskbarInAppDisplayProgress = new SparseArray<>(4);
+
     private final BaseQuickstepLauncher mLauncher;
 
     private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
-            this::onStashedInAppChanged;
+            dp -> {
+                onStashedInAppChanged(dp);
+                if (mControllers != null && mControllers.taskbarViewController != null) {
+                    mControllers.taskbarViewController.onRotationChanged(dp);
+                }
+            };
 
     // Initialized in init.
     private AnimatedFloat mTaskbarOverrideBackgroundAlpha;
@@ -65,15 +79,6 @@
     private final TaskbarLauncherStateController
             mTaskbarLauncherStateController = new TaskbarLauncherStateController();
 
-    private final DeviceProfile.OnDeviceProfileChangeListener mProfileChangeListener =
-            new DeviceProfile.OnDeviceProfileChangeListener() {
-                @Override
-                public void onDeviceProfileChanged(DeviceProfile dp) {
-                    mControllers.taskbarViewController.onRotationChanged(
-                            mLauncher.getDeviceProfile());
-                }
-            };
-
     public LauncherTaskbarUIController(BaseQuickstepLauncher launcher) {
         mLauncher = launcher;
     }
@@ -93,7 +98,6 @@
 
         onStashedInAppChanged(mLauncher.getDeviceProfile());
         mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
-        mLauncher.addOnDeviceProfileChangeListener(mProfileChangeListener);
     }
 
     @Override
@@ -102,9 +106,8 @@
         onLauncherResumedOrPaused(false);
         mTaskbarLauncherStateController.onDestroy();
 
-        mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
         mLauncher.setTaskbarUIController(null);
-        mLauncher.removeOnDeviceProfileChangeListener(mProfileChangeListener);
+        mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
         updateTaskTransitionSpec(true);
     }
 
@@ -271,4 +274,85 @@
         // gesture ends, start drawing taskbar's background again since launcher might stop drawing.
         forceHideBackground(inProgress);
     }
+
+    /**
+     * Animates Taskbar elements during a transition to a Launcher state that should use in-app
+     * layouts.
+     *
+     * @param progress [0, 1]
+     *                 0 => use home layout
+     *                 1 => use in-app layout
+     */
+    public void onTaskbarInAppDisplayProgressUpdate(float progress, int progressIndex) {
+        if (mControllers == null) {
+            // This method can be called before init() is called.
+            return;
+        }
+        mTaskbarInAppDisplayProgress.put(progressIndex, progress);
+        if (!mControllers.taskbarStashController.isInApp()
+                && !mTaskbarLauncherStateController.isAnimatingToLauncher()) {
+            // Only animate the nav buttons while home and not animating home, otherwise let
+            // the TaskbarViewController handle it.
+            mControllers.navbarButtonsViewController
+                    .getTaskbarNavButtonTranslationYForInAppDisplay()
+                    .updateValue(mLauncher.getDeviceProfile().getTaskbarOffsetY()
+                            * getInAppDisplayProgress());
+        }
+    }
+
+    /** Returns true iff any in-app display progress > 0. */
+    public boolean shouldUseInAppLayout() {
+        return getInAppDisplayProgress() > 0;
+    }
+
+    private float getInAppDisplayProgress(int index) {
+        if (!mTaskbarInAppDisplayProgress.contains(index)) {
+            mTaskbarInAppDisplayProgress.put(index, 0f);
+        }
+        return mTaskbarInAppDisplayProgress.get(index);
+    }
+
+    private float getInAppDisplayProgress() {
+        return Stream.of(
+                getInAppDisplayProgress(MINUS_ONE_PAGE_PROGRESS_INDEX),
+                getInAppDisplayProgress(ALL_APPS_PAGE_PROGRESS_INDEX),
+                getInAppDisplayProgress(WIDGETS_PAGE_PROGRESS_INDEX),
+                getInAppDisplayProgress(SYSUI_SURFACE_PROGRESS_INDEX))
+                .max(Float::compareTo)
+                .get();
+    }
+
+    @Override
+    public void dumpLogs(String prefix, PrintWriter pw) {
+        super.dumpLogs(prefix, pw);
+
+        pw.println(String.format(
+                "%s\tmTaskbarOverrideBackgroundAlpha=%.2f",
+                prefix,
+                mTaskbarOverrideBackgroundAlpha.value));
+
+        pw.println(String.format("%s\tTaskbar in-app display progress:", prefix));
+        if (mControllers == null) {
+            pw.println(String.format("%s\t\tMissing mControllers", prefix));
+        } else {
+            pw.println(String.format(
+                    "%s\t\tprogress at MINUS_ONE_PAGE_PROGRESS_INDEX=%.2f",
+                    prefix,
+                    getInAppDisplayProgress(MINUS_ONE_PAGE_PROGRESS_INDEX)));
+            pw.println(String.format(
+                    "%s\t\tprogress at ALL_APPS_PAGE_PROGRESS_INDEX=%.2f",
+                    prefix,
+                    getInAppDisplayProgress(ALL_APPS_PAGE_PROGRESS_INDEX)));
+            pw.println(String.format(
+                    "%s\t\tprogress at WIDGETS_PAGE_PROGRESS_INDEX=%.2f",
+                    prefix,
+                    getInAppDisplayProgress(WIDGETS_PAGE_PROGRESS_INDEX)));
+            pw.println(String.format(
+                    "%s\t\tprogress at SYSUI_SURFACE_PROGRESS_INDEX=%.2f",
+                    prefix,
+                    getInAppDisplayProgress(SYSUI_SURFACE_PROGRESS_INDEX)));
+        }
+
+        mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index f65b907..cbdbdb9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -16,6 +16,8 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
+import static com.android.launcher3.taskbar.LauncherTaskbarUIController.SYSUI_SURFACE_PROGRESS_INDEX;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
@@ -50,6 +52,7 @@
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.PaintDrawable;
 import android.inputmethodservice.InputMethodService;
+import android.os.Handler;
 import android.util.Property;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -126,11 +129,13 @@
 
     private final AnimatedFloat mTaskbarNavButtonTranslationY = new AnimatedFloat(
             this::updateNavButtonTranslationY);
+    private final AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay = new AnimatedFloat(
+            this::updateNavButtonTranslationY);
     private final AnimatedFloat mTaskbarNavButtonTranslationYForIme = new AnimatedFloat(
             this::updateNavButtonTranslationY);
-    // Only applies to mTaskbarNavButtonTranslationY
-    private final AnimatedFloat mNavButtonTranslationYMultiplier = new AnimatedFloat(
-            this::updateNavButtonTranslationY);
+    // Used for System UI state updates that should translate the nav button for in-app display.
+    private final AnimatedFloat mNavButtonInAppDisplayProgressForSysui = new AnimatedFloat(
+            this::updateNavButtonInAppDisplayProgressForSysui);
     private final AnimatedFloat mTaskbarNavButtonDarkIntensity = new AnimatedFloat(
             this::updateNavButtonDarkIntensity);
     private final AnimatedFloat mNavButtonDarkIntensityMultiplier = new AnimatedFloat(
@@ -155,6 +160,7 @@
     private BaseDragLayer<TaskbarActivityContext> mSeparateWindowParent; // Initialized in init.
     private final ViewTreeObserverWrapper.OnComputeInsetsListener mSeparateWindowInsetsComputer =
             this::onComputeInsetsForSeparateWindow;
+    private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender();
 
     public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
         mContext = context;
@@ -173,7 +179,6 @@
     public void init(TaskbarControllers controllers) {
         mControllers = controllers;
         mNavButtonsView.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
-        mNavButtonTranslationYMultiplier.value = 1;
 
         boolean isThreeButtonNav = mContext.isThreeButtonNav();
         mIsImeRenderingNavButtons =
@@ -205,9 +210,9 @@
         // Make sure to remove nav bar buttons translation when notification shade is expanded or
         // IME is showing (add separate translation for IME).
         int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE;
-        mPropertyHolders.add(new StatePropertyHolder(mNavButtonTranslationYMultiplier,
+        mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
                 flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
-                0, 1));
+                1, 0));
         // Center nav buttons in new height for IME.
         float transForIme = (mContext.getDeviceProfile().taskbarSize
                 - mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
@@ -295,6 +300,8 @@
                 navButtonsLayoutParams.setMarginEnd(navButtonsLayoutParams.getMarginStart());
                 navButtonsLayoutParams.gravity = Gravity.CENTER;
                 mNavButtonContainer.requestLayout();
+
+                mHomeButton.setOnLongClickListener(null);
             }
 
             // Animate taskbar background when either..
@@ -386,8 +393,7 @@
                         || (flags & FLAG_KEYGUARD_VISIBLE) != 0,
                 VIEW_TRANSLATE_X, navButtonSize * (isRtl ? -2 : 2), 0));
 
-
-        // home and recents buttons
+        // home button
         mHomeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, navContainer,
                 navButtonController, R.id.home);
         mHomeButtonAlpha = new MultiValueAlpha(mHomeButton, NUM_ALPHA_CHANNELS);
@@ -397,8 +403,21 @@
                         ALPHA_INDEX_KEYGUARD_OR_DISABLE),
                 flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
                         (flags & FLAG_DISABLE_HOME) == 0));
+
+        // Recents button
         View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
                 navContainer, navButtonController, R.id.recent_apps);
+        mHitboxExtender.init(recentsButton, mNavButtonsView, mContext.getDeviceProfile(),
+                () -> {
+                    float[] recentsCoords = new float[2];
+                    getDescendantCoordRelativeToAncestor(recentsButton, mNavButtonsView,
+                            recentsCoords, false);
+                    return recentsCoords;
+                }, new Handler());
+        recentsButton.setOnClickListener(v -> {
+            navButtonController.onButtonClick(BUTTON_RECENTS);
+            mHitboxExtender.onRecentsButtonClicked();
+        });
         mPropertyHolders.add(new StatePropertyHolder(recentsButton,
                 flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_RECENTS) == 0
                         && !mContext.isNavBarKidsModeActive()));
@@ -502,6 +521,9 @@
             View button = mAllButtons.get(i);
             if (button.getVisibility() == View.VISIBLE) {
                 parent.getDescendantRectRelativeToSelf(button, mTempRect);
+                if (mHitboxExtender.extendedHitboxEnabled()) {
+                    mTempRect.bottom += mContext.mDeviceProfile.getTaskbarOffsetY();
+                }
                 outRegion.op(mTempRect, Op.UNION);
             }
         }
@@ -526,6 +548,11 @@
         return mTaskbarNavButtonTranslationY;
     }
 
+    /** Use to set the translationY for the all nav+contextual buttons when in Launcher */
+    public AnimatedFloat getTaskbarNavButtonTranslationYForInAppDisplay() {
+        return mTaskbarNavButtonTranslationYForInAppDisplay;
+    }
+
     /** Use to set the dark intensity for the all nav+contextual buttons */
     public AnimatedFloat getTaskbarNavButtonDarkIntensity() {
         return mTaskbarNavButtonDarkIntensity;
@@ -554,11 +581,26 @@
         }
     }
 
+    private void updateNavButtonInAppDisplayProgressForSysui() {
+        TaskbarUIController uiController = mControllers.uiController;
+        if (uiController instanceof LauncherTaskbarUIController) {
+            ((LauncherTaskbarUIController) uiController).onTaskbarInAppDisplayProgressUpdate(
+                    mNavButtonInAppDisplayProgressForSysui.value, SYSUI_SURFACE_PROGRESS_INDEX);
+        }
+    }
+
     private void updateNavButtonTranslationY() {
-        float normalTranslationY = mTaskbarNavButtonTranslationY.value
-                * mNavButtonTranslationYMultiplier.value;
-        float otherTranslationY = mTaskbarNavButtonTranslationYForIme.value;
-        mNavButtonsView.setTranslationY(normalTranslationY + otherTranslationY);
+        final float normalTranslationY = mTaskbarNavButtonTranslationY.value;
+        final float imeAdjustmentTranslationY = mTaskbarNavButtonTranslationYForIme.value;
+        TaskbarUIController uiController = mControllers.uiController;
+        final float inAppDisplayAdjustmentTranslationY =
+                (uiController instanceof LauncherTaskbarUIController
+                        && ((LauncherTaskbarUIController) uiController).shouldUseInAppLayout())
+                        ? mTaskbarNavButtonTranslationYForInAppDisplay.value : 0;
+
+        mNavButtonsView.setTranslationY(normalTranslationY
+                + imeAdjustmentTranslationY
+                + inAppDisplayAdjustmentTranslationY);
     }
 
     private void updateNavButtonDarkIntensity() {
@@ -711,6 +753,17 @@
         return str.toString();
     }
 
+    public TouchController getTouchController() {
+        return mHitboxExtender;
+    }
+
+    /**
+     * @param alignment 0 -> Taskbar, 1 -> Workspace
+     */
+    public void updateTaskbarAlignment(float alignment) {
+        mHitboxExtender.onAnimationProgressToOverview(alignment);
+    }
+
     private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
         @Override
         public void onVisibilityChanged(boolean isVisible) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/RecentsHitboxExtender.java b/quickstep/src/com/android/launcher3/taskbar/RecentsHitboxExtender.java
new file mode 100644
index 0000000..4651570
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/RecentsHitboxExtender.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 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.taskbar;
+
+import android.graphics.Rect;
+import android.os.Handler;
+import android.view.MotionEvent;
+import android.view.TouchDelegate;
+import android.view.View;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.util.TouchController;
+
+import java.util.function.Supplier;
+
+/**
+ * Extends the Recents touch area during the taskbar to overview animation
+ * to give user some error room when trying to quickly double tap recents button since it moves.
+ *
+ * Listens for icon alignment as our indication for the animation.
+ */
+public class RecentsHitboxExtender implements TouchController {
+
+    private static final int RECENTS_HITBOX_TIMEOUT_MS = 500;
+
+    private View mRecentsButton;
+    private View mRecentsParent;
+    private DeviceProfile mDeviceProfile;
+    private Supplier<float[]> mParentCoordSupplier;
+    private TouchDelegate mRecentsTouchDelegate;
+    /**
+     * Will be true while the animation from taskbar to overview is occurring.
+     * Lifecycle of this variable slightly extends past the animation by
+     * {@link #RECENTS_HITBOX_TIMEOUT_MS}, so can use this variable as a proxy for if
+     * the current hitbox is extended or not.
+     */
+    private boolean mAnimatingFromTaskbarToOverview;
+    private float mLastIconAlignment;
+    private final Rect mRecentsHitBox = new Rect();
+    private boolean mRecentsButtonClicked;
+    private Handler mHandler;
+    private final Runnable mRecentsHitboxResetRunnable = this::reset;
+
+    public void init(View recentsButton, View recentsParent, DeviceProfile deviceProfile,
+            Supplier<float[]> parentCoordSupplier, Handler handler) {
+        mRecentsButton = recentsButton;
+        mRecentsParent = recentsParent;
+        mDeviceProfile = deviceProfile;
+        mParentCoordSupplier = parentCoordSupplier;
+        mHandler = handler;
+    }
+
+    public void onRecentsButtonClicked() {
+        mRecentsButtonClicked = true;
+    }
+
+    /**
+     * @param progress 0 -> Taskbar, 1 -> Overview
+     */
+    public void onAnimationProgressToOverview(float progress) {
+        if (progress == 1 || progress == 0) {
+            // Done w/ animation
+            mLastIconAlignment = progress;
+            if (mAnimatingFromTaskbarToOverview) {
+                if (progress == 1) {
+                    // Finished animation to workspace, remove the touch delegate shortly
+                    mHandler.postDelayed(mRecentsHitboxResetRunnable, RECENTS_HITBOX_TIMEOUT_MS);
+                    return;
+                } else {
+                    // Went back to taskbar, reset immediately
+                    mHandler.removeCallbacks(mRecentsHitboxResetRunnable);
+                    reset();
+                }
+            }
+        }
+
+        if (mAnimatingFromTaskbarToOverview) {
+            return;
+        }
+
+        if (progress > 0 && mLastIconAlignment == 0 && mRecentsButtonClicked) {
+            // Starting animation, previously we were showing taskbar
+            mAnimatingFromTaskbarToOverview = true;
+            float[] recentsCoords = mParentCoordSupplier.get();
+            int x = (int) recentsCoords[0];
+            int y = (int) (recentsCoords[1]);
+            // Extend hitbox vertically by the offset amount from mDeviceProfile.getTaskbarOffsetY()
+            mRecentsHitBox.set(x, y,
+                    x + mRecentsButton.getWidth(),
+                    y + mRecentsButton.getHeight() + mDeviceProfile.getTaskbarOffsetY()
+            );
+            mRecentsTouchDelegate = new TouchDelegate(mRecentsHitBox, mRecentsButton);
+            mRecentsParent.setTouchDelegate(mRecentsTouchDelegate);
+        }
+    }
+
+    private void reset() {
+        mAnimatingFromTaskbarToOverview = false;
+        mRecentsButton.setTouchDelegate(null);
+        mRecentsHitBox.setEmpty();
+        mRecentsButtonClicked = false;
+    }
+
+    /**
+     * @return {@code true} if the bounds for recents touches are currently extended
+     */
+    public boolean extendedHitboxEnabled() {
+        return mAnimatingFromTaskbarToOverview;
+    }
+
+    @Override
+    public boolean onControllerTouchEvent(MotionEvent ev) {
+        return mRecentsTouchDelegate.onTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        return mRecentsHitBox.contains((int)ev.getX(), (int)ev.getY());
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index b349637..2f32219 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -199,7 +199,7 @@
                 new TaskbarInsetsController(this));
     }
 
-    public void init(TaskbarSharedState sharedState) {
+    public void init(@NonNull TaskbarSharedState sharedState) {
         mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
         mWindowLayoutParams = createDefaultWindowLayoutParams();
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index ff08e3d..449e0a7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -61,6 +61,8 @@
     private boolean mAreAllControllersInitialized;
     private final List<Runnable> mPostInitCallbacks = new ArrayList<>();
 
+    @Nullable private TaskbarSharedState mSharedState = null;
+
     public TaskbarControllers(TaskbarActivityContext taskbarActivityContext,
             TaskbarDragController taskbarDragController,
             TaskbarNavButtonController navButtonController,
@@ -104,8 +106,9 @@
      * TaskbarControllers instance, but should be careful to only access things that were created
      * in constructors for now, as some controllers may still be waiting for init().
      */
-    public void init(TaskbarSharedState sharedState) {
+    public void init(@NonNull TaskbarSharedState sharedState) {
         mAreAllControllersInitialized = false;
+        mSharedState = sharedState;
 
         taskbarDragController.init(this);
         navbarButtonsViewController.init(this);
@@ -116,11 +119,11 @@
         taskbarUnfoldAnimationController.init(this);
         taskbarKeyguardController.init(navbarButtonsViewController);
         stashedHandleViewController.init(this);
-        taskbarStashController.init(this, sharedState);
+        taskbarStashController.init(this, sharedState.setupUIVisible);
         taskbarEduController.init(this);
         taskbarPopupController.init(this);
         taskbarForceVisibleImmersiveController.init(this);
-        taskbarAllAppsController.init(this, sharedState);
+        taskbarAllAppsController.init(this, sharedState.allAppsVisible);
         navButtonController.init(this);
         taskbarInsetsController.init(this);
 
@@ -139,6 +142,12 @@
         mPostInitCallbacks.clear();
     }
 
+    @Nullable
+    public TaskbarSharedState getSharedState() {
+        // This should only be null if called before init() and after destroy().
+        return mSharedState;
+    }
+
     public void onConfigurationChanged(@Config int configChanges) {
         navbarButtonsViewController.onConfigurationChanged(configChanges);
     }
@@ -147,6 +156,8 @@
      * Cleans up all controllers.
      */
     public void onDestroy() {
+        mSharedState = null;
+
         navbarButtonsViewController.onDestroy();
         uiController.onDestroy();
         rotationButtonController.onDestroy();
@@ -187,9 +198,12 @@
             return;
         }
 
+        pw.println(String.format(
+                "%s\tmAreAllControllersInitialized=%b", prefix, mAreAllControllersInitialized));
         for (LoggableTaskbarController controller : mControllersToLog) {
             controller.dumpLogs(prefix + "\t", pw);
         }
+        uiController.dumpLogs(prefix + "\t", pw);
         rotationButtonController.dumpLogs(prefix + "\t", pw);
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 5c10565..c522888 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -73,6 +73,7 @@
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.function.Predicate;
 
 /**
  * Handles long click on Taskbar items to start a system drag and drop operation.
@@ -439,12 +440,12 @@
                 target = taskbarViewController.getAllAppsButtonView();
             } else if (item.container >= 0) {
                 // Since folders close when the drag starts, target the folder icon instead.
-                ItemInfoMatcher matcher = ItemInfoMatcher.forFolderMatch(
+                Predicate<ItemInfo> matcher = ItemInfoMatcher.forFolderMatch(
                         ItemInfoMatcher.ofItemIds(IntSet.wrap(item.id)));
                 target = taskbarViewController.getFirstIconMatch(matcher);
             } else if (item.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
                 // Find first icon with same package/user as the deep shortcut.
-                ItemInfoMatcher packageUserMatcher = ItemInfoMatcher.ofPackages(
+                Predicate<ItemInfo> packageUserMatcher = ItemInfoMatcher.ofPackages(
                         Collections.singleton(item.getTargetPackage()), item.user);
                 target = taskbarViewController.getFirstIconMatch(packageUserMatcher);
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 3e2695c..99c59a8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -182,7 +182,8 @@
          */
         public TouchController[] getTouchControllers() {
             return new TouchController[]{mActivity.getDragController(),
-                    mControllers.taskbarForceVisibleImmersiveController};
+                    mControllers.taskbarForceVisibleImmersiveController,
+                    mControllers.navbarButtonsViewController.getTouchController()};
         }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 36e6420..052c695 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -42,7 +42,9 @@
 import com.android.systemui.animation.ViewRootSync;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
+import java.io.PrintWriter;
 import java.util.HashMap;
+import java.util.StringJoiner;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
@@ -370,6 +372,7 @@
 
         // If we're already animating to the value, just leave it be instead of restarting it.
         if (!mIconAlignmentForLauncherState.isAnimatingToValue(toAlignment)) {
+            mIconAlignmentForLauncherState.finishAnimation();
             animatorSet.play(mIconAlignmentForLauncherState.animateToValue(toAlignment)
                     .setDuration(duration));
         }
@@ -425,6 +428,7 @@
 
         // Switch taskbar and hotseat in last frame
         setTaskbarViewVisible(alignment < 1);
+        mControllers.navbarButtonsViewController.updateTaskbarAlignment(alignment);
     }
 
     private float getCurrentIconAlignmentRatioBetweenAppAndHome() {
@@ -476,4 +480,48 @@
             controller.applyState();
         }
     }
+
+    private static String getStateString(int flags) {
+        StringJoiner str = new StringJoiner("|");
+        str.add((flags & FLAG_RESUMED) != 0 ? "FLAG_RESUMED" : "");
+        str.add((flags & FLAG_RECENTS_ANIMATION_RUNNING) != 0
+                ? "FLAG_RECENTS_ANIMATION_RUNNING" : "");
+        str.add((flags & FLAG_TRANSITION_STATE_RUNNING) != 0
+                ? "FLAG_TRANSITION_STATE_RUNNING" : "");
+        return str.toString();
+    }
+
+    protected void dumpLogs(String prefix, PrintWriter pw) {
+        pw.println(prefix + "TaskbarLauncherStateController:");
+
+        pw.println(String.format(
+                "%s\tmIconAlignmentForResumedState=%.2f",
+                prefix,
+                mIconAlignmentForResumedState.value));
+        pw.println(String.format(
+                "%s\tmIconAlignmentForGestureState=%.2f",
+                prefix,
+                mIconAlignmentForGestureState.value));
+        pw.println(String.format(
+                "%s\tmIconAlignmentForLauncherState=%.2f",
+                prefix,
+                mIconAlignmentForLauncherState.value));
+        pw.println(String.format(
+                "%s\tmTaskbarBackgroundAlpha=%.2f", prefix, mTaskbarBackgroundAlpha.value));
+        pw.println(String.format(
+                "%s\tmIconAlphaForHome=%.2f", prefix, mIconAlphaForHome.getValue()));
+        pw.println(String.format("%s\tmPrevState=%s", prefix, getStateString(mPrevState)));
+        pw.println(String.format("%s\tmState=%s", prefix, getStateString(mState)));
+        pw.println(String.format("%s\tmLauncherState=%s", prefix, mLauncherState));
+        pw.println(String.format(
+                "%s\tmIsAnimatingToLauncherViaGesture=%b",
+                prefix,
+                mIsAnimatingToLauncherViaGesture));
+        pw.println(String.format(
+                "%s\tmIsAnimatingToLauncherViaResume=%b",
+                prefix,
+                mIsAnimatingToLauncherViaResume));
+        pw.println(String.format(
+                "%s\tmShouldDelayLauncherStateAnim=%b", prefix, mShouldDelayLauncherStateAnim));
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index e02a9d7..2e37170 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -194,6 +194,9 @@
      * Sets a {@link StatefulActivity} to act as taskbar callback
      */
     public void setActivity(@NonNull StatefulActivity activity) {
+        if (mActivity == activity) {
+            return;
+        }
         mActivity = activity;
         mUnfoldProgressProvider.setSourceProvider(getUnfoldTransitionProgressProviderForActivity(
                 activity));
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 62392ee..75881a3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -36,6 +36,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Launcher model Callbacks for rendering taskbar.
@@ -126,16 +127,16 @@
     }
 
     @Override
-    public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) {
+    public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
         if (handleItemsRemoved(matcher)) {
             commitItemsToUI();
         }
     }
 
-    private boolean handleItemsRemoved(ItemInfoMatcher matcher) {
+    private boolean handleItemsRemoved(Predicate<ItemInfo> matcher) {
         boolean modified = false;
         for (int i = mHotseatItems.size() - 1; i >= 0; i--) {
-            if (matcher.matchesInfo(mHotseatItems.valueAt(i))) {
+            if (matcher.test(mHotseatItems.valueAt(i))) {
                 modified = true;
                 mHotseatItems.removeAt(i);
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index a5c55b0..87b3789 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -25,5 +25,4 @@
     public boolean setupUIVisible = false;
 
     public boolean allAppsVisible = false;
-
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index f34759d..7d95743 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -17,6 +17,7 @@
 
 import static android.view.HapticFeedbackConstants.LONG_PRESS;
 
+import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
 import static com.android.launcher3.taskbar.Utilities.appendFlag;
@@ -34,7 +35,6 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.quickstep.AnimatedFloat;
@@ -167,7 +167,7 @@
         mStashedHeight = mActivity.getDeviceProfile().stashedTaskbarSize;
     }
 
-    public void init(TaskbarControllers controllers, TaskbarSharedState sharedState) {
+    public void init(TaskbarControllers controllers, boolean setupUIVisible) {
         mControllers = controllers;
 
         TaskbarDragLayerController dragLayerController = controllers.taskbarDragLayerController;
@@ -188,7 +188,7 @@
 
         boolean isManuallyStashedInApp = supportsManualStashing()
                 && mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF);
-        boolean isInSetup = !mActivity.isUserSetupComplete() || sharedState.setupUIVisible;
+        boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
         updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
         updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
         updateStateForFlag(FLAG_IN_SETUP, isInSetup);
@@ -202,7 +202,7 @@
      * state.
      */
     public boolean supportsVisualStashing() {
-        return !mActivity.isThreeButtonNav();
+        return mControllers.uiController.supportsVisualStashing();
     }
 
     /**
@@ -275,7 +275,7 @@
         return !mIsStashed && isInApp();
     }
 
-    private boolean isInApp() {
+    public boolean isInApp() {
         return hasAnyFlag(FLAGS_IN_APP);
     }
 
@@ -564,7 +564,8 @@
 
         updateStateForFlag(FLAG_STASHED_IN_APP_ALL_APPS, false);
         if (applyState) {
-            applyState(TaskbarAllAppsSlideInView.DEFAULT_CLOSE_DURATION);
+            applyState(ALL_APPS.getTransitionDuration(
+                    mControllers.taskbarActivityContext, false /* isToState */));
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index d5c399b..fcc34c6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -22,6 +22,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 
+import java.io.PrintWriter;
 import java.util.stream.Stream;
 
 /**
@@ -48,6 +49,11 @@
         return true;
     }
 
+    public boolean supportsVisualStashing() {
+        if (mControllers == null) return false;
+        return !mControllers.taskbarActivityContext.isThreeButtonNav();
+    }
+
     protected void onStashedInAppChanged() { }
 
     public Stream<ItemInfoWithIcon> getAppIconsForEdu() {
@@ -86,4 +92,12 @@
             stashController.applyState();
         }
     }
+
+    @CallSuper
+    protected void dumpLogs(String prefix, PrintWriter pw) {
+        pw.println(String.format(
+                "%sTaskbarUIController: using an instance of %s",
+                prefix,
+                getClass().getSimpleName()));
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 7548398..6f88d64 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -41,12 +41,13 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.uioverrides.ApiWrapper;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.AllAppsButton;
 import com.android.launcher3.views.DoubleShadowBubbleTextView;
 
+import java.util.function.Predicate;
+
 /**
  * Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
  */
@@ -424,8 +425,8 @@
      * Finds the first icon to match one of the given matchers, from highest to lowest priority.
      * @return The first match, or All Apps button if no match was found.
      */
-    public View getFirstMatch(ItemInfoMatcher... matchers) {
-        for (ItemInfoMatcher matcher : matchers) {
+    public View getFirstMatch(Predicate<ItemInfo>... matchers) {
+        for (Predicate<ItemInfo> matcher : matchers) {
             for (int i = 0; i < getChildCount(); i++) {
                 View item = getChildAt(i);
                 if (!(item.getTag() instanceof ItemInfo)) {
@@ -433,7 +434,7 @@
                     continue;
                 }
                 ItemInfo info = (ItemInfo) item.getTag();
-                if (matcher.matchesInfo(info)) {
+                if (matcher.test(info)) {
                     return item;
                 }
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 6416720..5db495d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -47,6 +47,7 @@
 import com.android.quickstep.AnimatedFloat;
 
 import java.io.PrintWriter;
+import java.util.function.Predicate;
 
 /**
  * Handles properties/data collection, then passes the results to TaskbarView to render.
@@ -73,6 +74,7 @@
     private final AnimatedFloat mTaskbarIconTranslationYForStash = new AnimatedFloat(
             this::updateTranslationY);
     private AnimatedFloat mTaskbarNavButtonTranslationY;
+    private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
 
     private final AnimatedFloat mThemeIconsBackground = new AnimatedFloat(
             this::updateIconsBackground);
@@ -112,6 +114,8 @@
         }
         mTaskbarNavButtonTranslationY =
                 controllers.navbarButtonsViewController.getTaskbarNavButtonTranslationY();
+        mTaskbarNavButtonTranslationYForInAppDisplay = controllers.navbarButtonsViewController
+                .getTaskbarNavButtonTranslationYForInAppDisplay();
     }
 
     public void onDestroy() {
@@ -242,6 +246,7 @@
         int offsetY = launcherDp.getTaskbarOffsetY();
         setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, LINEAR);
         setter.setFloat(mTaskbarNavButtonTranslationY, VALUE, -offsetY, LINEAR);
+        setter.setFloat(mTaskbarNavButtonTranslationYForInAppDisplay, VALUE, offsetY, LINEAR);
 
         if (Utilities.isDarkTheme(mTaskbarView.getContext())) {
             setter.addFloat(mThemeIconsBackground, VALUE, 0f, 1f, LINEAR);
@@ -258,12 +263,14 @@
             View child = mTaskbarView.getChildAt(i);
 
             int positionInHotseat = -1;
-            if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() && i == count - 1) {
+            boolean isRtl = Utilities.isRtl(child.getResources());
+            if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()
+                    && ((isRtl && i == 0) || (!isRtl && i == count - 1))) {
                 // Note that there is no All Apps button in the hotseat, this position is only used
                 // as its convenient for animation purposes.
-                positionInHotseat = Utilities.isRtl(child.getResources())
+                positionInHotseat = isRtl
                         ? -1
-                        : mActivity.getDeviceProfile().inv.numShownHotseatIcons;
+                        : mActivity.getDeviceProfile().numShownHotseatIcons;
 
                 setter.setViewAlpha(child, 0, LINEAR);
             } else if (child.getTag() instanceof ItemInfo) {
@@ -289,10 +296,12 @@
     }
 
     public void onRotationChanged(DeviceProfile deviceProfile) {
-        if (areIconsVisible()) {
+        if (mControllers.taskbarStashController.isInApp()) {
             // We only translate on rotation when on home
             return;
         }
+        mActivity.setTaskbarWindowHeight(
+                deviceProfile.taskbarSize + deviceProfile.getTaskbarOffsetY());
         mTaskbarNavButtonTranslationY.updateValue(-deviceProfile.getTaskbarOffsetY());
     }
 
@@ -309,8 +318,8 @@
      * 2) FolderIcon of the Folder containing the given icon
      * 3) All Apps button
      */
-    public View getFirstIconMatch(ItemInfoMatcher matcher) {
-        ItemInfoMatcher folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
+    public View getFirstIconMatch(Predicate<ItemInfo> matcher) {
+        Predicate<ItemInfo> folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
         return mTaskbarView.getFirstMatch(matcher, folderMatcher);
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
index 51fa4d9..0ea2aa0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
@@ -44,10 +44,9 @@
     }
 
     @Override
-    protected BaseAllAppsAdapter<TaskbarAllAppsContext> createAdapter(
-            AlphabeticalAppsList<TaskbarAllAppsContext> appsList,
+    protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<TaskbarAllAppsContext> mAppsList,
             BaseAdapterProvider[] adapterProviders) {
-        return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
+        return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
                 adapterProviders);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index 9fca8eb..eaf9384 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -38,7 +38,6 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarControllers;
-import com.android.launcher3.taskbar.TaskbarSharedState;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 
@@ -72,7 +71,6 @@
     };
 
     private TaskbarControllers mControllers;
-    private TaskbarSharedState mSharedState;
     /** Window context for all apps if it is open. */
     private @Nullable TaskbarAllAppsContext mAllAppsContext;
 
@@ -88,18 +86,17 @@
     }
 
     /** Initialize the controller. */
-    public void init(TaskbarControllers controllers, TaskbarSharedState sharedState) {
+    public void init(TaskbarControllers controllers, boolean allAppsVisible) {
         if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
             return;
         }
         mControllers = controllers;
-        mSharedState = sharedState;
 
         /*
          * Recreate All Apps if it was open in the previous Taskbar instance (e.g. the configuration
          * changed).
          */
-        if (mSharedState.allAppsVisible) {
+        if (allAppsVisible) {
             show(false);
         }
     }
@@ -141,7 +138,9 @@
             return;
         }
         mProxyView.show();
-        mSharedState.allAppsVisible = true;
+        // mControllers and getSharedState should never be null here. Do not handle null-pointer
+        // to catch invalid states.
+        mControllers.getSharedState().allAppsVisible = true;
 
         mAllAppsContext = new TaskbarAllAppsContext(mTaskbarContext,
                 this,
@@ -176,7 +175,9 @@
             return;
         }
         mProxyView.close(false);
-        mSharedState.allAppsVisible = false;
+        // mControllers and getSharedState should never be null here. Do not handle null-pointer
+        // to catch invalid states.
+        mControllers.getSharedState().allAppsVisible = false;
         onDestroy();
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index a37ebac..c4837a0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -15,13 +15,16 @@
  */
 package com.android.launcher3.taskbar.allapps;
 
+import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
+import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
 
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
+import android.view.animation.Interpolator;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
@@ -33,9 +36,6 @@
 /** Wrapper for taskbar all apps with slide-in behavior. */
 public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarAllAppsContext>
         implements Insettable, DeviceProfile.OnDeviceProfileChangeListener {
-    static final int DEFAULT_OPEN_DURATION = 500;
-    public static final int DEFAULT_CLOSE_DURATION = 200;
-
     private TaskbarAllAppsContainerView mAppsView;
     private OnCloseListener mOnCloseBeginListener;
     private float mShiftRange;
@@ -61,7 +61,8 @@
             mOpenCloseAnimator.setValues(
                     PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
             mOpenCloseAnimator.setInterpolator(AGGRESSIVE_EASE);
-            mOpenCloseAnimator.setDuration(DEFAULT_OPEN_DURATION).start();
+            mOpenCloseAnimator.setDuration(
+                    ALL_APPS.getTransitionDuration(mActivityContext, true /* isToState */)).start();
         } else {
             mTranslationShift = TRANSLATION_SHIFT_OPENED;
         }
@@ -80,7 +81,13 @@
     @Override
     protected void handleClose(boolean animate) {
         Optional.ofNullable(mOnCloseBeginListener).ifPresent(OnCloseListener::onSlideInViewClosed);
-        handleClose(animate, DEFAULT_CLOSE_DURATION);
+        handleClose(animate,
+                ALL_APPS.getTransitionDuration(mActivityContext, false /* isToState */));
+    }
+
+    @Override
+    protected Interpolator getIdleInterpolator() {
+        return EMPHASIZED_ACCELERATE;
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index f19b7de..a39e872 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -15,8 +15,8 @@
  */
 package com.android.launcher3.taskbar.allapps;
 
+import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_ALL_APPS;
-import static com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView.DEFAULT_OPEN_DURATION;
 import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
 
 import com.android.launcher3.AbstractFloatingView;
@@ -81,7 +81,8 @@
 
     private void setUpTaskbarStashing() {
         mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_APP_ALL_APPS, true);
-        mTaskbarStashController.applyState(DEFAULT_OPEN_DURATION);
+        mTaskbarStashController.applyState(
+                ALL_APPS.getTransitionDuration(mContext, true /* isToState */));
         mSlideInView.setOnCloseBeginListener(() -> {
             AbstractFloatingView.closeOpenContainer(
                     mContext, AbstractFloatingView.TYPE_ACTION_POPUP);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index f32b315..4bb4343 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -70,7 +70,6 @@
 import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.NavigationMode;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.PendingRequestArgs;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.util.UiThreadHelper;
@@ -86,6 +85,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Objects;
+import java.util.function.Predicate;
 import java.util.stream.Stream;
 
 public class QuickstepLauncher extends BaseQuickstepLauncher {
@@ -220,8 +220,7 @@
                     (getActivityFlags() & ACTIVITY_STATE_USER_WILL_BE_ACTIVE) != 0;
             boolean visible = (state == NORMAL || state == OVERVIEW)
                     && (willUserBeActive || isUserActive())
-                    && !profile.isVerticalBarLayout()
-                    && profile.isPhone && !profile.isLandscape;
+                    && !profile.isVerticalBarLayout();
             UiThreadHelper.runAsyncCommand(this, SET_SHELF_HEIGHT, visible ? 1 : 0,
                     profile.hotseatBarSizePx);
         }
@@ -246,7 +245,7 @@
     }
 
     @Override
-    public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) {
+    public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
         super.bindWorkspaceComponentsRemoved(matcher);
         mHotseatPredictionController.onModelItemsRemoved(matcher);
     }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 86f26c3..00a98c0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -118,7 +118,7 @@
         if (toState == OVERVIEW_SPLIT_SELECT) {
             // Animation to "dismiss" selected taskView
             PendingAnimation splitSelectInitAnimation = mRecentsView.createSplitSelectInitAnimation(
-                    toState.getTransitionDuration(mLauncher));
+                    toState.getTransitionDuration(mLauncher, true /* isToState */));
             // Add properties to shift remaining taskViews to get out of placeholder view
             splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.first,
                     toState.getSplitSelectTranslation(mLauncher), LINEAR);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
index df0ac7c..fe0bca6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
@@ -33,12 +33,12 @@
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.shared.plugins.PluginManagerImpl;
 import com.android.systemui.shared.plugins.PluginPrefs;
+import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Optional;
 import java.util.Set;
 
 public class PluginManagerWrapper {
@@ -48,6 +48,9 @@
 
     public static final String PLUGIN_CHANGED = PluginManager.PLUGIN_CHANGED;
 
+    private static final UncaughtExceptionPreHandlerManager UNCAUGHT_EXCEPTION_PRE_HANDLER_MANAGER =
+            new UncaughtExceptionPreHandlerManager();
+
     private final Context mContext;
     private final PluginManager mPluginManager;
     private final PluginEnablerImpl mPluginEnabler;
@@ -67,7 +70,7 @@
 
         mPluginManager = new PluginManagerImpl(c, instanceManagerFactory,
                 Utilities.IS_DEBUG_DEVICE,
-                Optional.ofNullable(Thread.getDefaultUncaughtExceptionHandler()), mPluginEnabler,
+                UNCAUGHT_EXCEPTION_PRE_HANDLER_MANAGER, mPluginEnabler,
                 new PluginPrefs(c), privilegedPlugins);
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index cd14b3f..3b1f119 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 
+import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
@@ -30,15 +31,19 @@
  */
 public class AllAppsState extends LauncherState {
 
-    private static final int STATE_FLAGS = FLAG_WORKSPACE_INACCESSIBLE | FLAG_CLOSE_POPUPS;
+    private static final int STATE_FLAGS =
+            FLAG_WORKSPACE_INACCESSIBLE | FLAG_CLOSE_POPUPS | FLAG_HOTSEAT_INACCESSIBLE;
 
     public AllAppsState(int id) {
         super(id, LAUNCHER_STATE_ALLAPPS, STATE_FLAGS);
     }
 
     @Override
-    public int getTransitionDuration(Context context) {
-        return 150;
+    public <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable>
+    int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState) {
+        return !context.getDeviceProfile().isTablet && isToState
+                ? 600
+                : isToState ? 500 : 300;
     }
 
     @Override
@@ -53,17 +58,21 @@
 
     @Override
     public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
-        ScaleAndTranslation scaleAndTranslation =
-                new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET);
+        return new ScaleAndTranslation(0.97f, NO_OFFSET, NO_OFFSET);
+    }
+
+    @Override
+    public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
         if (launcher.getDeviceProfile().isTablet) {
-            scaleAndTranslation.scale = 0.97f;
+            return getWorkspaceScaleAndTranslation(launcher);
         } else {
             ScaleAndTranslation overviewScaleAndTranslation = LauncherState.OVERVIEW
                     .getWorkspaceScaleAndTranslation(launcher);
-            scaleAndTranslation.translationX = overviewScaleAndTranslation.translationX;
-            scaleAndTranslation.translationY = overviewScaleAndTranslation.translationY;
+            return new ScaleAndTranslation(
+                    NO_SCALE,
+                    overviewScaleAndTranslation.translationX,
+                    overviewScaleAndTranslation.translationY);
         }
-        return scaleAndTranslation;
     }
 
     @Override
@@ -88,7 +97,9 @@
 
     @Override
     public int getVisibleElements(Launcher launcher) {
-        return ALL_APPS_CONTENT | HOTSEAT_ICONS;
+        // Don't add HOTSEAT_ICONS for non-tablets in ALL_APPS state.
+        return launcher.getDeviceProfile().isTablet ? ALL_APPS_CONTENT | HOTSEAT_ICONS
+                : ALL_APPS_CONTENT;
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index 6f084a1..0c49e5f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -40,7 +40,7 @@
     }
 
     @Override
-    public int getTransitionDuration(Context launcher) {
+    public int getTransitionDuration(Context launcher, boolean isToState) {
         return 300;
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 236454e..699ce97 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -22,10 +22,12 @@
 import android.graphics.Rect;
 import android.os.SystemProperties;
 
+import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
+import com.android.launcher3.taskbar.LauncherTaskbarUIController;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Themes;
 import com.android.quickstep.util.LayoutUtils;
@@ -56,7 +58,7 @@
     }
 
     @Override
-    public int getTransitionDuration(Context context) {
+    public int getTransitionDuration(Context context, boolean isToState) {
         // In gesture modes, overview comes in all the way from the side, so give it more time.
         return DisplayController.getNavigationMode(context).hasGestures ? 380 : 250;
     }
@@ -93,7 +95,13 @@
 
     @Override
     public boolean isTaskbarStashed(Launcher launcher) {
-        return true;
+        if (launcher instanceof BaseQuickstepLauncher) {
+            LauncherTaskbarUIController uiController =
+                    ((BaseQuickstepLauncher) launcher).getTaskbarUIController();
+
+            return uiController != null && uiController.supportsVisualStashing();
+        }
+        return super.isTaskbarStashed(launcher);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index b1d83e7..f2162b0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -42,6 +42,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
@@ -50,6 +51,8 @@
 import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_SCRIM_OPAQUE_THRESHOLD;
 import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_SCRIM_VISIBLE_THRESHOLD;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
+import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE;
 
 import android.animation.ValueAnimator;
 
@@ -179,12 +182,20 @@
             }
             config.duration = Math.max(config.duration, mHintToNormalDuration);
         } else if (fromState == ALL_APPS && toState == NORMAL) {
-            config.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
-                    1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
-                    1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD));
-            config.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(DEACCEL,
+            boolean isTablet = mActivity.getDeviceProfile().isTablet;
+            config.setInterpolator(ANIM_ALL_APPS_FADE,
+                    isTablet ? FINAL_FRAME : Interpolators.clampToProgress(LINEAR,
+                            1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
+                            1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD));
+            config.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(LINEAR,
                     1 - ALL_APPS_SCRIM_OPAQUE_THRESHOLD,
                     1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD));
+            config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED_ACCELERATE);
+        } else if (fromState == NORMAL && toState == ALL_APPS) {
+            if (mActivity.getDeviceProfile().isTablet) {
+                config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED_DECELERATE);
+            }
+            // TODO(b/231682175): centralize this setup in AllAppsSwipeController
         }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 7ec1243..4da1d41 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -180,7 +180,7 @@
             // Normally we compute the duration based on the velocity and distance to the given
             // state, but since the hint state tracks the entire screen without a clear endpoint, we
             // need to manually set the duration to a reasonable value.
-            animator.setDuration(HINT_STATE.getTransitionDuration(mLauncher));
+            animator.setDuration(HINT_STATE.getTransitionDuration(mLauncher, true /* isToState */));
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 2ca59eb..53dc9dd 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -27,6 +27,7 @@
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEDOWN;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEUP;
 import static com.android.launcher3.logging.StatsLogManager.getLauncherAtomEvent;
@@ -451,9 +452,11 @@
                 .withSrcState(LAUNCHER_STATE_HOME)
                 .withDstState(targetState.statsLogOrdinal)
                 .log(getLauncherAtomEvent(mStartState.statsLogOrdinal, targetState.statsLogOrdinal,
-                        targetState.ordinal > mStartState.ordinal
-                                ? LAUNCHER_UNKNOWN_SWIPEUP
-                                : LAUNCHER_UNKNOWN_SWIPEDOWN));
+                        targetState == QUICK_SWITCH
+                                ? LAUNCHER_QUICKSWITCH_RIGHT
+                                : targetState.ordinal > mStartState.ordinal
+                                        ? LAUNCHER_UNKNOWN_SWIPEUP
+                                        : LAUNCHER_UNKNOWN_SWIPEDOWN));
         mLauncher.getStateManager().goToState(targetState, false, forEndCallback(this::clearState));
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 27a55c3..dbee9c1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -21,10 +21,9 @@
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
 import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
 
@@ -131,10 +130,10 @@
         boolean isTablet = mLauncher.getDeviceProfile().isTablet;
         builder.setInterpolator(ANIM_ALL_APPS_FADE, isTablet
                 ? INSTANT
-                : Interpolators.clampToProgress(ACCEL,
+                : Interpolators.clampToProgress(LINEAR,
                         ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD,
                         ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD));
-        builder.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(ACCEL,
+        builder.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(LINEAR,
                 ALL_APPS_SCRIM_VISIBLE_THRESHOLD,
                 ALL_APPS_SCRIM_OPAQUE_THRESHOLD));
         return builder;
@@ -145,10 +144,10 @@
         boolean isTablet = mLauncher.getDeviceProfile().isTablet;
         builder.setInterpolator(ANIM_ALL_APPS_FADE, isTablet
                 ? FINAL_FRAME
-                : Interpolators.clampToProgress(DEACCEL,
+                : Interpolators.clampToProgress(LINEAR,
                         1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
                         1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD));
-        builder.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(DEACCEL,
+        builder.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(LINEAR,
                 1 - ALL_APPS_SCRIM_OPAQUE_THRESHOLD,
                 1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD));
         return builder;
@@ -262,7 +261,7 @@
 
     @Override
     protected void onReachedFinalState(LauncherState toState) {
-        super.onReinitToState(toState);
+        super.onReachedFinalState(toState);
         if (toState == ALL_APPS) {
             InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
         }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index b90e820..f60b225 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -22,6 +22,7 @@
 
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
+import static com.android.launcher3.PagedView.INVALID_PAGE;
 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.anim.Interpolators.DEACCEL;
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
@@ -66,6 +67,7 @@
 import android.os.Build;
 import android.os.IBinder;
 import android.os.SystemClock;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnApplyWindowInsetsListener;
@@ -163,7 +165,11 @@
                     if (mActivity != activity) {
                         return;
                     }
+                    if (mTaskAnimationManager != null) {
+                        mTaskAnimationManager.finishRunningRecentsAnimation(true);
+                    }
                     mRecentsView = null;
+                    mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
                     mActivity = null;
                 }
             };
@@ -922,7 +928,13 @@
             mLogDirectionUpOrLeft = velocity.x < 0;
         }
         mDownPos = downPos;
-        handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */);
+        Runnable handleNormalGestureEndCallback = () ->
+                handleNormalGestureEnd(endVelocity, isFling, velocity, /* isCancel= */ false);
+        if (mRecentsView != null) {
+            mRecentsView.runOnPageScrollsInitialized(handleNormalGestureEndCallback);
+        } else {
+            handleNormalGestureEndCallback.run();
+        }
     }
 
     private void endRunningWindowAnim(boolean cancel) {
@@ -1126,6 +1138,13 @@
         } else if (endTarget == RECENTS) {
             if (mRecentsView != null) {
                 int nearestPage = mRecentsView.getDestinationPage();
+                if (nearestPage == INVALID_PAGE) {
+                    // Allow the snap to invalid page to catch future error cases.
+                    Log.e(TAG,
+                            "RecentsView destination page is invalid",
+                            new IllegalStateException());
+                }
+
                 boolean isScrolling = false;
                 if (mRecentsView.getNextPage() != nearestPage) {
                     // We shouldn't really scroll to the next page when swiping up to recents.
@@ -1158,6 +1177,11 @@
     }
 
     private void doLogGesture(GestureEndTarget endTarget, @Nullable TaskView targetTask) {
+        if (mDp == null || !mDp.isGestureMode || mDownPos == null) {
+            // We probably never received an animation controller, skip logging.
+            return;
+        }
+
         StatsLogManager.EventEnum event;
         switch (endTarget) {
             case HOME:
@@ -1181,11 +1205,6 @@
             logger.withItemInfo(targetTask.getItemInfo());
         }
 
-        DeviceProfile dp = mDp;
-        if (dp == null || mDownPos == null) {
-            // We probably never received an animation controller, skip logging.
-            return;
-        }
         int pageIndex = endTarget == LAST_TASK || mRecentsView == null
                 ? LOG_NO_OP_PAGE_INDEX
                 : mRecentsView.getNextPage();
@@ -1571,9 +1590,6 @@
 
     private void reset() {
         mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
-        if (mActivity != null) {
-            mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
-        }
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 9686510..6745246 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -19,7 +19,6 @@
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.util.DisplayController.getNavigationMode;
 import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
 import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
@@ -62,7 +61,6 @@
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.SplitScreenBounds;
-import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -86,6 +84,8 @@
 
     private STATE_TYPE mTargetState;
 
+    @Nullable private Runnable mOnInitBackgroundStateUICallback = null;
+
     protected BaseActivityInterface(boolean rotationSupportedByActivity,
             STATE_TYPE overviewState, STATE_TYPE backgroundState) {
         this.rotationSupportedByActivity = rotationSupportedByActivity;
@@ -224,7 +224,7 @@
         Resources res = context.getResources();
         if (dp.isTablet) {
             Rect gridRect = new Rect();
-            calculateGridSize(context, dp, gridRect);
+            calculateGridSize(dp, gridRect);
 
             PointF taskDimension = getTaskDimension(context, dp);
             float scale = gridRect.height() / taskDimension.y;
@@ -238,15 +238,15 @@
             int taskMargin = dp.overviewTaskMarginPx;
             calculateTaskSizeInternal(context, dp,
                     dp.overviewTaskThumbnailTopMarginPx,
-                    getOverviewActionsHeight(context, dp),
+                    dp.getOverviewActionsClaimedSpace(),
                     res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
+                    Gravity.CENTER,
                     outRect);
         }
     }
 
-    private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
-            int claimedSpaceAbove, int claimedSpaceBelow, int minimumHorizontalPadding,
-            Rect outRect) {
+    private void calculateTaskSizeInternal(Context context, DeviceProfile dp, int claimedSpaceAbove,
+            int claimedSpaceBelow, int minimumHorizontalPadding, int gravity, Rect outRect) {
         PointF taskDimension = getTaskDimension(context, dp);
         Rect insets = dp.getInsets();
 
@@ -264,7 +264,7 @@
         int outWidth = Math.round(scale * taskDimension.x);
         int outHeight = Math.round(scale * taskDimension.y);
 
-        Gravity.apply(Gravity.CENTER, outWidth, outHeight, potentialTaskRect, outRect);
+        Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect);
     }
 
     private static PointF getTaskDimension(Context context, DeviceProfile dp) {
@@ -314,10 +314,10 @@
     /**
      * Calculates the overview grid size for the provided device configuration.
      */
-    public final void calculateGridSize(Context context, DeviceProfile dp, Rect outRect) {
+    public final void calculateGridSize(DeviceProfile dp, Rect outRect) {
         Rect insets = dp.getInsets();
         int topMargin = dp.overviewTaskThumbnailTopMarginPx;
-        int bottomMargin = getOverviewActionsHeight(context, dp);
+        int bottomMargin = dp.getOverviewActionsClaimedSpace();
         int sideMargin = dp.overviewGridSideMargin;
 
         outRect.set(0, 0, dp.widthPx, dp.heightPx);
@@ -352,21 +352,17 @@
      * Calculates the modal taskView size for the provided device configuration
      */
     public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+        calculateTaskSize(context, dp, outRect);
+        float maxScale = context.getResources().getFloat(R.dimen.overview_modal_max_scale);
         calculateTaskSizeInternal(
                 context, dp,
                 dp.overviewTaskMarginPx,
-                getOverviewActionsHeight(context, dp),
-                dp.overviewTaskMarginPx,
+                dp.heightPx - outRect.bottom - dp.getInsets().bottom,
+                Math.round((dp.availableWidthPx - outRect.width() * maxScale) / 2),
+                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
                 outRect);
     }
 
-    /** Gets the space that the overview actions will take, including bottom margin. */
-    private int getOverviewActionsHeight(Context context, DeviceProfile dp) {
-        return OverviewActionsView.getOverviewActionsBottomMarginPx(getNavigationMode(context), dp)
-                + OverviewActionsView.getOverviewActionsTopMarginPx(getNavigationMode(context), dp)
-                + dp.overviewActionsHeight;
-    }
-
     /**
      * Called when the gesture ends and the animation starts towards the given target. Used to add
      * an optional additional animation with the same duration.
@@ -414,6 +410,21 @@
         return null;
     }
 
+    protected void runOnInitBackgroundStateUI(Runnable callback) {
+        mOnInitBackgroundStateUICallback = callback;
+        ACTIVITY_TYPE activity = getCreatedActivity();
+        if (activity != null && activity.getStateManager().getState() == mBackgroundState) {
+            onInitBackgroundStateUI();
+        }
+    }
+
+    private void onInitBackgroundStateUI() {
+        if (mOnInitBackgroundStateUICallback != null) {
+            mOnInitBackgroundStateUICallback.run();
+            mOnInitBackgroundStateUICallback = null;
+        }
+    }
+
     public interface AnimationFactory {
 
         void createActivityInterface(long transitionLength);
@@ -453,13 +464,14 @@
             mStartState = mActivity.getStateManager().getState();
         }
 
-        protected ACTIVITY_TYPE initUI() {
+        protected ACTIVITY_TYPE initBackgroundStateUI() {
             STATE_TYPE resetState = mStartState;
             if (mStartState.shouldDisableRestore()) {
                 resetState = mActivity.getStateManager().getRestState();
             }
             mActivity.getStateManager().setRestState(resetState);
             mActivity.getStateManager().goToState(mBackgroundState, false);
+            onInitBackgroundStateUI();
             return mActivity;
         }
 
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 7feec2c..ba61574 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -89,7 +89,7 @@
             boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback) {
         notifyRecentsOfOrientation(deviceState.getRotationTouchHelper());
         DefaultAnimationFactory factory = new DefaultAnimationFactory(callback);
-        factory.initUI();
+        factory.initBackgroundStateUI();
         return factory;
     }
 
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 10a3a2e..c13b95f 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -135,7 +135,7 @@
             }
         };
 
-        BaseQuickstepLauncher launcher = factory.initUI();
+        BaseQuickstepLauncher launcher = factory.initBackgroundStateUI();
         // Since all apps is not visible, we can safely reset the scroll position.
         // This ensures then the next swipe up to all-apps starts from scroll 0.
         launcher.getAppsView().reset(false /* animate */);
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 921674a..fd9f922 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -16,6 +16,7 @@
 
 package com.android.quickstep;
 
+import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
 import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
 import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
@@ -29,7 +30,6 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Handler;
-import android.util.MathUtils;
 import android.util.Pair;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
@@ -38,6 +38,7 @@
 import android.window.BackEvent;
 import android.window.IOnBackInvokedCallback;
 
+import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.R;
@@ -46,6 +47,7 @@
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
+
 /**
  * Controls the animation of swiping back and returning to launcher.
  *
@@ -88,6 +90,7 @@
     private boolean mAnimatorSetInProgress = false;
     private float mBackProgress = 0;
     private boolean mBackInProgress = false;
+    private IOnBackInvokedCallback mBackCallback;
 
     public LauncherBackAnimationController(
             BaseQuickstepLauncher launcher,
@@ -113,34 +116,35 @@
      * @param handler Handler to the thread to run the animations on.
      */
     public void registerBackCallbacks(Handler handler) {
-        SystemUiProxy.INSTANCE.get(mLauncher).setBackToLauncherCallback(
-                new IOnBackInvokedCallback.Stub() {
-                    @Override
-                    public void onBackCancelled() {
-                        handler.post(() -> resetPositionAnimated());
-                    }
+        mBackCallback = new IOnBackInvokedCallback.Stub() {
+            @Override
+            public void onBackCancelled() {
+                handler.post(() -> resetPositionAnimated());
+            }
 
-                    @Override
-                    public void onBackInvoked() {
-                        handler.post(() -> startTransition());
-                    }
+            @Override
+            public void onBackInvoked() {
+                handler.post(() -> startTransition());
+            }
 
-                    @Override
-                    public void onBackProgressed(BackEvent backEvent) {
-                        mBackProgress = backEvent.getProgress();
-                        // TODO: Update once the interpolation curve spec is finalized.
-                        mBackProgress =
-                                1 - (1 - mBackProgress) * (1 - mBackProgress) * (1
-                                        - mBackProgress);
-                        if (!mBackInProgress) {
-                            startBack(backEvent);
-                        } else {
-                            updateBackProgress(mBackProgress, backEvent);
-                        }
-                    }
+            @Override
+            public void onBackProgressed(BackEvent backEvent) {
+                mBackProgress = backEvent.getProgress();
+                // TODO: Update once the interpolation curve spec is finalized.
+                mBackProgress =
+                        1 - (1 - mBackProgress) * (1 - mBackProgress) * (1
+                                - mBackProgress);
+                if (!mBackInProgress) {
+                    startBack(backEvent);
+                } else {
+                    updateBackProgress(mBackProgress, backEvent);
+                }
+            }
 
-                    public void onBackStarted() { }
-                });
+            @Override
+            public void onBackStarted() { }
+        };
+        SystemUiProxy.INSTANCE.get(mLauncher).setBackToLauncherCallback(mBackCallback);
     }
 
     private void resetPositionAnimated() {
@@ -163,7 +167,10 @@
 
     /** Unregisters the back to launcher callback in shell. */
     public void unregisterBackCallbacks() {
-        SystemUiProxy.INSTANCE.get(mLauncher).clearBackToLauncherCallback();
+        if (mBackCallback != null) {
+            SystemUiProxy.INSTANCE.get(mLauncher).clearBackToLauncherCallback(mBackCallback);
+        }
+        mBackCallback = null;
     }
 
     private void startBack(BackEvent backEvent) {
@@ -195,10 +202,10 @@
         float followWidth = screenWidth - dX;
         // The 'progress width' is the width of the window if it strictly linearly interpolates
         // to minimum scale base on progress.
-        float progressWidth = MathUtils.lerp(1, MIN_WINDOW_SCALE, progress) * screenWidth;
+        float progressWidth = Utilities.mapRange(progress, 1, MIN_WINDOW_SCALE) * screenWidth;
         // The final width is derived from interpolating between the follow with and progress width
         // using gesture progress.
-        float width = MathUtils.lerp(followWidth, progressWidth, progress);
+        float width = Utilities.mapRange(progress, followWidth, progressWidth);
         float height = screenHeight / screenWidth * width;
         float deltaYRatio = (event.getTouchY() - mInitialTouchPos.y) / screenHeight;
         // Base the window movement in the Y axis on the touch movement in the Y axis.
@@ -221,13 +228,15 @@
             return;
         }
         mCurrentRect.set(
-                MathUtils.lerp(mCancelRect.left, mStartRect.left, progress),
-                MathUtils.lerp(mCancelRect.top, mStartRect.top, progress),
-                MathUtils.lerp(mCancelRect.right, mStartRect.right, progress),
-                MathUtils.lerp(mCancelRect.bottom, mStartRect.bottom, progress));
+                Utilities.mapRange(progress, mCancelRect.left, mStartRect.left),
+                Utilities.mapRange(progress, mCancelRect.top, mStartRect.top),
+                Utilities.mapRange(progress, mCancelRect.right, mStartRect.right),
+                Utilities.mapRange(progress, mCancelRect.bottom, mStartRect.bottom));
 
+        float endCornerRadius = Utilities.mapRange(
+                mBackProgress, mWindowScaleStartCornerRadius, mWindowScaleEndCornerRadius);
         float cornerRadius = Utilities.mapRange(
-                progress, mWindowScaleEndCornerRadius, mWindowScaleStartCornerRadius);
+                progress, endCornerRadius, mWindowScaleStartCornerRadius);
         applyTransform(mCurrentRect, cornerRadius);
     }
 
@@ -267,12 +276,19 @@
             mLauncher.getStateManager().moveToRestState();
         }
 
+        // Explicitly close opened floating views (which is typically called from
+        // Launcher#onResumed, but in the predictive back flow launcher is not resumed until
+        // the transition is fully finished.)
+        AbstractFloatingView.closeAllOpenViewsExcept(mLauncher, false, TYPE_REBIND_SAFE);
+        float cornerRadius = Utilities.mapRange(
+                mBackProgress, mWindowScaleStartCornerRadius, mWindowScaleEndCornerRadius);
         Pair<RectFSpringAnim, AnimatorSet> pair =
                 mQuickstepTransitionManager.createWallpaperOpenAnimations(
                     new RemoteAnimationTargetCompat[]{mBackTarget},
                     new RemoteAnimationTargetCompat[]{},
                     false /* fromUnlock */,
-                    mCurrentRect);
+                    mCurrentRect,
+                    cornerRadius);
         startTransitionAnimations(pair.first, pair.second);
         mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
     }
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 42f9eb6..dffdc5a 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -217,7 +217,8 @@
             @Override
             public void onRecentsAnimationStart(RecentsAnimationController controller,
                     RecentsAnimationTargets targets) {
-                interactionHandler.onGestureEnded(0, new PointF(), new PointF());
+                activityInterface.runOnInitBackgroundStateUI(() ->
+                        interactionHandler.onGestureEnded(0, new PointF(), new PointF()));
                 cmd.removeListener(this);
             }
 
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index ef81449..528fb97 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -66,6 +66,12 @@
                         mDeviceProfile.overviewPageSpacing);
                 return response;
             }
+
+            case TestProtocol.REQUEST_HAS_TIS: {
+                response.putBoolean(
+                        TestProtocol.REQUEST_HAS_TIS, true);
+                return response;
+            }
         }
 
         return super.call(method, arg, extras);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index fe31f1d..51ae56b 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -104,8 +104,7 @@
                 .map(RemoteAnimationTargetCompat::unwrap)
                 .toArray(RemoteAnimationTarget[]::new);
 
-        RemoteAnimationTarget[] nonAppTargets =
-                mSystemUiProxy.onGoingToRecentsLegacy(mCancelled, nonHomeApps);
+        RemoteAnimationTarget[] nonAppTargets = mSystemUiProxy.onGoingToRecentsLegacy(nonHomeApps);
 
         RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets,
                 wallpaperTargets, RemoteAnimationTargetCompat.wrap(nonAppTargets),
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 5ef89d3..39d8b54 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -676,14 +676,12 @@
      * Call this when going to recents so that shell can set-up and provide appropriate leashes
      * for animation (eg. DividerBar).
      *
-     * @param cancel true if recents starting is being cancelled.
      * @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
      */
-    public RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel,
-            RemoteAnimationTarget[] apps) {
+    public RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
         if (mSplitScreen != null) {
             try {
-                return mSplitScreen.onGoingToRecentsLegacy(cancel, apps);
+                return mSplitScreen.onGoingToRecentsLegacy(apps);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call onGoingToRecentsLegacy");
             }
@@ -691,6 +689,17 @@
         return null;
     }
 
+    public RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
+        if (mSplitScreen != null) {
+            try {
+                return mSplitScreen.onStartingSplitLegacy(apps);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call onStartingSplitLegacy");
+            }
+        }
+        return null;
+    }
+
     //
     // One handed
     //
@@ -847,8 +856,14 @@
         }
     }
 
-    /** Clears the previously registered {@link IOnBackInvokedCallback}. */
-    public void clearBackToLauncherCallback() {
+    /** Clears the previously registered {@link IOnBackInvokedCallback}.
+     *
+     * @param callback The previously registered callback instance.
+     */
+    public void clearBackToLauncherCallback(IOnBackInvokedCallback callback) {
+        if (mBackToLauncherCallback != callback) {
+            return;
+        }
         mBackToLauncherCallback = null;
         if (mBackAnimation == null) {
             return;
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index f094d71..54f457d 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -177,8 +177,9 @@
                     ((RecentsActivity) activityInterface.getCreatedActivity()).startHome();
                     return;
                 }
-                RemoteAnimationTarget[] nonAppTargets = SystemUiProxy.INSTANCE.get(mCtx)
-                        .onGoingToRecentsLegacy(false, nonHomeApps);
+
+                RemoteAnimationTarget[] nonAppTargets =
+                        SystemUiProxy.INSTANCE.getNoCreate().onStartingSplitLegacy(nonHomeApps);
 
                 if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode()
                         && activityInterface.getCreatedActivity() != null) {
@@ -191,6 +192,10 @@
                                 RemoteAnimationTargetCompat.wrap(nonAppTargets) /* nonApps */);
                         return;
                     }
+                } else if (nonAppTargets != null && nonAppTargets.length > 0) {
+                    TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
+                            RemoteAnimationTargetCompat.wrap(nonAppTargets) /* nonApps */,
+                            true /*shown*/, dividerAnimator -> dividerAnimator.start());
                 }
                 if (mController != null) {
                     if (mLastAppearedTaskTarget == null
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index d94e5f1..3ef1332 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -46,6 +46,7 @@
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.ResourceBasedOverride;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.launcher3.views.ActivityContext;
 import com.android.quickstep.TaskShortcutFactory.SplitSelectSystemShortcut;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.views.OverviewActionsView;
@@ -314,12 +315,21 @@
         }
 
         protected void showBlockedByPolicyMessage() {
+            ActivityContext activityContext = ActivityContext.lookupContext(
+                    mThumbnailView.getContext());
+            String message = activityContext.getStringCache() != null
+                    ? activityContext.getStringCache().disabledByAdminMessage
+                    : mThumbnailView.getContext().getString(R.string.blocked_by_policy);
             Toast.makeText(
                     mThumbnailView.getContext(),
-                    R.string.blocked_by_policy,
+                    message,
                     Toast.LENGTH_LONG).show();
         }
 
+        /** Called when the snapshot has updated its full screen drawing parameters. */
+        public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) {
+        }
+
         private class ScreenshotSystemShortcut extends SystemShortcut {
 
             private final BaseDraggingActivity mActivity;
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 29f2123..6179b81 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -38,7 +38,6 @@
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
 import static com.android.launcher3.statehandlers.DepthController.DEPTH;
 import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
 
@@ -501,7 +500,7 @@
         }
 
         for (int i = 0; i < nonAppTargets.length; ++i) {
-            final SurfaceControl leash = appTargets[i].leash;
+            final SurfaceControl leash = nonAppTargets[i].leash;
             if (nonAppTargets[i].windowType == TYPE_DOCK_DIVIDER && leash != null) {
                 openingTargets.add(leash);
             }
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 5094d49..f68bbbc 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -112,7 +112,7 @@
         RecentsState currentState = mActivity.getStateManager().getState();
         if (isSplitSelectionState(state) && !isSplitSelectionState(currentState)) {
             setter.add(mRecentsView.createSplitSelectInitAnimation(
-                    state.getTransitionDuration(mActivity)).buildAnim());
+                    state.getTransitionDuration(mActivity, true /* isToState */)).buildAnim());
         }
 
         Pair<FloatProperty, FloatProperty> taskViewsFloat =
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index c9ee2db..3e68c7f 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -221,6 +221,9 @@
         setOverviewStateEnabled(true);
         setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
         setOverviewFullscreenEnabled(toState.isFullScreen());
+        if (toState == MODAL_TASK) {
+            setOverviewSelectEnabled(true);
+        }
         Log.d(BAD_STATE, "FRV onStateTransitionStart setFreezeVisibility=true, toState=" + toState);
         setFreezeViewVisibility(true);
     }
@@ -236,6 +239,9 @@
         Log.d(BAD_STATE, "FRV onStateTransitionComplete setFreezeVisibility=false, finalState="
                 + finalState);
         setFreezeViewVisibility(false);
+        if (finalState != MODAL_TASK) {
+            setOverviewSelectEnabled(false);
+        }
 
         if (isOverlayEnabled) {
             runActionOnRemoteHandles(remoteTargetHandle ->
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index 9705bb6..77db6b7 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -77,7 +77,7 @@
     }
 
     @Override
-    public int getTransitionDuration(Context context) {
+    public int getTransitionDuration(Context context, boolean isToState) {
         return 250;
     }
 
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 9ba5577..35d9f22 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -33,17 +33,22 @@
     }
 
     @Override
-    public Integer getIntroductionTitle() {
+    public int getIntroductionTitle() {
         return R.string.back_gesture_intro_title;
     }
 
     @Override
-    public Integer getIntroductionSubtitle() {
+    public int getIntroductionSubtitle() {
         return R.string.back_gesture_intro_subtitle;
     }
 
     @Override
-    public Integer getSuccessFeedbackSubtitle() {
+    public int getSpokenIntroductionSubtitle() {
+        return R.string.back_gesture_spoken_intro_subtitle;
+    }
+
+    @Override
+    public int getSuccessFeedbackSubtitle() {
         return mTutorialFragment.isAtFinalStep()
                 ? R.string.back_gesture_feedback_complete_without_follow_up
                 : R.string.back_gesture_feedback_complete_with_overview_follow_up;
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index 6254313..f519d50 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -32,17 +32,22 @@
     }
 
     @Override
-    public Integer getIntroductionTitle() {
+    public int getIntroductionTitle() {
         return R.string.home_gesture_intro_title;
     }
 
     @Override
-    public Integer getIntroductionSubtitle() {
+    public int getIntroductionSubtitle() {
         return R.string.home_gesture_intro_subtitle;
     }
 
     @Override
-    public Integer getSuccessFeedbackSubtitle() {
+    public int getSpokenIntroductionSubtitle() {
+        return R.string.home_gesture_spoken_intro_subtitle;
+    }
+
+    @Override
+    public int getSuccessFeedbackSubtitle() {
         return mTutorialFragment.isAtFinalStep()
                 ? R.string.home_gesture_feedback_complete_without_follow_up
                 : R.string.home_gesture_feedback_complete_with_follow_up;
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 09640c6..6b016ce 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -42,17 +42,22 @@
     }
 
     @Override
-    public Integer getIntroductionTitle() {
+    public int getIntroductionTitle() {
         return R.string.overview_gesture_intro_title;
     }
 
     @Override
-    public Integer getIntroductionSubtitle() {
+    public int getIntroductionSubtitle() {
         return R.string.overview_gesture_intro_subtitle;
     }
 
     @Override
-    public Integer getSuccessFeedbackSubtitle() {
+    public int getSpokenIntroductionSubtitle() {
+        return R.string.overview_gesture_spoken_intro_subtitle;
+    }
+
+    @Override
+    public int getSuccessFeedbackSubtitle() {
         return mTutorialFragment.getNumSteps() > 1 && mTutorialFragment.isAtFinalStep()
                 ? R.string.overview_gesture_feedback_complete_with_follow_up
                 : R.string.overview_gesture_feedback_complete_without_follow_up;
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 6a8894e..fa7d848 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -62,7 +62,7 @@
 abstract class TutorialController implements BackGestureAttemptCallback,
         NavBarGestureAttemptCallback {
 
-    private static final String TAG = "TutorialController";
+    private static final String LOG_TAG = "TutorialController";
 
     private static final float FINGER_DOT_VISIBLE_ALPHA = 0.7f;
     private static final float FINGER_DOT_SMALL_SCALE = 0.7f;
@@ -217,18 +217,23 @@
     }
 
     @StringRes
-    public Integer getIntroductionTitle() {
-        return null;
+    public int getIntroductionTitle() {
+        return NO_ID;
     }
 
     @StringRes
-    public Integer getIntroductionSubtitle() {
-        return null;
+    public int getIntroductionSubtitle() {
+        return NO_ID;
     }
 
     @StringRes
-    public Integer getSuccessFeedbackSubtitle() {
-        return null;
+    public int getSpokenIntroductionSubtitle() {
+        return NO_ID;
+    }
+
+    @StringRes
+    public int getSuccessFeedbackSubtitle() {
+        return NO_ID;
     }
 
     void showFeedback() {
@@ -247,7 +252,16 @@
      * Show feedback reflecting a successful gesture attempt.
      **/
     void showSuccessFeedback() {
-        showFeedback(getSuccessFeedbackSubtitle(), true);
+        int successSubtitleResId = getSuccessFeedbackSubtitle();
+        if (successSubtitleResId == NO_ID) {
+            // Allow crash since this should never be reached with a tutorial controller used in
+            // production.
+            Log.e(LOG_TAG,
+                    "Cannot show success feedback for tutorial step: " + mTutorialType
+                            + ", no success feedback subtitle",
+                    new IllegalStateException());
+        }
+        showFeedback(successSubtitleResId, true);
     }
 
     /**
@@ -269,6 +283,7 @@
                 isGestureSuccessful
                         ? R.string.gesture_tutorial_nice : R.string.gesture_tutorial_try_again,
                 subtitleResId,
+                NO_ID,
                 isGestureSuccessful,
                 false);
     }
@@ -276,6 +291,7 @@
     void showFeedback(
             int titleResId,
             int subtitleResId,
+            int spokenSubtitleResId,
             boolean isGestureSuccessful,
             boolean useGestureAnimationDelay) {
         mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
@@ -287,7 +303,10 @@
         mFeedbackTitleView.setText(titleResId);
         TextView subtitle =
                 mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle);
-        subtitle.setText(subtitleResId);
+        subtitle.setText(spokenSubtitleResId == NO_ID
+                ? mContext.getText(subtitleResId)
+                : Utilities.wrapForTts(
+                        mContext.getText(subtitleResId), mContext.getString(spokenSubtitleResId)));
         if (isGestureSuccessful) {
             if (mTutorialFragment.isAtFinalStep()) {
                 showActionButton();
@@ -580,7 +599,7 @@
                         packageManager.getApplicationInfo(
                                 PIXEL_TIPS_APP_PACKAGE_NAME, PackageManager.GET_META_DATA));
             } catch (PackageManager.NameNotFoundException e) {
-                Log.e(TAG,
+                Log.e(LOG_TAG,
                         "Could not find app label for package name: "
                                 + PIXEL_TIPS_APP_PACKAGE_NAME
                                 + ". Defaulting to 'Pixel Tips.'",
@@ -593,7 +612,7 @@
                 subtitleTextView.setText(
                         mContext.getString(R.string.skip_tutorial_dialog_subtitle, tipsAppName));
             } else {
-                Log.w(TAG, "No subtitle view in the skip tutorial dialog to update.");
+                Log.w(LOG_TAG, "No subtitle view in the skip tutorial dialog to update.");
             }
 
             Button cancelButton = (Button) contentView.findViewById(
@@ -602,7 +621,7 @@
                 cancelButton.setOnClickListener(
                         v -> tutorialDialog.dismiss());
             } else {
-                Log.w(TAG, "No cancel button in the skip tutorial dialog to update.");
+                Log.w(LOG_TAG, "No cancel button in the skip tutorial dialog to update.");
             }
 
             Button confirmButton = contentView.findViewById(
@@ -613,7 +632,7 @@
                     tutorialDialog.dismiss();
                 });
             } else {
-                Log.w(TAG, "No confirm button in the skip tutorial dialog to update.");
+                Log.w(LOG_TAG, "No confirm button in the skip tutorial dialog to update.");
             }
 
             tutorialDialog.getWindow().setBackgroundDrawable(
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 33e800d..1599c8c 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -15,6 +15,8 @@
  */
 package com.android.quickstep.interaction;
 
+import static android.view.View.NO_ID;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.app.Activity;
@@ -211,13 +213,31 @@
         if (isGestureComplete()) {
             mTutorialController.showSuccessFeedback();
         } else if (!mIntroductionShown) {
-            Integer introTileStringResId = mTutorialController.getIntroductionTitle();
-            Integer introSubtitleResId = mTutorialController.getIntroductionSubtitle();
-            if (introTileStringResId != null && introSubtitleResId != null) {
-                mTutorialController.showFeedback(
-                        introTileStringResId, introSubtitleResId, false, true);
-                mIntroductionShown = true;
+            int introTitleResId = mTutorialController.getIntroductionTitle();
+            int introSubtitleResId = mTutorialController.getIntroductionSubtitle();
+            if (introTitleResId == NO_ID) {
+                // Allow crash since this should never be reached with a tutorial controller used in
+                // production.
+                Log.e(LOG_TAG,
+                        "Cannot show introduction feedback for tutorial step: " + mTutorialType
+                                + ", no introduction feedback title",
+                        new IllegalStateException());
             }
+            if (introTitleResId == NO_ID) {
+                // Allow crash since this should never be reached with a tutorial controller used in
+                // production.
+                Log.e(LOG_TAG,
+                        "Cannot show introduction feedback for tutorial step: " + mTutorialType
+                                + ", no introduction feedback subtitle",
+                        new IllegalStateException());
+            }
+            mTutorialController.showFeedback(
+                    introTitleResId,
+                    introSubtitleResId,
+                    mTutorialController.getSpokenIntroductionSubtitle(),
+                    false,
+                    true);
+            mIntroductionShown = true;
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 10c56c9..85ef6cb 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -130,7 +130,7 @@
         if (IS_VERBOSE) {
             Log.d(TAG, String.format("\nwriteSnapshot(%d):\n%s", instanceId.getId(), info));
         }
-        if (!Utilities.ATLEAST_R) {
+        if (!Utilities.ATLEAST_R || Utilities.IS_RUNNING_IN_TEST_HARNESS) {
             return;
         }
         SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_SNAPSHOT,
@@ -415,6 +415,10 @@
                 consumer.consume(event, atomInfo);
             }
 
+            // TODO: remove this when b/231648228 is fixed.
+            if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+                return;
+            }
             SysUiStatsLog.write(
                     SysUiStatsLog.LAUNCHER_EVENT,
                     SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */,
@@ -510,6 +514,9 @@
     }
 
     private static int getCardinality(LauncherAtom.ItemInfo info) {
+        if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+            return 0;
+        }
         switch (info.getContainerInfo().getContainerCase()) {
             case PREDICTED_HOTSEAT_CONTAINER:
                 return info.getContainerInfo().getPredictedHotseatContainer().getCardinality();
@@ -625,6 +632,9 @@
     }
 
     private static int getHierarchy(LauncherAtom.ItemInfo info) {
+        if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+            return 0;
+        }
         if (info.getContainerInfo().getContainerCase() == FOLDER) {
             return info.getContainerInfo().getFolder().getParentContainerCase().getNumber()
                     + FOLDER_HIERARCHY_OFFSET;
@@ -665,6 +675,9 @@
     }
 
     private static int getSearchAttributes(LauncherAtom.ItemInfo info) {
+        if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+            return 0;
+        }
         ContainerInfo containerInfo = info.getContainerInfo();
         if (containerInfo.getContainerCase() == EXTENDED_CONTAINERS
                 && containerInfo.getExtendedContainers().getContainerCase()
diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index 5cf4f0b..3cec1a4 100644
--- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -82,7 +82,7 @@
             // WorkspaceRevealAnim handles the depth, so don't interfere.
             config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
         }
-        config.duration = startState.getTransitionDuration(mLauncher);
+        config.duration = startState.getTransitionDuration(mLauncher, false /* isToState */);
         AnimatorSet stateAnim = stateManager.createAtomicAnimation(
                 startState, NORMAL, config);
         stateAnim.addListener(new AnimationSuccessListener() {
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index 54420de..c980d1e 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -196,6 +196,13 @@
                     0, 1, ACCEL);
             animation.addFloat(mThumbnailView, LauncherAnimUtils.VIEW_ALPHA,
                     1, 0, DEACCEL_3);
+        } else if (isStagedTask) {
+            // Fade in the placeholder view when split is initiated from homescreen / all apps
+            // icons.
+            if (mSplitPlaceholderView.getAlpha() == 0) {
+                animation.addFloat(mSplitPlaceholderView, SplitPlaceholderView.ALPHA_FLOAT,
+                        0.3f, 1, ACCEL);
+            }
         }
 
         MultiValueUpdateListener listener = new MultiValueUpdateListener() {
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 45aaf35..306ebd7 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -100,6 +100,9 @@
         setOverviewStateEnabled(toState.overviewUi);
         setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
         setOverviewFullscreenEnabled(toState.getOverviewFullscreenProgress() == 1);
+        if (toState == OVERVIEW_MODAL_TASK) {
+            setOverviewSelectEnabled(true);
+        }
         Log.d(BAD_STATE, "LRV onStateTransitionStart setFreezeVisibility=true, toState=" + toState);
         setFreezeViewVisibility(true);
     }
@@ -115,6 +118,9 @@
         Log.d(BAD_STATE, "LRV onStateTransitionComplete setFreezeVisibility=false, finalState="
                 + finalState);
         setFreezeViewVisibility(false);
+        if (finalState != OVERVIEW_MODAL_TASK) {
+            setOverviewSelectEnabled(false);
+        }
 
         if (isOverlayEnabled) {
             runActionOnRemoteHandles(remoteTargetHandle ->
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 99a2d6f..1c4e497 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -16,8 +16,6 @@
 
 package com.android.quickstep.views;
 
-import static com.android.launcher3.util.DisplayController.NavigationMode.THREE_BUTTONS;
-
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -58,7 +56,6 @@
             HIDDEN_NON_ZERO_ROTATION,
             HIDDEN_NO_TASKS,
             HIDDEN_NO_RECENTS,
-            HIDDEN_FOCUSED_SCROLL,
             HIDDEN_SPLIT_SCREEN})
     @Retention(RetentionPolicy.SOURCE)
     public @interface ActionsHiddenFlags { }
@@ -66,8 +63,7 @@
     public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 0;
     public static final int HIDDEN_NO_TASKS = 1 << 1;
     public static final int HIDDEN_NO_RECENTS = 1 << 2;
-    public static final int HIDDEN_FOCUSED_SCROLL = 1 << 3;
-    public static final int HIDDEN_SPLIT_SCREEN = 1 << 4;
+    public static final int HIDDEN_SPLIT_SCREEN = 1 << 3;
 
     @IntDef(flag = true, value = {
             DISABLED_SCROLLING,
@@ -99,6 +95,7 @@
 
     @Nullable
     protected DeviceProfile mDp;
+    private final Rect mTaskSize = new Rect();
 
     public OverviewActionsView(Context context) {
         this(context, null);
@@ -202,8 +199,10 @@
      * Offsets OverviewActionsView horizontal position based on 3 button nav container in taskbar.
      */
     private void updatePadding() {
-        boolean alignFor3ButtonTaskbar = mDp.isTaskbarPresent &&
-                DisplayController.getNavigationMode(getContext()) == THREE_BUTTONS;
+        if (mDp == null) {
+            return;
+        }
+        boolean alignFor3ButtonTaskbar = mDp.isTaskbarPresent && !mDp.isGestureMode;
         if (alignFor3ButtonTaskbar) {
             // Add extra horizontal spacing
             int additionalPadding = ApiWrapper.getHotseatEndOffset(getContext());
@@ -225,15 +224,34 @@
         LayoutParams actionParams = (LayoutParams) findViewById(
                 R.id.action_buttons).getLayoutParams();
         actionParams.setMargins(
-                actionParams.leftMargin, getOverviewActionsTopMarginPx(mode, mDp),
-                actionParams.rightMargin, getOverviewActionsBottomMarginPx(mode, mDp));
+                actionParams.leftMargin, mDp.overviewActionsTopMarginPx,
+                actionParams.rightMargin, getBottomMargin());
+    }
+
+    private int getBottomMargin() {
+        if (mDp == null) {
+            return 0;
+        }
+
+        if (mDp.isVerticalBarLayout()) {
+            return mDp.getInsets().bottom;
+        }
+
+        if (!mDp.isGestureMode && mDp.isTaskbarPresent) {
+            return mDp.getOverviewActionsClaimedSpaceBelow();
+        }
+
+        // Align to bottom of task Rect.
+        return mDp.heightPx - mTaskSize.bottom - mDp.overviewActionsTopMarginPx
+                - mDp.overviewActionsHeight;
     }
 
     /**
-     * Set the device profile for this view to draw with.
+     * Updates device profile and task size for this view to draw with.
      */
-    public void setDp(DeviceProfile dp) {
+    public void updateDimension(DeviceProfile dp, Rect taskSize) {
         mDp = dp;
+        mTaskSize.set(taskSize);
         updateVerticalMargin(DisplayController.getNavigationMode(getContext()));
 
         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
@@ -257,45 +275,4 @@
         mSplitButton.setVisibility(visible ? VISIBLE : GONE);
         findViewById(R.id.action_split_space).setVisibility(visible ? VISIBLE : GONE);
     }
-
-    /** Get the top margin associated with the action buttons in Overview. */
-    public static int getOverviewActionsTopMarginPx(NavigationMode mode, DeviceProfile dp) {
-        // In vertical bar, use the smaller task margin for the top regardless of mode
-        if (dp.isVerticalBarLayout()) {
-            return dp.overviewTaskMarginPx;
-        }
-
-        if (mode == NavigationMode.THREE_BUTTONS) {
-            return dp.overviewActionsMarginThreeButtonPx;
-        }
-
-        return dp.overviewActionsTopMarginGesturePx;
-    }
-
-    /** Get the bottom margin associated with the action buttons in Overview. */
-    public static int getOverviewActionsBottomMarginPx(NavigationMode mode, DeviceProfile dp) {
-        int bottomInset = dp.getInsets().bottom;
-
-        if (dp.isVerticalBarLayout()) {
-            return bottomInset;
-        }
-
-        if (mode == NavigationMode.THREE_BUTTONS) {
-            int bottomMargin = dp.overviewActionsMarginThreeButtonPx + bottomInset;
-            if (dp.isTaskbarPresent) {
-                // Align vertically, using taskbar height + mDp.taskbarOffsetY() to estimate where
-                // the button nav top is.
-                int actionsTop = (dp.heightPx - bottomMargin - bottomInset)
-                        - dp.overviewActionsHeight;
-                int navTop = dp.heightPx - (dp.taskbarSize + dp.getTaskbarOffsetY());
-                bottomMargin -=
-                        navTop - actionsTop + ((dp.taskbarSize - dp.overviewActionsHeight) / 2);
-            }
-            return bottomMargin;
-        }
-
-        // There is no bottom inset when taskbar is present, use stashed taskbar as padding instead.
-        return dp.overviewActionsBottomMarginGesturePx
-                + (dp.isTaskbarPresent ? dp.stashedTaskbarSize : bottomInset);
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 49bf827..b634518 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -378,6 +378,8 @@
     // OverScroll constants
     private static final int OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION = 270;
 
+    private static final int DEFAULT_ACTIONS_VIEW_ALPHA_ANIMATION_DURATION = 300;
+
     private static final int DISMISS_TASK_DURATION = 300;
     private static final int ADDITION_TASK_DURATION = 200;
     private static final float INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.55f;
@@ -455,6 +457,7 @@
     protected boolean mFreezeViewVisibility;
     private boolean mOverviewGridEnabled;
     private boolean mOverviewFullscreenEnabled;
+    private boolean mOverviewSelectEnabled;
 
     private float mAdjacentPageHorizontalOffset = 0;
     protected float mTaskViewsSecondaryTranslation = 0;
@@ -651,6 +654,8 @@
     private TaskView mMovingTaskView;
 
     private OverviewActionsView mActionsView;
+    private ObjectAnimator mActionsViewAlphaAnimator;
+    private float mActionsViewAlphaAnimatorFinalValue;
 
     private MultiWindowModeChangedListener mMultiWindowModeChangedListener =
             new MultiWindowModeChangedListener() {
@@ -941,7 +946,7 @@
                 mHasVisibleTaskData.delete(i);
             }
             if (child instanceof GroupedTaskView) {
-                mGroupedTaskViewPool.recycle((GroupedTaskView)taskView);
+                mGroupedTaskViewPool.recycle((GroupedTaskView) taskView);
             } else {
                 mTaskViewPool.recycle(taskView);
             }
@@ -1144,6 +1149,11 @@
         return getScrollForPage(taskIndex) == getPagedOrientationHandler().getPrimaryScroll(this);
     }
 
+    private boolean isFocusedTaskInExpectedScrollPosition() {
+        TaskView focusedTask = getFocusedTaskView();
+        return focusedTask != null && isTaskInExpectedScrollPosition(indexOfChild(focusedTask));
+    }
+
     /**
      * Returns a {@link TaskView} that has taskId matching {@code taskId} or null if no match.
      */
@@ -1190,13 +1200,15 @@
     @Override
     protected void onPageBeginTransition() {
         super.onPageBeginTransition();
-        mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, true);
+        if (!mActivity.getDeviceProfile().isTablet) {
+            mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, true);
+        }
     }
 
     @Override
     protected void onPageEndTransition() {
         super.onPageEndTransition();
-        if (isClearAllHidden()) {
+        if (isClearAllHidden() && !mActivity.getDeviceProfile().isTablet) {
             mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
         }
         if (getNextPage() > 0) {
@@ -1637,11 +1649,11 @@
         // Propagate DeviceProfile change event.
         runActionOnRemoteHandles(
                 remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator().setDp(dp));
-        mActionsView.setDp(dp);
         mOrientationState.setDeviceProfile(dp);
 
         // Update RecentsView and TaskView's DeviceProfile dependent layout.
         updateOrientationHandler();
+        mActionsView.updateDimension(dp, mLastComputedTaskSize);
     }
 
     private void updateOrientationHandler() {
@@ -1706,7 +1718,7 @@
                 dp.widthPx - mInsets.right - mTempRect.right,
                 dp.heightPx - mInsets.bottom - mTempRect.bottom);
 
-        mSizeStrategy.calculateGridSize(mActivity, mActivity.getDeviceProfile(),
+        mSizeStrategy.calculateGridSize(mActivity.getDeviceProfile(),
                 mLastComputedGridSize);
         mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
                 mLastComputedGridTaskSize, mOrientationHandler);
@@ -1764,7 +1776,8 @@
      * Returns the size of task selected to enter modal state.
      */
     public Point getSelectedTaskSize() {
-        mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), mTempRect);
+        mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(),
+                mTempRect);
         return new Point(mTempRect.width(), mTempRect.height());
     }
 
@@ -1806,16 +1819,24 @@
     }
 
     private void updateActionsViewFocusedScroll() {
-        boolean hiddenFocusedScroll;
         if (showAsGrid()) {
-            TaskView focusedTaskView = getFocusedTaskView();
-            hiddenFocusedScroll = focusedTaskView == null
-                    || !isTaskInExpectedScrollPosition(indexOfChild(focusedTaskView));
-        } else {
-            hiddenFocusedScroll = false;
+            float actionsViewAlphaValue = isFocusedTaskInExpectedScrollPosition() ? 1 : 0;
+            // If animation is already in progress towards the same end value, do not restart.
+            if (mActionsViewAlphaAnimator == null || !mActionsViewAlphaAnimator.isStarted()
+                    || (mActionsViewAlphaAnimator.isStarted()
+                    && mActionsViewAlphaAnimatorFinalValue != actionsViewAlphaValue)) {
+                animateActionsViewAlpha(actionsViewAlphaValue,
+                        DEFAULT_ACTIONS_VIEW_ALPHA_ANIMATION_DURATION);
+            }
         }
-        mActionsView.updateHiddenFlags(OverviewActionsView.HIDDEN_FOCUSED_SCROLL,
-                hiddenFocusedScroll);
+    }
+
+    private void animateActionsViewAlpha(float alphaValue, long duration) {
+        mActionsViewAlphaAnimator = ObjectAnimator.ofFloat(
+                mActionsView.getVisibilityAlpha(), MultiValueAlpha.VALUE, alphaValue);
+        mActionsViewAlphaAnimatorFinalValue = alphaValue;
+        mActionsViewAlphaAnimator.setDuration(duration);
+        mActionsViewAlphaAnimator.start();
     }
 
     /**
@@ -1834,17 +1855,18 @@
         if (!mActivity.getDeviceProfile().isTablet) {
             return super.getDestinationPage(scaledScroll);
         }
-
-        final int childCount = getChildCount();
-        if (mPageScrolls == null || childCount != mPageScrolls.length) {
-            return -1;
+        if (!pageScrollsInitialized()) {
+            Log.e(TAG,
+                    "Cannot get destination page: RecentsView not properly initialized",
+                    new IllegalStateException());
+            return INVALID_PAGE;
         }
 
         // When in tablet with variable task width, return the page which scroll is closest to
         // screenStart instead of page nearest to center of screen.
         int minDistanceFromScreenStart = Integer.MAX_VALUE;
-        int minDistanceFromScreenStartIndex = -1;
-        for (int i = 0; i < childCount; ++i) {
+        int minDistanceFromScreenStartIndex = INVALID_PAGE;
+        for (int i = 0; i < getChildCount(); ++i) {
             int distanceFromScreenStart = Math.abs(mPageScrolls[i] - scaledScroll);
             if (distanceFromScreenStart < minDistanceFromScreenStart) {
                 minDistanceFromScreenStart = distanceFromScreenStart;
@@ -2344,10 +2366,9 @@
     }
 
     private void animateActionsViewIn() {
-        ObjectAnimator anim = ObjectAnimator.ofFloat(
-                mActionsView.getVisibilityAlpha(), MultiValueAlpha.VALUE, 0, 1);
-        anim.setDuration(TaskView.SCALE_ICON_DURATION);
-        anim.start();
+        if (!showAsGrid() || isFocusedTaskInExpectedScrollPosition()) {
+            animateActionsViewAlpha(1, TaskView.SCALE_ICON_DURATION);
+        }
     }
 
     public void animateUpTaskIconScale() {
@@ -2684,13 +2705,6 @@
             PendingAnimation anim) {
         // Use setFloat instead of setViewAlpha as we want to keep the view visible even when it's
         // alpha is set to 0 so that it can be recycled in the view pool properly
-        if (ENABLE_QUICKSTEP_LIVE_TILE.get() && taskView.isRunningTask()) {
-            runActionOnRemoteHandles(remoteTargetHandle -> {
-                TransformParams params = remoteTargetHandle.getTransformParams();
-                anim.setFloat(params, TransformParams.TARGET_ALPHA, 0,
-                        clampToProgress(FINAL_FRAME, 0, 0.5f));
-            });
-        }
         anim.setFloat(taskView, VIEW_ALPHA, 0,
                 clampToProgress(isOnGridBottomRow(taskView) ? ACCEL : FINAL_FRAME, 0, 0.5f));
         FloatProperty<TaskView> secondaryViewTranslate =
@@ -2737,16 +2751,15 @@
                     mSplitHiddenTaskView.getThumbnail().getThumbnail(),
                     mSplitHiddenTaskView.getIconView().getDrawable(), startingTaskRect);
             mFirstFloatingTaskView.setAlpha(1);
-            mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
-                    mTempRect, true /* fadeWithThumbnail */, true /* isStagedTask */);
+            mFirstFloatingTaskView.addAnimation(anim, startingTaskRect, mTempRect,
+                    true /* fadeWithThumbnail */, true /* isStagedTask */);
         } else {
-            mSplitSelectSource.view.setVisibility(INVISIBLE);
             mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
-                    mSplitSelectSource.view, null,
+                    mSplitSelectSource.view, null /* thumbnail */,
                     mSplitSelectSource.drawable, startingTaskRect);
             mFirstFloatingTaskView.setAlpha(1);
-            mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
-                    mTempRect, true /* fadeWithThumbnail */, true /* isStagedTask */);
+            mFirstFloatingTaskView.addAnimation(anim, startingTaskRect, mTempRect,
+                    false /* fadeWithThumbnail */, true /* isStagedTask */);
         }
         InteractionJankMonitorWrapper.begin(this,
                 InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "First tile selected");
@@ -3290,7 +3303,7 @@
                         // Update various scroll-dependent UI.
                         dispatchScrollChanged();
                         updateActionsViewFocusedScroll();
-                        if (isClearAllHidden()) {
+                        if (isClearAllHidden() && !mActivity.getDeviceProfile().isTablet) {
                             mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING,
                                     false);
                         }
@@ -3689,10 +3702,7 @@
 
         // Update the pivots such that when the task is scaled, it fills the full page
         getTaskSize(mTempRect);
-        getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect,
-                mActivity.getDeviceProfile(), mTempPointF);
-        setPivotX(mTempPointF.x);
-        setPivotY(mTempPointF.y);
+        updatePivots();
         setTaskModalness(mTaskModalness);
         mLastComputedTaskStartPushOutDistance = null;
         mLastComputedTaskEndPushOutDistance = null;
@@ -3704,6 +3714,18 @@
                 : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
     }
 
+    private void updatePivots() {
+        if (mOverviewSelectEnabled) {
+            setPivotX(mLastComputedTaskSize.centerX());
+            setPivotY(mLastComputedTaskSize.bottom);
+        } else {
+            getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect,
+                    mActivity.getDeviceProfile(), mTempPointF);
+            setPivotX(mTempPointF.x);
+            setPivotY(mTempPointF.y);
+        }
+    }
+
     private void updatePageOffsets() {
         float offset = mAdjacentPageHorizontalOffset;
         float modalOffset = ACCEL_0_75.getInterpolation(mTaskModalness);
@@ -4030,7 +4052,8 @@
         // TODO(194414938) starting bounds seem slightly off, investigate
         Rect firstTaskStartingBounds = new Rect();
         Rect firstTaskEndingBounds = mTempRect;
-        int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
+        int duration = mActivity.getStateManager().getState().getTransitionDuration(mActivity,
+                false /* isToState */);
         PendingAnimation pendingAnimation = new PendingAnimation(duration);
 
         int halfDividerSize = getResources()
@@ -4866,6 +4889,17 @@
     }
 
     /**
+     * Update whether RecentsView is in select mode. Should be enabled before transitioning to
+     * select mode, and only disabled after transitioning from select mode.
+     */
+    public void setOverviewSelectEnabled(boolean overviewSelectEnabled) {
+        if (mOverviewSelectEnabled != overviewSelectEnabled) {
+            mOverviewSelectEnabled = overviewSelectEnabled;
+            updatePivots();
+        }
+    }
+
+    /**
      * Switch the current running task view to static snapshot mode,
      * capturing the snapshot at the same time.
      */
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index bff8651..d8120ff 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -283,6 +283,7 @@
 
     public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) {
         mFullscreenParams = fullscreenParams;
+        getTaskOverlay().setFullscreenParams(fullscreenParams);
         invalidate();
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 8869ff1..b5971f2 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -1022,7 +1022,7 @@
     }
 
     public float getTaskCornerRadius() {
-        return TaskCornerRadius.get(mActivity);
+        return mCurrentFullscreenParams.mCornerRadius;
     }
 
     @Override
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java
new file mode 100644
index 0000000..929bff3
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java
@@ -0,0 +1,125 @@
+package com.android.launcher3.taskbar;
+
+import static android.view.MotionEvent.ACTION_DOWN;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Handler;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.DeviceProfile;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Supplier;
+
+@RunWith(AndroidJUnit4.class)
+public class RecentsHitboxExtenderTest {
+
+    private static final int TASKBAR_OFFSET_Y = 35;
+    private static final int BUTTON_WIDTH = 10;
+    private static final int BUTTON_HEIGHT = 10;
+
+    private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender();
+    @Mock
+    View mMockRecentsButton;
+    @Mock
+    View mMockRecentsParent;
+    @Mock
+    DeviceProfile mMockDeviceProfile;
+    @Mock
+    Handler mMockHandler;
+    Context mContext;
+
+    float[] mRecentsCoords = new float[]{0,0};
+    private final Supplier<float[]> mSupplier = () -> mRecentsCoords;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = instrumentation.getContext();
+        mHitboxExtender.init(mMockRecentsButton, mMockRecentsParent, mMockDeviceProfile, mSupplier,
+                mMockHandler);
+        when(mMockDeviceProfile.getTaskbarOffsetY()).thenReturn(TASKBAR_OFFSET_Y);
+        when(mMockRecentsButton.getContext()).thenReturn(mContext);
+        when(mMockRecentsButton.getWidth()).thenReturn(BUTTON_WIDTH);
+        when(mMockRecentsButton.getHeight()).thenReturn(BUTTON_HEIGHT);
+    }
+
+    @Test
+    public void noRecentsButtonClick_notActive() {
+        mHitboxExtender.onAnimationProgressToOverview(0);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertFalse(mHitboxExtender.extendedHitboxEnabled());
+    }
+
+    @Test
+    public void recentsButtonClick_active() {
+        mHitboxExtender.onRecentsButtonClicked();
+        mHitboxExtender.onAnimationProgressToOverview(0);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertTrue(mHitboxExtender.extendedHitboxEnabled());
+    }
+
+    @Test
+    public void homeToTaskbar_notActive() {
+        mHitboxExtender.onAnimationProgressToOverview(1);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertFalse(mHitboxExtender.extendedHitboxEnabled());
+    }
+
+    @Test
+    public void animationEndReset() {
+        mHitboxExtender.onRecentsButtonClicked();
+        mHitboxExtender.onAnimationProgressToOverview(0);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertTrue(mHitboxExtender.extendedHitboxEnabled());
+        mHitboxExtender.onAnimationProgressToOverview(1);
+        verify(mMockHandler, times(1)).postDelayed(any(), anyLong());
+    }
+
+    @Test
+    public void motionWithinHitbox() {
+        mHitboxExtender.onRecentsButtonClicked();
+        mHitboxExtender.onAnimationProgressToOverview(0);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertTrue(mHitboxExtender.extendedHitboxEnabled());
+        // Center width, past height but w/in offset bounds
+        MotionEvent motionEvent = getMotionEvent(ACTION_DOWN,
+                BUTTON_WIDTH / 2, BUTTON_HEIGHT + TASKBAR_OFFSET_Y / 2);
+        assertTrue(mHitboxExtender.onControllerInterceptTouchEvent(motionEvent));
+    }
+
+    @Test
+    public void motionOutsideHitbox() {
+        mHitboxExtender.onRecentsButtonClicked();
+        mHitboxExtender.onAnimationProgressToOverview(0);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertTrue(mHitboxExtender.extendedHitboxEnabled());
+        // Center width, past height and offset
+        MotionEvent motionEvent = getMotionEvent(ACTION_DOWN,
+                BUTTON_WIDTH / 2, BUTTON_HEIGHT + TASKBAR_OFFSET_Y * 2);
+        assertFalse(mHitboxExtender.onControllerInterceptTouchEvent(motionEvent));
+    }
+
+    private MotionEvent getMotionEvent(int action, int x, int y) {
+        return MotionEvent.obtain(0, 0, action, x, y, 0);
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 4d38822..4bf247c 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -52,6 +52,8 @@
 public class TaplTestsQuickstep extends AbstractQuickStepTest {
 
     private static final String APP_NAME = "LauncherTestApp";
+    private static final String CALCULATOR_APP_PACKAGE =
+            resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
 
     @Before
     public void setUp() throws Exception {
@@ -73,7 +75,7 @@
 
     public static void startTestApps() throws Exception {
         startAppFast(getAppPackageName());
-        startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
+        startAppFast(CALCULATOR_APP_PACKAGE);
         startTestActivity(2);
     }
 
@@ -207,7 +209,7 @@
     @NavigationModeSwitch
     @PortraitLandscape
     public void testBackground() throws Exception {
-        startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
+        startAppFast(CALCULATOR_APP_PACKAGE);
         final LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
 
         assertNotNull("Background.switchToOverview() returned null",
@@ -302,7 +304,7 @@
         mLauncher.getWorkspace();
         waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
 
-        startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
+        startAppFast(CALCULATOR_APP_PACKAGE);
         mLauncher.pressBack();
         mLauncher.getWorkspace();
         waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
diff --git a/res/color-night-v31/all_apps_button_color_2.xml b/res/color-night-v31/all_apps_button_color_2.xml
index 30b972f..e400543 100644
--- a/res/color-night-v31/all_apps_button_color_2.xml
+++ b/res/color-night-v31/all_apps_button_color_2.xml
@@ -15,6 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
-        android:color="@android:color/system_accent2_50"
+        android:color="@android:color/system_accent2_500"
         android:lStar="98" />
 </selector>
diff --git a/res/color-night-v31/folder_background_dark.xml b/res/color-night-v31/folder_background_dark.xml
index d607395..696e8ea 100644
--- a/res/color-night-v31/folder_background_dark.xml
+++ b/res/color-night-v31/folder_background_dark.xml
@@ -15,6 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
-        android:color="@android:color/system_neutral2_50"
+        android:color="@android:color/system_neutral2_500"
         android:lStar="35" />
 </selector>
diff --git a/res/color-night-v31/folder_preview_dark.xml b/res/color-night-v31/folder_preview_dark.xml
index a5bd636..bdd48a2 100644
--- a/res/color-night-v31/folder_preview_dark.xml
+++ b/res/color-night-v31/folder_preview_dark.xml
@@ -15,6 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
-        android:color="@android:color/system_neutral2_50"
+        android:color="@android:color/system_neutral2_500"
         android:lStar="30" />
 </selector>
diff --git a/res/color-v31/all_apps_button_bg_color.xml b/res/color-v31/all_apps_button_bg_color.xml
index 3ad38bc..8959020 100644
--- a/res/color-v31/all_apps_button_bg_color.xml
+++ b/res/color-v31/all_apps_button_bg_color.xml
@@ -15,6 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
-        android:color="@android:color/system_neutral1_50"
+        android:color="@android:color/system_neutral1_500"
         android:lStar="98" />
 </selector>
diff --git a/res/color-v31/all_apps_button_color_1.xml b/res/color-v31/all_apps_button_color_1.xml
index 2d0895e..71c7d8d 100644
--- a/res/color-v31/all_apps_button_color_1.xml
+++ b/res/color-v31/all_apps_button_color_1.xml
@@ -15,6 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
-        android:color="@android:color/system_accent1_50"
+        android:color="@android:color/system_accent1_500"
         android:lStar="40" />
 </selector>
diff --git a/res/color-v31/all_apps_button_color_2.xml b/res/color-v31/all_apps_button_color_2.xml
index 7674b43..608c8a9 100644
--- a/res/color-v31/all_apps_button_color_2.xml
+++ b/res/color-v31/all_apps_button_color_2.xml
@@ -15,6 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
-        android:color="@android:color/system_accent2_50"
+        android:color="@android:color/system_accent2_500"
         android:lStar="48" />
 </selector>
diff --git a/res/color-v31/all_apps_button_color_3.xml b/res/color-v31/all_apps_button_color_3.xml
index 17cb54f..dbb97b1 100644
--- a/res/color-v31/all_apps_button_color_3.xml
+++ b/res/color-v31/all_apps_button_color_3.xml
@@ -15,6 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
-        android:color="@android:color/system_accent1_50"
+        android:color="@android:color/system_accent1_500"
         android:lStar="35" />
 </selector>
diff --git a/res/color-v31/all_apps_button_color_4.xml b/res/color-v31/all_apps_button_color_4.xml
index a6150f1..d02528f6 100644
--- a/res/color-v31/all_apps_button_color_4.xml
+++ b/res/color-v31/all_apps_button_color_4.xml
@@ -15,6 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
-        android:color="@android:color/system_accent3_50"
+        android:color="@android:color/system_accent3_500"
         android:lStar="48" />
 </selector>
diff --git a/res/color-v31/folder_background_light.xml b/res/color-v31/folder_background_light.xml
index e3c7e7d..eb2fdd7 100644
--- a/res/color-v31/folder_background_light.xml
+++ b/res/color-v31/folder_background_light.xml
@@ -15,6 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
-        android:color="@android:color/system_neutral1_50"
+        android:color="@android:color/system_neutral1_500"
         android:lStar="98" />
 </selector>
diff --git a/res/color-v31/folder_preview_light.xml b/res/color-v31/folder_preview_light.xml
index fe30c87..ed1205e 100644
--- a/res/color-v31/folder_preview_light.xml
+++ b/res/color-v31/folder_preview_light.xml
@@ -15,6 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
-        android:color="@android:color/system_accent2_50"
+        android:color="@android:color/system_accent2_500"
         android:lStar="80" />
 </selector>
diff --git a/res/drawable/rounded_action_button.xml b/res/drawable/rounded_action_button.xml
index b9942c0..81e94f7 100644
--- a/res/drawable/rounded_action_button.xml
+++ b/res/drawable/rounded_action_button.xml
@@ -18,10 +18,11 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:shape="rectangle">
+    <solid android:color="?androidprv:attr/colorSurfaceVariant" />
     <corners android:radius="@dimen/rounded_button_radius" />
     <stroke
         android:width="1dp"
-        android:color="?androidprv:attr/colorAccentPrimaryVariant" />
+        android:color="?androidprv:attr/colorSurfaceVariant" />
     <padding
         android:left="@dimen/rounded_button_padding"
         android:right="@dimen/rounded_button_padding" />
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index d0d82d4..2ac7e63 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -30,10 +30,6 @@
         android:visibility="gone" />
 
     <include
-        layout="@layout/search_results_rv_layout"
-        android:visibility="gone" />
-
-    <include
         layout="@layout/all_apps_rv_layout"
         android:visibility="gone" />
 
diff --git a/res/layout/search_results_rv_layout.xml b/res/layout/search_results_rv_layout.xml
deleted file mode 100644
index 567cb5f..0000000
--- a/res/layout/search_results_rv_layout.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2022 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.allapps.SearchRecyclerView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/search_results_list_view"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:clipToPadding="false"
-    android:descendantFocusability="afterDescendants"
-    android:focusable="true" />
diff --git a/res/layout/secondary_launcher.xml b/res/layout/secondary_launcher.xml
index 635db14..0fe05ee 100644
--- a/res/layout/secondary_launcher.xml
+++ b/res/layout/secondary_launcher.xml
@@ -60,10 +60,6 @@
             android:visibility="gone" />
 
         <include
-            layout="@layout/search_results_rv_layout"
-            android:visibility="gone" />
-
-        <include
             layout="@layout/all_apps_rv_layout"
             android:visibility="gone" />
 
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 0f6fc6c..feebfe1 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -22,7 +22,7 @@
         android:layout_width="0dp"
         android:layout_height="0dp"
         android:layout_weight="1"
-        android:importantForAccessibility="no"
+        android:importantForAccessibility="noHideDescendants"
         android:layout_marginVertical="8dp">
         <!-- The image of the widget. This view does not support padding. Any placement adjustment
              should be done using margins. Width & height are set at runtime after scaling the
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index 8f0eae7..3cdc2e8 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -21,7 +21,10 @@
     android:layout_height="wrap_content"
     android:paddingVertical="@dimen/widget_list_header_view_vertical_padding"
     android:orientation="horizontal"
-    launcher:appIconSize="48dp">
+    android:importantForAccessibility="yes"
+    android:focusable="true"
+    launcher:appIconSize="48dp"
+    android:descendantFocusability="afterDescendants">
 
     <ImageView
         android:id="@+id/app_icon"
@@ -32,14 +35,11 @@
         tools:src="@drawable/ic_corp"/>
 
     <LinearLayout
-        android:id="@+id/app_container"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:layout_weight="1"
-        android:orientation="vertical"
-        android:focusable="true"
-        android:descendantFocusability="afterDescendants">
+        android:orientation="vertical">
 
         <TextView
             android:id="@+id/app_title"
diff --git a/res/layout/work_apps_edu.xml b/res/layout/work_apps_edu.xml
index 73200de..f3b3053 100644
--- a/res/layout/work_apps_edu.xml
+++ b/res/layout/work_apps_edu.xml
@@ -16,9 +16,9 @@
 <com.android.launcher3.allapps.WorkEduCard xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_marginTop="8dp"
+    android:layout_marginTop="@dimen/work_edu_card_margin"
+    android:layout_marginBottom="@dimen/work_edu_card_bottom_margin"
     android:gravity="center">
-
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -36,30 +36,29 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginBottom="@dimen/work_card_margin"
-            android:layout_marginRight="@dimen/work_card_margin"
+            android:layout_marginEnd="@dimen/work_card_margin"
             android:text="@string/work_profile_edu_work_apps"
+            android:textDirection="locale"
             android:textSize="18sp" />
         <RelativeLayout
             android:layout_width="match_parent"
             android:layout_height="@dimen/padded_rounded_button_height"
-            android:orientation="horizontal"
-            >
+            android:orientation="horizontal">
             <FrameLayout
                 android:layout_width="@dimen/rounded_button_width"
                 android:layout_height="@dimen/rounded_button_width"
+                android:layout_alignParentEnd="true"
                 android:background="@drawable/rounded_action_button"
-                android:padding="@dimen/rounded_button_padding"
-                android:layout_alignParentRight="true">
+                android:padding="@dimen/rounded_button_padding">
                 <ImageButton
+                    android:id="@+id/action_btn"
                     android:layout_width="@dimen/x_icon_size"
                     android:layout_height="@dimen/x_icon_size"
-                    android:id="@+id/action_btn"
-                    android:src="@drawable/ic_remove_no_shadow"
                     android:layout_gravity="center"
-                    android:padding="@dimen/x_icon_padding" />
+                    android:padding="@dimen/x_icon_padding"
+                    android:src="@drawable/ic_remove_no_shadow" />
             </FrameLayout>
         </RelativeLayout>
-
     </RelativeLayout>
 
 
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index c536d77..d2fa5fa 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -21,14 +21,14 @@
     android:layout_width="wrap_content"
     android:gravity="center"
     android:includeFontPadding="false"
+    android:textDirection="locale"
     android:drawableTint="@color/all_apps_tab_text"
     android:textColor="@color/all_apps_tab_text"
     android:textSize="14sp"
     android:background="@drawable/work_apps_toggle_background"
     android:drawablePadding="8dp"
     android:drawableStart="@drawable/ic_corp_off"
-    android:layout_marginBottom="@dimen/work_fab_margin"
-    android:layout_marginEnd="@dimen/work_fab_margin"
+    android:layout_marginBottom="@dimen/work_fab_margin_bottom"
     android:paddingLeft="@dimen/work_mode_fab_padding"
     android:paddingRight="@dimen/work_mode_fab_padding"
     android:text="@string/work_apps_pause_btn_text" />
\ No newline at end of file
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 471bcc5..019fc5b 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeer tans; <xliff:g id="PROGRESS">%2$s</xliff:g> voltooi"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> laai tans af, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> wag tans om te installeer"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Programopdatering word vereis"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Die program vir hierdie ikoon is nie opgedateer nie. Jy kan dit handmatig opdateer om hierdie kortpad weer te aktiveer, of die ikoon verwyder."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Dateer op"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Verwyder"</string>
     <string name="widgets_list" msgid="796804551140113767">"Legstukkelys"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Legstukkelys is toegemaak"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Voeg by tuisskerm"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 73bbdd1..7de1041 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> በመጫን ላይ፣ <xliff:g id="PROGRESS">%2$s</xliff:g> ተጠናቅቋል"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> በመውረድ ላይ፣ <xliff:g id="PROGRESS">%2$s</xliff:g> ተጠናቋል"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ለመጫን በመጠበቅ ላይ"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"መተግበሪያ ማዘመን አስፈላጊ ነው"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"የዚህ አዶ መተግበሪያ አልተዘመነም። ይህን አቋራጭ ዳግም ለማንቃት በራስዎ ማዘመን ወይም አዶውን ማስወገድ ይችላሉ።"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"አዘምን"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"አስወግድ"</string>
     <string name="widgets_list" msgid="796804551140113767">"የመግብሮች ዝርዝር"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"የመግብሮች ዝርዝር ተዘግቷል"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"ወደ መነሻ ማያ ገጽ አክል"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 774977c..bcd1fa9 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"جارٍ تثبيت <xliff:g id="NAME">%1$s</xliff:g>، مستوى التقدم: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"جارٍ تنزيل <xliff:g id="NAME">%1$s</xliff:g>، اكتمل <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> في انتظار التثبيت"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"مطلوب تحديث التطبيق"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"لم يتمّ تحديث التطبيق الخاص بهذا الرمز. يمكنك تحديث التطبيق يدويًا لإعادة تفعيل هذا الاختصار أو إزالة الرمز."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"تحديث"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"إزالة"</string>
     <string name="widgets_list" msgid="796804551140113767">"قائمة الأدوات"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"تم إغلاق قائمة الأدوات."</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"إضافة تطبيق للشاشة الرئيسية"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index cb1581f..e3f637f 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ইনষ্টল কৰি থকা হৈছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূৰ্ণ হৈছে"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনল’ড কৰি থকা হৈছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূৰ্ণ হ’ল"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনষ্টল হোৱালৈ অপেক্ষা কৰি থকা হৈছে"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"এপ্‌টো আপডে’ট কৰা প্ৰয়োজন"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"এই চিহ্নটোৰ এপ্‌টো আপডে’ট কৰা হোৱা নাই। আপুনি এই শ্বৰ্টকাটটো পুনৰ সক্ষম কৰিবলৈ মেনুৱেলী আপডে’ট কৰিব পাৰে অথবা চিহ্নটো আঁতৰাব পাৰে।"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"আপডে’ট কৰক"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"আঁতৰাওক"</string>
     <string name="widgets_list" msgid="796804551140113767">"ৱিজেটৰ তালিকা"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ৱিজেটৰ তালিকা বন্ধ কৰা হ’ল"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"গৃহ স্ক্ৰীনত যোগ কৰক"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index aa19e28..47fde2a 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> quraşdırır, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlanıb"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> endirilir, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> yüklənmək üçün gözləyir"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Tətbiqin güncəllənməsi tələb edilir"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Bu ikona üçün tətbiq güncəllənməyib. Bu qısayolu yenidən aktivləşdirmək üçün manual olaraq güncəlləyə və ya ikonanı silə bilərsiniz."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Güncəlləyin"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Silin"</string>
     <string name="widgets_list" msgid="796804551140113767">"Vidcet siyahısı"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Vidcet siyahısı bağlandı"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Əsas ekrana əlavə edin"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index ddcb256..6ad0ea9 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se instalira, <xliff:g id="PROGRESS">%2$s</xliff:g> gotovo"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno je <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka na instaliranje"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Treba da ažurirate aplikaciju"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacija za ovu ikonu nije ažurirana. Možete da je ručno ažurirate da biste ponovo omogućili ovu prečicu ili uklonite ikonu."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Ažuriraj"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Ukloni"</string>
     <string name="widgets_list" msgid="796804551140113767">"Lista vidžeta"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Lista vidžeta je zatvorena"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Dodajte na početni ekran"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 43e5e90..3617fcc 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Усталёўваецца праграма \"<xliff:g id="NAME">%1$s</xliff:g>\", завершана <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Ідзе спампоўка <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> завершана"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чакае ўсталёўкі"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Неабходна абнавіць праграму"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Гэта версія праграмы састарэла. Абнавіце праграму ўручную, каб зноў карыстацца гэтым ярлыком, або выдаліце значок."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Абнавіць"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Выдаліць"</string>
     <string name="widgets_list" msgid="796804551140113767">"Спіс віджэтаў"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Спіс віджэтаў закрыты"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Дадаць на галоўны экран"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 9c65708..1a8671a 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> завършено"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> се изтегля. Завършено: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> изчаква инсталиране"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Изисква се актуализация на приложението"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Приложението за тази икона не е актуализирано. Можете да го актуализирате ръчно, за да активирате отново този пряк път, или да премахнете иконата."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Актуализиране"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Премахване"</string>
     <string name="widgets_list" msgid="796804551140113767">"Списък с приспособления"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Списъкът с приспособления е затворен"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Добавяне към началния екран"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 38be6e2..7b45842 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ইনস্টল করা হচ্ছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূর্ণ হয়েছে"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনলোড হচ্ছে <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পন্ন হয়েছে"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনস্টলের অপেক্ষায় রয়েছে"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"অ্যাপটি আপডেট করা প্রয়োজন"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"এই আইকনের জন্য অ্যাপটি আপডেট করা নেই। এই শর্টকার্ট আবার চালু করতে, আপনি ম্যানুয়ালি আপডেট করতে বা সরিয়ে দিতে পারবেন।"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"আপডেট করুন"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"সরান"</string>
     <string name="widgets_list" msgid="796804551140113767">"উইজেটের তালিকা"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"উইজেটের তালিকা বন্ধ করা হয়েছে"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"হোম স্ক্রিনে যোগ করুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index fbf9fce..fbe4bf1 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instaliranje aplikacije <xliff:g id="NAME">%1$s</xliff:g>, završeno je <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka da se instalira"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Potrebno je ažurirati aplikaciju"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacija za ovu ikonu nije ažurirana. Možete je ažurirati ručno da ponovo omogućite ovu prečicu ili možete ukloniti ikonu."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Ažuriraj"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Ukloni"</string>
     <string name="widgets_list" msgid="796804551140113767">"Spisak vidžeta"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Spisak vidžeta je zatvoren"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Dodavanje na početni ekran"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 9eba6b8..5d58a90 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"S\'està instal·lant <xliff:g id="NAME">%1$s</xliff:g>; s\'ha completat un <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"S\'està baixant <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> completat"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"S\'està esperant per instal·lar <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Cal actualitzar l\'aplicació"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"L\'aplicació d\'aquesta icona no està actualitzada. Pots actualitzar-la manualment per tornar a activar aquesta drecera o pots suprimir la icona."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Actualitza"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Suprimeix"</string>
     <string name="widgets_list" msgid="796804551140113767">"Llista de widgets"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"S\'ha tancat la llista de widgets"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Afegeix a la pantalla d\'inici"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 3b38e62..2b0b100 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instalace aplikace <xliff:g id="NAME">%1$s</xliff:g>, dokončeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Stahování aplikace <xliff:g id="NAME">%1$s</xliff:g> (dokončeno <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Instalace aplikace <xliff:g id="NAME">%1$s</xliff:g> čeká na zahájení"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Je nutná aktualizace aplikace"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplikace pro tuto ikonu není nainstalována. Můžete ji ručně aktualizovat, aby zkratka znovu fungovala, případně můžete ikonu odstranit."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Aktualizovat"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Odstranit"</string>
     <string name="widgets_list" msgid="796804551140113767">"Seznam widgetů"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Seznam widgetů zavřen"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Přidat na plochu"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 284f2d9..45d8358 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeres. <xliff:g id="PROGRESS">%2$s</xliff:g> fuldført"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloades. <xliff:g id="PROGRESS">%2$s</xliff:g> er gennemført"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> venter på at installere"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Appen skal opdateres"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Appen, der tilhører dette ikon, er ikke opdateret. Du kan opdatere appen manuelt for at genaktivere denne genvej, eller du kan fjerne ikonet."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Opdater"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Fjern"</string>
     <string name="widgets_list" msgid="796804551140113767">"Liste med widgets"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Listen med widgets blev lukket"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Føj til startskærm"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 0dc06cd..140584c 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> wird installiert, <xliff:g id="PROGRESS">%2$s</xliff:g> abgeschlossen"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> wird heruntergeladen, <xliff:g id="PROGRESS">%2$s</xliff:g> abgeschlossen"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Warten auf Installation von <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"App-Update erforderlich"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Die App für dieses Symbol wurde noch nicht aktualisiert. Du kannst sie manuell aktualisieren, um die Verknüpfung wieder zu aktivieren, oder das Symbol entfernen."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Aktualisieren"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Entfernen"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widgetliste"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Widgetliste geschlossen"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Zum Startbildschirm hinzufügen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 2b67848..5bbc008 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Έχει ολοκληρωθεί το <xliff:g id="PROGRESS">%2$s</xliff:g> της εγκατάστασης της εφαρμογής <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Λήψη <xliff:g id="NAME">%1$s</xliff:g>, ολοκληρώθηκε <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> σε αναμονή για εγκατάσταση"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Απαιτείται ενημέρωση της εφαρμογής"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Η εφαρμογή για αυτό το εικονίδιο δεν έχει ενημερωθεί. Μπορείτε να την ενημερώσετε μη αυτόματα για να ενεργοποιήσετε ξανά τη συγκεκριμένη συντόμευση ή να καταργήσετε το εικονίδιο."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Ενημέρωση"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Κατάργηση"</string>
     <string name="widgets_list" msgid="796804551140113767">"Λίστα γραφικών στοιχείων"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Η λίστα γραφικών στοιχείων έκλεισε"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Προσθήκη στην αρχική οθόνη"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 4853509..62fa92d 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -102,7 +102,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> items"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> or more items"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
-    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper &amp; style"</string>
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper and style"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
     <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"App update required"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut or remove the icon."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Remove"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Add to home screen"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 4853509..62fa92d 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -102,7 +102,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> items"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> or more items"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
-    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper &amp; style"</string>
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper and style"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
     <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"App update required"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut or remove the icon."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Remove"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Add to home screen"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 4853509..62fa92d 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -102,7 +102,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> items"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> or more items"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
-    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper &amp; style"</string>
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper and style"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
     <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"App update required"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut or remove the icon."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Remove"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Add to home screen"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 4853509..62fa92d 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -102,7 +102,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> items"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> or more items"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
-    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper &amp; style"</string>
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper and style"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
     <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"App update required"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut or remove the icon."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Remove"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Add to home screen"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index b67397b..1737658 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Se está instalando <xliff:g id="NAME">%1$s</xliff:g>; <xliff:g id="PROGRESS">%2$s</xliff:g> completado"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Se completó el <xliff:g id="PROGRESS">%2$s</xliff:g> de la descarga de <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Instalación de <xliff:g id="NAME">%1$s</xliff:g> en espera"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Es necesario actualizar la app"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"No se actualizó la app de este ícono. Puedes actualizarla manualmente para rehabilitar el acceso directo, o bien quitar el ícono."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Actualizar"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Quitar"</string>
     <string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Se cerró la lista de widgets"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Agregar a pantalla principal"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index a6f07da..21b81cb 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instalando <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> completado"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Descargando <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="PROGRESS">%2$s</xliff:g> completado)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Esperando para instalar <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Debes actualizar la aplicación"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"La aplicación de este icono no está actualizada. Puedes actualizarla manualmente para volver a habilitar este acceso directo o puedes eliminar el icono."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Actualizar"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Quitar"</string>
     <string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgets cerrada"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Añadir a pantalla de inicio"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index ee31cef..7ded0de 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Üksust <xliff:g id="NAME">%1$s</xliff:g> installitakse, <xliff:g id="PROGRESS">%2$s</xliff:g> on valmis"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Rakenduse <xliff:g id="NAME">%1$s</xliff:g> allalaadimine, <xliff:g id="PROGRESS">%2$s</xliff:g> on valmis"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> on installimise ootel"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Rakendust tuleb värskendada"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Selle ikooni rakendust pole värskendatud. Otsetee uuesti lubamiseks võite rakendust käsitsi värskendada või ikooni eemaldada."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Värskenda"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Eemalda"</string>
     <string name="widgets_list" msgid="796804551140113767">"Vidinate loend"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Vidinate loend on suletud"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Lisa avakuvale"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 2798733..48d26f0 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> instalatzen, <xliff:g id="PROGRESS">%2$s</xliff:g> osatuta"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> deskargatzen, <xliff:g id="PROGRESS">%2$s</xliff:g> osatuta"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> instalatzeko zain"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Aplikazioa eguneratu behar da"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Ikonoaren aplikazioa ez dago eguneratuta. Lasterbidea berriro gaitzeko, eskuz egunera dezakezu aplikazioa. Bestela, kendu ikonoa."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Eguneratu"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Kendu"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widget-zerrenda"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Itxi da widget-zerrenda"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Gehitu hasierako pantailan"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index a569816..e834d0c 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> درحال نصب است، <xliff:g id="PROGRESS">%2$s</xliff:g> تکمیل شده است"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"درحال بارگیری <xliff:g id="NAME">%1$s</xliff:g>، <xliff:g id="PROGRESS">%2$s</xliff:g> کامل شد"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> درانتظار نصب"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"برنامه باید به‌روز شود"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"برنامه برای این نماد به‌روز نشده است. می‌توانید آن را به‌صورت دستی به‌روز کنید تا میان‌بر دوباره فعال شود، یا نماد را بردارید."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"به‌روزرسانی"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"برداشتن"</string>
     <string name="widgets_list" msgid="796804551140113767">"فهرست ابزارک‌ها"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"فهرست ابزارک‌ها بسته شد"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"افزودن به صفحه اصلی"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 707dc9a..26ad66e 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> asennetaan, <xliff:g id="PROGRESS">%2$s</xliff:g> valmis"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> latautuu, valmiina <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> odottaa asennusta"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Sovelluspäivitys vaaditaan"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Kuvakkeen sovellusta ei ole päivitetty. Voit ottaa pikakuvakkeen uudelleen käyttöön päivittämällä sovelluksen tai poistaa kuvakkeen."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Päivitä"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Poista"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widget-luettelo"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Widget-luettelo suljettu"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Lisää aloitusnäytölle"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index ff7faad..1fc14f5 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Installation de l\'application <xliff:g id="NAME">%1$s</xliff:g> en cours, <xliff:g id="PROGRESS">%2$s</xliff:g> terminée"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Téléchargement de <xliff:g id="NAME">%1$s</xliff:g> : <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> en attente d\'installation"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Mise à jour de l\'application requise"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"L\'application pour cette icône n\'est pas à jour. Vous pouvez soit la mettre à jour manuellement pour réactiver ce raccourci, soit retirer l\'icône."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Mettre à jour"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Retirer"</string>
     <string name="widgets_list" msgid="796804551140113767">"Liste des widgets"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Liste des widgets fermée"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Ajouter à l\'écran d\'accueil"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index ce4add7..5ef521e 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -124,20 +124,16 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Installation de <xliff:g id="NAME">%1$s</xliff:g>… (<xliff:g id="PROGRESS">%2$s</xliff:g> terminés)"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> en cours de téléchargement, <xliff:g id="PROGRESS">%2$s</xliff:g> effectué(s)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> en attente d\'installation"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Mise à jour de l\'appli requise"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"L\'appli correspondant à cette icône n\'est pas mise à jour. Vous pouvez la mettre à jour manuellement pour réactiver le raccourci ou supprimer l\'icône."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Modifier"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Supprimer"</string>
     <string name="widgets_list" msgid="796804551140113767">"Liste des widgets"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"La liste des widgets est fermée"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Ajouter à l\'écran d\'accueil"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Déplacer l\'élément ici"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"L\'élément a bien été ajouté à l\'écran d\'accueil."</string>
-    <string name="item_removed" msgid="851119963877842327">"L\'élément a bien été supprimé."</string>
+    <string name="item_removed" msgid="851119963877842327">"Élément supprimé"</string>
     <string name="undo" msgid="4151576204245173321">"Annuler"</string>
     <string name="action_move" msgid="4339390619886385032">"Déplacer l\'élément"</string>
     <string name="move_to_empty_cell" msgid="2833711483015685619">"Déplacer vers la ligne <xliff:g id="NUMBER_0">%1$s</xliff:g>, colonne <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 6e42995..2879f0d 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instalando <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> completado"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Descargando <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="PROGRESS">%2$s</xliff:g> completado)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Esperando para instalar <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"É necesario actualizar a aplicación"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"A aplicación á que corresponde esta icona non está actualizada. Podes actualizala manualmente para activar de novo este atallo, ou ben quitar a icona."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Actualizar"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Quitar"</string>
     <string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Pechouse a lista de widgets"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Engadir á pantalla de inicio"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index b2d2654..ce02af6 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -72,7 +72,7 @@
     <string name="all_apps_button_personal_label" msgid="1315764287305224468">"વ્યક્તિગત ઍપની સૂચિ"</string>
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"કાર્યસ્થળની ઍપની સૂચિ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"કાઢી નાખો"</string>
-    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"અનઇન્સ્ટોલ કરો"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"અનઇન્સ્ટૉલ કરો"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ઍપની માહિતી"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ઇન્સ્ટૉલ કરો"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ઍપ સૂચવશો નહીં"</string>
@@ -124,20 +124,16 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ઇન્સ્ટૉલ કરી રહ્યાં છીએ, <xliff:g id="PROGRESS">%2$s</xliff:g> પૂર્ણ થયું"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ડાઉનલોડ કરી રહ્યાં છે, <xliff:g id="PROGRESS">%2$s</xliff:g> પૂર્ણ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>, ઇન્સ્ટૉલ થવાની રાહ જોઈ રહ્યું છે"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"ઍપને અપડેટ કરવી જરૂરી છે"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"આ આઇકન માટે ઍપ અપડેટ કરવામાં આવી નથી. તમે આ શૉર્ટકટ ફરી ચાલુ કરવા અથવા આઇકન કાઢી નાખવા માટે ઍપને મેન્યુઅલી અપડેટ કરી શકો છો."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"અપડેટ કરો"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"કાઢી નાખો"</string>
     <string name="widgets_list" msgid="796804551140113767">"વિજેટની સૂચિ"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"વિજેટની સૂચિ બંધ કરવામાં આવી છે"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"હોમ સ્ક્રીનમાં ઉમેરો"</string>
     <string name="action_move_here" msgid="2170188780612570250">"આઇટમ અહીં ખસેડો"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"હોમ સ્ક્રીનમાં આઇટમ ઉમેરી"</string>
-    <string name="item_removed" msgid="851119963877842327">"આઇટમ દૂર કરી"</string>
+    <string name="item_removed" msgid="851119963877842327">"આઇટમ કાઢી નાખી"</string>
     <string name="undo" msgid="4151576204245173321">"રદ કરો"</string>
     <string name="action_move" msgid="4339390619886385032">"આઇટમ ખસેડો"</string>
     <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> પંક્તિ <xliff:g id="NUMBER_1">%2$s</xliff:g> કૉલમ પર ખસેડો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index bdb16cc..5ed7bc8 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -108,7 +108,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"होम स्क्रीन घुमाने की अनुमति दें"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"फ़ोन घुुमाए जाने पर"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"सूचनाएं बताने वाला डॉट"</string>
-    <string name="notification_dots_desc_on" msgid="1679848116452218908">"चालू"</string>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"चालू है"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"चालू"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"सूचना के ऐक्सेस की ज़रूरत है"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"सूचना बिंदु दिखाने के लिए, <xliff:g id="NAME">%1$s</xliff:g> के ऐप्लिकेशन सूचना चालू करें"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल किया जा रहा है, <xliff:g id="PROGRESS">%2$s</xliff:g> पूरा हो गया"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड हो रहा है, <xliff:g id="PROGRESS">%2$s</xliff:g> पूरी हुई"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> के इंस्टॉल होने की प्रतीक्षा की जा रही है"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"ऐप्लिकेशन को अपडेट करना ज़रूरी है"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"इस आइकॉन का ऐप्लिकेशन अपडेट नहीं है. इस शॉर्टकट को फिर से चालू करने या आइकॉन को हटाने के लिए, ऐप्लिकेशन को मैन्युअल रूप से अपडेट किया जा सकता है."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"अपडेट करें"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"हटाएं"</string>
     <string name="widgets_list" msgid="796804551140113767">"विजेट की सूची"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"विजेट की सूची बंद हो गई है"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"होम स्क्रीन पर जोड़ें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index cc7f067..06a330f 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instaliranje aplikacije <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> dovršeno"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Preuzimanje aplikacije <xliff:g id="NAME">%1$s</xliff:g>, dovršeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Čekanje na instaliranje aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Aplikacija se treba ažurirati"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacija ove ikone nije ažurirana. Možete ručno ažurirati da biste ponovo omogućili ovaj prečac ili uklonite ikonu."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Ažuriraj"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Ukloni"</string>
     <string name="widgets_list" msgid="796804551140113767">"Popis widgeta"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Popis widgeta zatvoren"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Dodajte na početni zaslon"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 9cd705c..2d67fc3 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Folyamatban van a(z) <xliff:g id="NAME">%1$s</xliff:g> telepítése, <xliff:g id="PROGRESS">%2$s</xliff:g> kész"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"A(z) <xliff:g id="NAME">%1$s</xliff:g> letöltése, <xliff:g id="PROGRESS">%2$s</xliff:g> kész"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"A(z) <xliff:g id="NAME">%1$s</xliff:g> telepítésre vár"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Alkalmazásfrissítés szükséges"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Az ikonhoz tartozó alkalmazás nincs frissítve. A parancsikon újbóli engedélyezéséhez frissítse az alkalmazást, vagy távolítsa ez az ikont."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Frissítés"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Eltávolítás"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widgetlista"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Widgetlista bezárva"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Hozzáadás a kezdőképernyőhöz"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index e8124a6..e76ed7e 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -78,11 +78,11 @@
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Թաքցնել առաջարկը"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Ամրացնել առաջարկվող հավելվածը"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Դյուրանցումների տեղադրում"</string>
-    <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ծրագրին թույլ է տալիս ավելացնել դյուրանցումներ՝ առանց օգտագործողի միջամտության:"</string>
+    <string name="permdesc_install_shortcut" msgid="923466509822011139">"Հավելվածին թույլ է տալիս ավելացնել դյուրանցումներ՝ առանց օգտագործողի միջամտության:"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"կարդալ հիմնական էկրանի կարգավորումներն ու դյուրանցումները"</string>
-    <string name="permdesc_read_settings" msgid="4208061150510996676">"Ծրագրին թույլ է տալիս կարդալ հիմնական էկրանի կարգավորումներն ու դյուրանցումները։"</string>
+    <string name="permdesc_read_settings" msgid="4208061150510996676">"Հավելվածին թույլ է տալիս կարդալ հիմնական էկրանի կարգավորումներն ու դյուրանցումները։"</string>
     <string name="permlab_write_settings" msgid="4820028712156303762">"փոփոխել հիմնական էկրանի կարգավորումներն ու դյուրանցումները"</string>
-    <string name="permdesc_write_settings" msgid="726859348127868466">"Ծրագրին թույլ է տալիս փոփոխել հիմնական էկրանի կարգավորումներն ու դյուրանցումները։"</string>
+    <string name="permdesc_write_settings" msgid="726859348127868466">"Հավելվածին թույլ է տալիս փոփոխել հիմնական էկրանի կարգավորումներն ու դյուրանցումները։"</string>
     <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածին չի թույլատրվում հեռախոսազանգեր կատարել"</string>
     <string name="gadget_error_text" msgid="740356548025791839">"Չհաջողվեց բեռնել վիջեթը"</string>
     <string name="gadget_setup_text" msgid="8348374825537681407">"Վիջեթի կարգավորումներ"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> հավելվածը տեղադրվում է, կատարված է <xliff:g id="PROGRESS">%2$s</xliff:g>-ը"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>–ի ներբեռնում (<xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>-ի տեղադրման սպասում"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Պահանջվում է թարմացնել հավելվածը"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Հավելվածը հնացել է։ Թարմացրեք այն ձեռքով, որպեսզի շարունակեք օգտագործել դյուրանցումը, կամ հեռացրեք հավելվածի պատկերակը։"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Թարմացնել"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Հեռացնել"</string>
     <string name="widgets_list" msgid="796804551140113767">"Վիջեթների ցանկ"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Վիջեթների ցանկը փակվեց"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Ավելացնել հիմնական էկրանին"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 07ebae9..b213d47 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> sedang diinstal, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> sedang didownload, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> menunggu dipasang"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Aplikasi perlu diupdate"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplikasi untuk ikon ini belum diupdate. Anda dapat mengupdate secara manual untuk mengaktifkan kembali pintasan ini, atau hapus ikon."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Hapus"</string>
     <string name="widgets_list" msgid="796804551140113767">"Daftar widget"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Daftar widget ditutup"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Tambahkan ke layar utama"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 3645bb9..95b6c1e 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Setur upp <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> lokið"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> í niðurhali, <xliff:g id="PROGRESS">%2$s</xliff:g> lokið"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> bíður uppsetningar"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Uppfæra þarf forritið"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Forritið fyrir þetta tákn er ekki uppfært. Þú getur uppfært það handvirkt til að kveikja aftur á þessari flýtileið eða fjarlægt táknið."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Uppfæra"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Fjarlægja"</string>
     <string name="widgets_list" msgid="796804551140113767">"Græjulisti"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Græjulista lokað"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Bæta á heimaskjá"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index c56ce0b..4664726 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -77,7 +77,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installa"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suggerire app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Blocca previsione"</string>
-    <string name="permlab_install_shortcut" msgid="5632423390354674437">"aggiunta di scorciatoie"</string>
+    <string name="permlab_install_shortcut" msgid="5632423390354674437">"Aggiunta di scorciatoie"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Consente a un\'app di aggiungere scorciatoie automaticamente."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"leggere le impostazioni e le scorciatoie nella schermata Home"</string>
     <string name="permdesc_read_settings" msgid="4208061150510996676">"Consente all\'app di leggere le impostazioni e le scorciatoie nella schermata Home."</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Installazione di <xliff:g id="NAME">%1$s</xliff:g>, completamento: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Download di <xliff:g id="NAME">%1$s</xliff:g> in corso, <xliff:g id="PROGRESS">%2$s</xliff:g> completato"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> in attesa di installazione"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"È necessario aggiornare l\'app"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"L\'app relativa a questa icona non è aggiornata. Puoi eseguire manualmente l\'aggiornamento per riattivare questa scorciatoia oppure rimuovere l\'icona."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Aggiorna"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Rimuovi"</string>
     <string name="widgets_list" msgid="796804551140113767">"Elenco di widget"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Elenco di widget chiuso"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Aggiungi alla schermata Home"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 0aa3f11..b2ecf62 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> בתהליך התקנה, <xliff:g id="PROGRESS">%2$s</xliff:g> הושלמו"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"הורדת <xliff:g id="NAME">%1$s</xliff:g> מתבצעת, <xliff:g id="PROGRESS">%2$s</xliff:g> הושלמו"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"מחכה להתקנה של <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"נדרש עדכון לאפליקציה"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"האפליקציה של הסמל הזה לא מעודכנת. אפשר לעדכן אותה ידנית כדי להפעיל מחדש את קיצור הדרך הזה, או להסיר את הסמל."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"עדכון"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"הסרה"</string>
     <string name="widgets_list" msgid="796804551140113767">"רשימת ווידג\'טים"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"רשימת הווידג\'טים נסגרה"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"הוספה למסך הבית"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 9ac4b94..9e921dc 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> をインストールしています: <xliff:g id="PROGRESS">%2$s</xliff:g> 完了"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>をダウンロード中、<xliff:g id="PROGRESS">%2$s</xliff:g>完了"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>のインストール待ち"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"アプリの更新が必要"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"このアイコンのアプリは更新されていません。手動で更新して、このショートカットを再度有効にできます。また、アイコンを削除することもできます。"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"更新"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"削除"</string>
     <string name="widgets_list" msgid="796804551140113767">"ウィジェット リスト"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ウィジェット リストを閉じました"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"ホーム画面に追加"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 6f66155..e3d762d 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"ინსტალირდება <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> დასრულებულია"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"მიმდინარეობს <xliff:g id="NAME">%1$s</xliff:g>-ის ჩამოტვირთვა, <xliff:g id="PROGRESS">%2$s</xliff:g> დასრულდა"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ელოდება ინსტალაციას"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"საჭიროა აპის განახლება"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"ამ ხატულის აპი განახლებული არ არის. შეგიძლიათ, ხელით განაახლოთ ამ მალსახმობის ხელახლა გასააქტიურებლად, ან ამოშალოთ ხატულა."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"განახლება"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"ამოშლა"</string>
     <string name="widgets_list" msgid="796804551140113767">"ვიჯეტების სია"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ვიჯეტების სია დაიხურა"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"მთავარ ეკრანზე დამატება"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 8b738e4..d84d3d9 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -75,7 +75,7 @@
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Жою"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Қолданба ақпараты"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданбаны ұсынбау"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданба ұсынбау"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Болжанған қолданбаны бекіту"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"таңбаша орнату"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Қолданбаға пайдаланушының қатысуынсыз төте пернелерді қосу мүмкіндігін береді."</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> орнатылуда, <xliff:g id="PROGRESS">%2$s</xliff:g> аяқталды"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> жүктелуде, <xliff:g id="PROGRESS">%2$s</xliff:g> аяқталды"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> орнату күтілуде"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Қолданбаны жаңарту қажет"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Осы белгіше үшін қолданба жаңартылмаған. Оны қолмен жаңартып, осы таңбашаны қайта іске қоса аласыз немесе белгішені өшіріп тастаңыз."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Жаңарту"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Өшіру"</string>
     <string name="widgets_list" msgid="796804551140113767">"Виджеттер тізімі"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Видджеттер тізімі жабылды"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Негізгі экранға қосу"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index b0a3234..7545216 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -72,7 +72,7 @@
     <string name="all_apps_button_personal_label" msgid="1315764287305224468">"បញ្ជី​កម្មវិធី​ផ្ទាល់ខ្លួន"</string>
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"បញ្ជី​កម្មវិធី​ការងារ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"យកចេញ"</string>
-    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"លុបការដំឡើង"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"លុប"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ព័ត៌មាន​កម្មវិធី"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ដំឡើង"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"កុំណែនាំកម្មវិធី"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"កំពុង​ដំឡើង <xliff:g id="NAME">%1$s</xliff:g>, បាន​បញ្ចប់ <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"កំពុងដោនឡូត <xliff:g id="NAME">%1$s</xliff:g> បានបញ្ចប់ <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> កំពុងរង់ចាំការដំឡើង"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"តម្រូវឱ្យមាន​កំណែកម្មវិធីថ្មី"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"កម្មវិធីសម្រាប់​រូបតំណាងនេះ​មិនត្រូវបានដំឡើងកំណែ​ទេ។ អ្នកអាច​ដំឡើងកំណែ​ដោយផ្ទាល់ ដើម្បីបើក​ផ្លូវកាត់នេះឡើងវិញ ឬលុបរូបតំណាងនេះ។"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"ដំឡើងកំណែ"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"លុប"</string>
     <string name="widgets_list" msgid="796804551140113767">"បញ្ជីធាតុ​ក្រាហ្វិក"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"បាន​បិទ​បញ្ជីធាតុ​ក្រាហ្វិក"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"បញ្ចូល​ទៅក្នុង​អេក្រង់​ដើម"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 7d9f8d9..b2aa1d9 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -47,7 +47,7 @@
     <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"ಹುಡುಕಿ"</string>
     <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"ಹುಡುಕಾಟ ಪೆಟ್ಟಿಗೆಯಿಂದ ಪಠ್ಯವನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
     <string name="no_widgets_available" msgid="4337693382501046170">"ವಿಜೆಟ್‌ಗಳು ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
-    <string name="no_search_results" msgid="3787956167293097509">"ಯಾವುದೇ ವಿಜೆಟ್‌ಗಳು ಅಥವಾ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
+    <string name="no_search_results" msgid="3787956167293097509">"ಯಾವುದೇ ವಿಜೆಟ್‌ಗಳು ಅಥವಾ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು ಪತ್ತೆಯಾಗಿಲ್ಲ"</string>
     <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"ವೈಯಕ್ತಿಕ"</string>
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ಕೆಲಸ"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"ಸಂಭಾಷಣೆಗಳು"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ, <xliff:g id="PROGRESS">%2$s</xliff:g> ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ, <xliff:g id="PROGRESS">%2$s</xliff:g> ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ಸ್ಥಾಪಿಸಲು ಕಾಯಲಾಗುತ್ತಿದೆ"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"ಆ್ಯಪ್ ಅಪ್‌ಡೇಟ್ ಅಗತ್ಯವಿದೆ"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"ಈ ಐಕಾನ್‌ಗಾಗಿ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿಲ್ಲ. ಈ ಶಾರ್ಟ್‌ಕಟ್ ಅನ್ನು ಮರು-ಸಕ್ರಿಯಗೊಳಿಸಲು ನೀವು ಹಸ್ತಚಾಲಿತವಾಗಿ ಅಪ್‌ಡೇಟ್ ಮಾಡಬಹುದು ಅಥವಾ ಐಕಾನ್ ಅನ್ನು ತೆಗೆದುಹಾಕಬಹುದು."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"ಅಪ್‌ಡೇಟ್ ಮಾಡಿ"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"ತೆಗೆದುಹಾಕಿ"</string>
     <string name="widgets_list" msgid="796804551140113767">"ವಿಜೆಟ್ ಪಟ್ಟಿ"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ವಿಜೆಟ್ ಪಟ್ಟಿಯನ್ನು ಮುಚ್ಚಲಾಗಿದೆ"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಸೇರಿಸಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 22a9b3c..ac2cb02 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> 설치 중, <xliff:g id="PROGRESS">%2$s</xliff:g> 완료"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> 다운로드 중, <xliff:g id="PROGRESS">%2$s</xliff:g> 완료"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> 설치 대기 중"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"앱 업데이트 필요"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"바로가기 아이콘의 앱이 업데이트되지 않았습니다. 직접 업데이트하여 앱 바로가기를 다시 사용할 수 있도록 하거나 아이콘을 삭제하세요."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"업데이트"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"삭제"</string>
     <string name="widgets_list" msgid="796804551140113767">"위젯 목록"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"위젯 목록 닫힘"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"홈 화면에 추가"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index c235b3d..98be10a 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> орнотулууда, <xliff:g id="PROGRESS">%2$s</xliff:g> аткарылды"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> жүктөлүп алынууда, <xliff:g id="PROGRESS">%2$s</xliff:g> аяктады"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> орнотулушу күтүлүүдө"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Колдонмону жаңыртыңыз"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Бул сүрөтчөнүн колдонмосу жаңыртылган эмес. Ыкчам баскычты кайра иштетүү үчүн аны кол менен жаңыртып же сүрөтчөнү өчүрүп койсоңуз болот."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Жаңыртуу"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Өчүрүү"</string>
     <string name="widgets_list" msgid="796804551140113767">"Виджеттердин тизмеси"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Виджеттердин тизмеси жабык"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Башкы экранга кошуу"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 66ff43d..9aafa18 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"ກຳລັງຕິດຕັ້ງ <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> ສຳເລັດແລ້ວ"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ກຳ​ລັງ​ດາວ​ໂຫຼດ, <xliff:g id="PROGRESS">%2$s</xliff:g> ສຳ​ເລັດ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ກຳ​ລັງ​ລໍ​ຖ້າ​ຕິດ​ຕັ້ງ"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"ຈຳເປັນຕ້ອງອັບເດດແອັບ"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"ບໍ່ໄດ້ອັບເດດແອັບສຳລັບໄອຄອນນີ້. ທ່ານສາມາດອັບເດດເອງໄດ້ເພື່ອເປີດການນຳໃຊ້ທາງລັດນີ້ຄືນໃໝ່ ຫຼື ລຶບໄອຄອນດັ່ງກ່າວອອກ."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"ອັບເດດ"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"ລຶບອອກ"</string>
     <string name="widgets_list" msgid="796804551140113767">"ລາຍຊື່ວິດເຈັດ"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ປິດລາຍຊື່ວິດເຈັດແລ້ວ"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"ເພີ່ມໃສ່ໂຮມສະກຣີນ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 66933ac..888a8f7 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Įdiegiama: „<xliff:g id="NAME">%1$s</xliff:g>“; baigta: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Atsisiunčiama programa „<xliff:g id="NAME">%1$s</xliff:g>“, <xliff:g id="PROGRESS">%2$s</xliff:g> baigta"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Laukiama, kol bus įdiegta programa „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Būtina atnaujinti programą"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Šios piktogramos programa neatnaujinta. Galite patys atnaujinti, kad iš naujo įgalintumėte šį spartųjį klavišą, arba pašalinkite piktogramą."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Atnaujinti"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Pašalinti"</string>
     <string name="widgets_list" msgid="796804551140113767">"Valdiklių sąrašas"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Valdiklių sąrašas uždarytas"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Pridėti prie pagrind. ekrano"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 3eed085..3127ca8 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Notiek lietotnes “<xliff:g id="NAME">%1$s</xliff:g>” instalēšana. Norise: <xliff:g id="PROGRESS">%2$s</xliff:g>."</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Lietotnes <xliff:g id="NAME">%1$s</xliff:g> lejupielāde (<xliff:g id="PROGRESS">%2$s</xliff:g> pabeigti)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Notiek <xliff:g id="NAME">%1$s</xliff:g> instalēšana"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Lietotne ir jāatjaunina"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Šai ikonai paredzētā lietotne nav atjaunināta. Varat to atjaunināt manuāli, lai atkārtoti iespējotu šo saīsni, vai noņemt ikonu."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Atjaunināt"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Noņemt"</string>
     <string name="widgets_list" msgid="796804551140113767">"Logrīku saraksts"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Logrīku saraksts aizvērts"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Pievienot sākuma ekrānam"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index a45391f..2d87df8 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -77,7 +77,7 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апликација"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закачи го предвидувањето"</string>
-    <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирај кратенки"</string>
+    <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање кратенки"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Овозможува апликацијата да додава кратенки без интервенција на корисникот."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"да чита поставки и кратенки на почетна страница"</string>
     <string name="permdesc_read_settings" msgid="4208061150510996676">"Овозможува апликацијата да ги чита поставките и кратенките на почетната страница."</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> завршено"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Се презема <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> завршено"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека да се инсталира"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Потребно е ажурирање на апликацијата"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Апликацијата за оваа икона не е ажурирана. Може да ажурирате рачно за да повторно се овозможи кратенкава или отстранете ја иконата."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Ажурирај"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Отстрани"</string>
     <string name="widgets_list" msgid="796804551140113767">"Список со виџети"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Списокот со виџети е затворен"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Додај на почетниот екран"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 5a1ee03..b548002 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -72,7 +72,7 @@
     <string name="all_apps_button_personal_label" msgid="1315764287305224468">"വ്യക്തിഗത ആപ്പുകളുടെ ലിസ്റ്റ്"</string>
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"ഔദ്യോഗിക ആപ്പുകളുടെ ലിസ്റ്റ്"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"നീക്കംചെയ്യുക"</string>
-    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"അൺഇൻസ്റ്റാളുചെയ്യുക"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"അൺഇൻസ്റ്റാൾ"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ആപ്പ് വിവരങ്ങൾ"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്‌റ്റാൾ ചെയ്യുക"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കരുത്"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ഇൻസ്‌റ്റാൾ ചെയ്യുന്നു, <xliff:g id="PROGRESS">%2$s</xliff:g> പൂർത്തിയായി"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ഡൗൺലോഡ് ചെയ്യുന്നു, <xliff:g id="PROGRESS">%2$s</xliff:g> പൂർത്തിയായി"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"ഇൻസ്റ്റാൾ ചെയ്യാൻ <xliff:g id="NAME">%1$s</xliff:g> കാക്കുന്നു"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"ആപ്പ് അപ്‌ഡേറ്റ് ചെയ്യേണ്ടതുണ്ട്"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"ഈ ഐക്കണിനുള്ള ആപ്പ് അപ്‌ഡേറ്റ് ചെയ്തിട്ടില്ല. ഈ കുറുക്കുവഴി വീണ്ടും പ്രവർത്തനക്ഷമമാക്കാൻ നിങ്ങൾക്ക് നേരിട്ട് അപ്‌ഡേറ്റ് ചെയ്യാം അല്ലെങ്കിൽ ഐക്കൺ നീക്കം ചെയ്യാം."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"അപ്ഡേറ്റ് ചെയ്യുക"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"നീക്കം ചെയ്യുക"</string>
     <string name="widgets_list" msgid="796804551140113767">"വിജറ്റുകളുടെ ലിസ്‌റ്റ്"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"വിജറ്റുകളുടെ ലിസ്‌റ്റ് അവസാനിപ്പിച്ചു"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"ഹോം സ്‌ക്രീനിലേക്ക് ചേർക്കുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index b222ba9..a4daad1 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g>-г суулгаж байна. <xliff:g id="PROGRESS">%2$s</xliff:g> дууссан"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>-г татаж байна, <xliff:g id="PROGRESS">%2$s</xliff:g> татсан"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> нь суулгахыг хүлээж байна"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Аппын шинэчлэлт шаардлагатай"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Энэ дүрс тэмдгийн аппыг шинэчлээгүй. Та энэ товчлолыг дахин идэвхжүүлэх эсвэл дүрсийг хасахын тулд гараар шинэчлэх боломжтой."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Шинэчлэх"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Хасах"</string>
     <string name="widgets_list" msgid="796804551140113767">"Жижиг хэрэгслийн жагсаалт"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Жижиг хэрэгслийн жагсаалтыг хаасан"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Үндсэн нүүрэнд нэмэх"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 0f03074..30fb4ad 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल करत आहे, <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण झाले"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड होत आहे , <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण झाले"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल करण्याची प्रतिक्षा करत आहे"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"अ‍ॅप अपडेट करणे आवश्‍यक आहे"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"या आयकनसाठी अ‍ॅप अपडेट केलेले नाही. हा शॉटकर्ट पुन्हा सुरू करण्यासाठी तुम्ही मॅन्युअली अपडेट करू शकता किंवा आयकन काढून टाका."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"अपडेट करा"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"काढून टाका"</string>
     <string name="widgets_list" msgid="796804551140113767">"विजेट सूची"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"विजेट सूची बंद केली"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"होम स्क्रीनवर जोडा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index f24038c..ddd8dc8 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> dipasang, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> memuat turun, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> menunggu untuk dipasang"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Kemas kini apl diperlukan"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Apl untuk ikon ini tidak dikemas kini. Anda boleh mengemas kini secara manual untuk mendayakan semula pintasan atau mengalih keluar ikon."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Kemas kini"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Alih keluar"</string>
     <string name="widgets_list" msgid="796804551140113767">"Senarai widget"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Senarai widget ditutup"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Tambahkan pada skrin utama"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index c53b912..ea966d3 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -72,7 +72,7 @@
     <string name="all_apps_button_personal_label" msgid="1315764287305224468">"တစ်ကိုယ်ရေသုံး အက်ပ်စာရင်း"</string>
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"အလုပ်သုံး အက်ပ်စာရင်း"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ဖယ်ရှားမည်"</string>
-    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ဖြုတ်ရန်"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ဖယ်ရှားရန်"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"အက်ပ်အချက်အလက်"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ထည့်သွင်းရန်"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"အက်ပ်ကို အကြံမပြုပါနှင့်"</string>
@@ -124,20 +124,16 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ကို ထည့်သွင်းနေသည်၊ <xliff:g id="PROGRESS">%2$s</xliff:g> ပြီးပါပြီ"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ဒေါင်းလုဒ်လုပ်နေသည်၊ <xliff:g id="PROGRESS">%2$s</xliff:g> ပြီးပါပြီ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ကိုထည့်သွင်းရန်စောင့်နေသည်"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"အက်ပ်ကို အပ်ဒိတ်လုပ်ရန် လိုအပ်သည်"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"ဤသင်္ကေတအတွက် အက်ပ်ကို အပ်ဒိတ်လုပ်မထားပါ။ ဤဖြတ်လမ်းလင့်ခ်ကို ပြန်ဖွင့်ရန် ကိုယ်တိုင်အပ်ဒိတ်လုပ်နိုင်သည် (သို့) သင်္ကေတကို ဖယ်ရှားနိုင်သည်။"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"အပ်ဒိတ်လုပ်ရန်"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"ဖယ်ရှားရန်"</string>
     <string name="widgets_list" msgid="796804551140113767">"ဝိဂျက်စာရင်း"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ဝိဂျက်စာရင်းကို ပိတ်ထားသည်"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"ပင်မစာမျက်နှာတွင် ထည့်ရန်"</string>
     <string name="action_move_here" msgid="2170188780612570250">"၎င်းအား ဤသို့ ရွှေ့ပါ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ပင်မ ဖန်မျက်နှာပြင်သို့ ထည့်ပြီး၏"</string>
-    <string name="item_removed" msgid="851119963877842327">"၎င်းအား ဖယ်ရှားပြီး၏"</string>
+    <string name="item_removed" msgid="851119963877842327">"ဖယ်ရှားပြီးပြီ"</string>
     <string name="undo" msgid="4151576204245173321">"နောက်ပြန်ရန်"</string>
     <string name="action_move" msgid="4339390619886385032">"၎င်းအား ရွှေ့ပါ"</string>
     <string name="move_to_empty_cell" msgid="2833711483015685619">"အတန်း <xliff:g id="NUMBER_0">%1$s</xliff:g> အတိုင် <xliff:g id="NUMBER_1">%2$s</xliff:g> သို့ ရွှေ့ပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 416f204..d55c484 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installerer, <xliff:g id="PROGRESS">%2$s</xliff:g> er fullført"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Laster ned <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> er fullført"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Venter på å installere <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Appen må oppdateres"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Appen for dette ikonet er ikke oppdatert. Du kan oppdatere manuelt for å aktivere denne snarveien igjen, eller du kan fjerne ikonet."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Oppdater"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Fjern"</string>
     <string name="widgets_list" msgid="796804551140113767">"Modulliste"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Modullisten er lukket"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Legg til på startskjermen"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 1e212be..01f0f54 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -72,7 +72,7 @@
     <string name="all_apps_button_personal_label" msgid="1315764287305224468">"व्यक्तिगत अनुप्रयोगहरूको सूची"</string>
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"कार्यसम्बन्धी अनुप्रयोगहरूको सूची"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"हटाउनुहोस्"</string>
-    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"विस्थापित गर्नुहोस्"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइन्स्टल गर्नुहोस्"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"एपसम्बन्धी जानकारी"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"यो एप सिफारिस नगरियोस्"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> इन्स्टल गरिँदै छ, <xliff:g id="PROGRESS">%2$s</xliff:g> पूरा भयो"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड गर्दै, <xliff:g id="PROGRESS">%2$s</xliff:g> सम्पन्‍न"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> स्थापना गर्न प्रतीक्षा गर्दै"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"एप अपडेट गरिनु पर्छ"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"यो आइकनले जनाउने एप अपडेट गरिएको छैन। तपाईं यो सर्टकट फेरि अन गर्न म्यानुअल रूपमा अपडेट गर्न सक्नुहुन्छ वा आइकन नै हटाउनुहोस्।"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"अपडेट गर्नुहोस्"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"हटाउनुहोस्"</string>
     <string name="widgets_list" msgid="796804551140113767">"विजेटहरूको सूची"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"विजेटहरूको सूची बन्द गरियो"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"होम स्क्रिनमा राख्नुहोस्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index d534bc4..4289d05 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeren, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> wordt gedownload, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> wacht op installatie"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"App-update vereist"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"De app voor dit icoon is niet geüpdatet. Je kunt handmatig updaten om deze snelkoppeling weer aan te zetten of het icoon verwijderen."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Updaten"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Verwijderen"</string>
     <string name="widgets_list" msgid="796804551140113767">"Lijst met widgets"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Lijst met widgets gesloten"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Toevoegen aan startscherm"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 2bfb8a1..00e33b8 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍ କରାଯାଉଛି, <xliff:g id="PROGRESS">%2$s</xliff:g> ସମ୍ପୂର୍ଣ୍ଣ ହୋଇଛି"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ଡାଉନଲୋଡ୍‌ ହେଉଛି, <xliff:g id="PROGRESS">%2$s</xliff:g> ସମ୍ପୂର୍ଣ୍ଣ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍‌ ହେବାକୁ ଅପେକ୍ଷା କରିଛି"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"ଆପକୁ ଅପଡେଟ କରିବା ଆବଶ୍ୟକ"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"ଏହି ଆଇକନ ପାଇଁ ଆପକୁ ଅପଡେଟ କରାଯାଇନାହିଁ। ଏହି ସର୍ଟକଟକୁ ପୁଣି-ସକ୍ଷମ କରିବା ପାଇଁ ଆପଣ ମାନୁଆଲୀ ଅପଡେଟ କରିପାରିବେ କିମ୍ବା ଆଇକନଟିକୁ କାଢ଼ି ଦେଇପାରିବେ।"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"ଅପଡେଟ କରନ୍ତୁ"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"କାଢ଼ି ଦିଅନ୍ତୁ"</string>
     <string name="widgets_list" msgid="796804551140113767">"ୱିଜେଟ୍ ତାଲିକା"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ୱିଜେଟ୍ ତାଲିକା ବନ୍ଦ ହୋଇଛି"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"ମୂଳସ୍କ୍ରିନରେ ଯୋଗ କରନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 222247b..5dae6a4 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ਨੂੰ ਸਥਾਪਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ, <xliff:g id="PROGRESS">%2$s</xliff:g> ਪੂਰਾ ਹੋਇਆ"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ਡਾਉਨਲੋਡ ਹੋਰ ਰਿਹਾ ਹੈ, <xliff:g id="PROGRESS">%2$s</xliff:g> ਸੰਪੂਰਣ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ਸਥਾਪਤ ਕਰਨ ਦੀ ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"ਐਪ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਲੋੜ ਹੈ"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"ਇਸ ਪ੍ਰਤੀਕ ਲਈ ਐਪ ਨੂੰ ਅੱਪਡੇਟ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ। ਇਸ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਮੁੜ-ਚਾਲੂ ਕਰਨ ਜਾਂ ਪ੍ਰਤੀਕ ਨੂੰ ਹਟਾਉਣ ਲਈ ਤੁਸੀਂ ਹੱਥੀਂ ਅੱਪਡੇਟ ਕਰ ਸਕਦੇ ਹੋ।"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"ਅੱਪਡੇਟ ਕਰੋ"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"ਹਟਾਓ"</string>
     <string name="widgets_list" msgid="796804551140113767">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ ਬੰਦ ਕੀਤੀ ਗਈ"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index a7c1c18..ceca83c 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instaluję aplikację <xliff:g id="NAME">%1$s</xliff:g>, postęp: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Pobieranie elementu <xliff:g id="NAME">%1$s</xliff:g>, ukończono: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> oczekuje na instalację"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Wymagana aktualizacja aplikacji"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacja z tą ikoną nie jest aktualizowana. Możesz zaktualizować ją ręcznie, aby ponownie uruchomić ten skrót, lub usunąć ikonę."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Aktualizuj"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Usuń"</string>
     <string name="widgets_list" msgid="796804551140113767">"Lista widgetów"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Lista widgetów zamknięta"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Dodaj do ekranu głównego"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 6cb77d7..61c1ee0 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"A instalar <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"A transferir o <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"A aguardar a instalação do <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Atualização da app necessária"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"A app deste ícone não está atualizada. Pode atualizar manualmente para reativar este atalho ou remover o ícone."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Atualizar"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Remover"</string>
     <string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgets fechada."</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Adicionar ao ecrã principal"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 40edba2..340934c 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instalando <xliff:g id="NAME">%1$s</xliff:g>. <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Fazendo download de <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Aguardando instalação de <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Atualização obrigatória do app"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"O app desse ícone não está atualizado. Você pode remover o ícone ou atualizar o app manualmente para reativar esse atalho."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Atualizar"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Remover"</string>
     <string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgets fechada"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Adicionar à tela inicial"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 85703dd..43462d8 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se instalează, <xliff:g id="PROGRESS">%2$s</xliff:g> finalizat"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se descarcă (finalizat <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> așteaptă instalarea"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Este necesară actualizarea aplicației"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplicația pentru această pictogramă nu este actualizată. Puteți să actualizați manual ca să reactivați comanda rapidă sau să eliminați pictograma."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Actualizați"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Eliminați"</string>
     <string name="widgets_list" msgid="796804551140113767">"Listă de widgeturi"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgeturi este închisă"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Adăugați pe ecranul de pornire"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 90add40..0fa3280 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Установка приложения \"<xliff:g id="NAME">%1$s</xliff:g>\" (выполнено <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Скачивается \"<xliff:g id="NAME">%1$s</xliff:g>\" (<xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Ожидание установки \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Обновите приложение"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Эта версия приложения устарела. Обновите его вручную, чтобы снова пользоваться ярлыком, или удалите значок."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Обновить"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Удалить"</string>
     <string name="widgets_list" msgid="796804551140113767">"Список виджетов"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Список виджетов закрыт"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Добавить на главный экран"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 61b91c6..f77746a 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ස්ථාපනය කරමින්, <xliff:g id="PROGRESS">%2$s</xliff:g> සම්පූර්ණයි"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> බාගත කරමින්, <xliff:g id="PROGRESS">%2$s</xliff:g> සම්පූර්ණයි"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ස්ථාපනය කිරීමට බලා සිටිමින්"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"යෙදුම් යාවත්කාලීනයක් අවශ්‍යයි"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"මෙම නිරූපකය සඳහා යෙදුම යාවත්කාලීන කර නැත. ඔබට මෙම කෙටි මඟ යළි සබල කිරීමට හෝ නිරූපකය ඉවත් කිරීමට හස්තීයව යාවත්කාලීන කළ හැකිය."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"යාවත්කාලීන කරන්න"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"ඉවත් කරන්න"</string>
     <string name="widgets_list" msgid="796804551140113767">"විජට් ලැයිස්තුව"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"විජට් ලැයිස්තුව වසා ඇත"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"මුල් තිරය වෙත එක් කරන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index f85c1f5..212e5f3 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Inštaluje sa <xliff:g id="NAME">%1$s</xliff:g>. Dokončené: <xliff:g id="PROGRESS">%2$s</xliff:g>."</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Sťahuje sa aplikácia <xliff:g id="NAME">%1$s</xliff:g>. Stiahnuté: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Aplikácia <xliff:g id="NAME">%1$s</xliff:g> čaká na inštaláciu"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Vyžaduje sa aktualizácia aplikácie"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplikácia, ktorú zastupuje táto ikona, nie je aktualizovaná. Môžete ju ručne aktualizovať, aby odkaz znova fungoval, prípadne môžete ikonu odstrániť."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Aktualizovať"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Odstrániť"</string>
     <string name="widgets_list" msgid="796804551140113767">"Zoznam miniaplikácií"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Zoznam miniaplikácií je zavretý"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Pridať na plochu"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index f374fca..6debc8a 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -124,20 +124,16 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se namešča, dokončano: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Prenašanje aplikacije <xliff:g id="NAME">%1$s</xliff:g>; preneseno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Aplikacija <xliff:g id="NAME">%1$s</xliff:g> čaka na namestitev"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Zahtevana je posodobitev aplikacije"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacija za to ikono ni posodobljena. Lahko jo ročno posodobite, da znova omogočite to bližnjico, ali pa odstranite ikono."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Posodobi"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Odstrani"</string>
     <string name="widgets_list" msgid="796804551140113767">"Seznam pripomočkov"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Seznam pripomočkov se je zaprl"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Dodajanje na začetni zaslon"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Premik elementa sem"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Element je bil dodan na začetni zaslon"</string>
-    <string name="item_removed" msgid="851119963877842327">"Element je bil odstranjen"</string>
+    <string name="item_removed" msgid="851119963877842327">"Element je bil odstranjen."</string>
     <string name="undo" msgid="4151576204245173321">"Razveljavi"</string>
     <string name="action_move" msgid="4339390619886385032">"Premik elementa"</string>
     <string name="move_to_empty_cell" msgid="2833711483015685619">"Premik v <xliff:g id="NUMBER_0">%1$s</xliff:g>. vrstico <xliff:g id="NUMBER_1">%2$s</xliff:g>. stolpca"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 31af388..9931752 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> po instalohet, <xliff:g id="PROGRESS">%2$s</xliff:g> i përfunduar"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> po shkarkohet, <xliff:g id="PROGRESS">%2$s</xliff:g> të përfunduara"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> po pret të instalohet"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Kërkohet përditësimi i aplikacionit"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacioni për këtë ikonë nuk është përditësuar. Mund ta përditësosh manualisht për të riaktivizuar këtë shkurtore ose hiq ikonën."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Përditëso"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Hiq"</string>
     <string name="widgets_list" msgid="796804551140113767">"Lista e miniaplikacioneve"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Lista e miniaplikacioneve u mbyll"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Shto në ekranin bazë"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 6b5fe2b..d5f1bd2 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> готово"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> се преузима, завршено је <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека на инсталирање"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Треба да ажурирате апликацију"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Апликација за ову икону није ажурирана. Можете да је ручно ажурирате да бисте поново омогућили ову пречицу или уклоните икону."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Ажурирај"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Уклони"</string>
     <string name="widgets_list" msgid="796804551140113767">"Листа виџета"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Листа виџета је затворена"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Додајте на почетни екран"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index a8c4d1b..a3f8de4 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeras. <xliff:g id="PROGRESS">%2$s</xliff:g> har slutförts"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> laddas ned, <xliff:g id="PROGRESS">%2$s</xliff:g> klart"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> väntar på installation"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Du måste uppdatera appen"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Appen för den här ikonen har inte uppdaterats. Du kan uppdatera den manuellt för att återaktivera genvägen eller ta bort ikonen."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Uppdatera"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Ta bort"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widgetlista"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Widgetslistan har stängts"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Lägg till på startskärmen"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 1a7f2a4..0a4e510 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -72,7 +72,7 @@
     <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Orodha ya programu za binafsi"</string>
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"Orodha ya programu za kazini"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ondoa"</string>
-    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Sakinua"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ondoa"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Maelezo ya programu"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Sakinisha"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Isipendekeze programu"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Inasakinisha <xliff:g id="NAME">%1$s</xliff:g>, imekamilika <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> inapakuliwa, <xliff:g id="PROGRESS">%2$s</xliff:g> imekamilika"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> inasubiri kusakinisha"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Unahitaji kusasisha programu"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Programu ya aikoni hii haijasasishwa. Unaweza kusasisha mwenyewe ili uruhusu upya njia hii ya mkato au uondoe aikoni."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Sasisha"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Ondoa"</string>
     <string name="widgets_list" msgid="796804551140113767">"Orodha ya wijeti"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Orodha ya wijeti imefungwa"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Weka kwenye skrini ya kwanza"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index b9c7cb5..e7b5c9b 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> நிறுவப்படுகிறது, <xliff:g id="PROGRESS">%2$s</xliff:g> முடிந்தது"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>ஐப் பதிவிறக்குகிறது, <xliff:g id="PROGRESS">%2$s</xliff:g> முடிந்தது"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>ஐ நிறுவுவதற்காகக் காத்திருக்கிறது"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"ஆப்ஸைப் புதுப்பியுங்கள்"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"இந்த ஐகானுக்கான ஆப்ஸ் புதுப்பிக்கப்படவில்லை. இந்த ஷார்ட்கட்டை மீண்டும் இயக்கவோ ஐகானை அகற்றவோ நீங்களாகவே புதுப்பிக்கலாம்."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"புதுப்பி"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"அகற்று"</string>
     <string name="widgets_list" msgid="796804551140113767">"விட்ஜெட்கள் பட்டியல்"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"விட்ஜெட்கள் பட்டியல் மூடப்பட்டது"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"முகப்புத் திரையில் சேர்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 0976af7..a866da9 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -72,7 +72,7 @@
     <string name="all_apps_button_personal_label" msgid="1315764287305224468">"వ్యక్తిగత యాప్‌ల లిస్ట్‌"</string>
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"కార్యాలయ యాప్‌ల లిస్ట్‌"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"తీసివేయి"</string>
-    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"అన్ఇన్‌స్టాల్ చేయి"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"అన్ఇన్‌స్టాల్ చేయండి"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"యాప్ సమాచారం"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ఇన్‌స్టాల్ చేయండి"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"యాప్‌ను సూచించవద్దు"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g>‌ను ఇన్‌స్టాల్ చేయడం, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> డౌన్‌లోడ్ అవుతోంది, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ఇన్‌స్టాల్ కావడానికి వేచి ఉంది"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"యాప్‌ను అప్‌డేట్ చేయడం అవసరం"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"ఈ చిహ్నం కోసం యాప్ అప్‌డేట్ చేయబడలేదు. మీరు ఈ షార్ట్‌కట్‌ను మళ్లీ ఎనేబుల్ చేయడానికి మాన్యువల్‌గా అప్‌డేట్ చేయవచ్చు లేదా చిహ్నాన్ని తీసివేయవచ్చు."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"అప్‌డేట్ చేయండి"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"తీసివేయండి"</string>
     <string name="widgets_list" msgid="796804551140113767">"విడ్జెట్‌ల లిస్ట్‌"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"విడ్జెట్‌ల లిస్ట్‌ మూసివేయబడింది"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"మొదటి స్క్రీన్‌కు జోడించండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 6423bb4..aef06da 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"กำลังติดตั้ง <xliff:g id="NAME">%1$s</xliff:g> เสร็จแล้ว <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"กำลังดาวน์โหลด <xliff:g id="NAME">%1$s</xliff:g> เสร็จแล้ว <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> กำลังรอติดตั้ง"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"ต้องอัปเดตแอป"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"แอปสำหรับไอคอนนี้ยังไม่ได้อัปเดต คุณอัปเดตด้วยตนเองได้โดยเปิดใช้ทางลัดนี้อีกครั้งหรือนำไอคอนออก"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"อัปเดต"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"นำออก"</string>
     <string name="widgets_list" msgid="796804551140113767">"รายการวิดเจ็ต"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ปิดรายการวิดเจ็ตแล้ว"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"เพิ่มลงในหน้าจอหลัก"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index a737102..572a38f 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Ini-install ang <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> kumpleto"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Dina-download na ang <xliff:g id="NAME">%1$s</xliff:g>, tapos na ang <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Hinihintay nang mag-install ang <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Kinakailangang i-update ang app"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Hindi updated ang app para sa icon na ito. Puwede kang manual na mag-update para ma-enable ulit ang shortcut na ito, o alisin ang icon."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"I-update"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Alisin"</string>
     <string name="widgets_list" msgid="796804551140113767">"Listahan ng mga widget"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Nakasara ang listahan ng mga widget"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Idagdag sa home screen"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index b74e52b..7582461 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -124,20 +124,16 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> yükleniyor, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> indiriliyor, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> uygulaması yüklenmek için bekliyor"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Uygulama güncellemesi gerekli"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Bu simgenin uygulaması güncellenmemiş. Simgeyi kaldırabilir ya da uygulamayı manuel olarak güncelleyerek bu kısayolu yeniden etkinleştirebilirsiniz."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Güncelle"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Kaldır"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widget listesi"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Widget listesi kapalı"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Ana ekrana ekle"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Öğeyi buraya taşı"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Öğe ana ekrana eklendi"</string>
-    <string name="item_removed" msgid="851119963877842327">"Öğe kaldırıldı"</string>
+    <string name="item_removed" msgid="851119963877842327">"Öğe silindi"</string>
     <string name="undo" msgid="4151576204245173321">"Geri al"</string>
     <string name="action_move" msgid="4339390619886385032">"Öğeyi taşı"</string>
     <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g>. satır <xliff:g id="NUMBER_1">%2$s</xliff:g>. sütuna taşı"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 619b993..cacf898 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> встановлюється, виконано <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> завантажується, <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> очікує на завантаження"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Потрібно оновити додаток"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Додаток для цього значка не оновлено. Ви можете оновити його вручну, щоб знову ввімкнути цю швидку команду, або можете вилучити значок."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Оновити"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Вилучити"</string>
     <string name="widgets_list" msgid="796804551140113767">"Список віджетів"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Список віджектів закрито"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Додати на головний екран"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 3fdad53..67d0489 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> انسٹال کی جا رہی ہے، <xliff:g id="PROGRESS">%2$s</xliff:g> مکمل ہو گئی"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ڈاؤن لوڈ ہو رہا ہے، <xliff:g id="PROGRESS">%2$s</xliff:g> مکمل ہو گیا"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> انسٹال ہونے کا انتظار کر رہی ہے"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"ایپ کی اپ ڈیٹ درکار ہے"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"اس آئیکن کیلئے ایپ کو اپ ڈیٹ نہیں کیا گیا ہے۔ آپ اس شارٹ کٹ کو دوبارہ فعال کرنے کے لیے دستی طور پر اپ ڈیٹ کر سکتے ہیں، یا آئیکن کو ہٹا سکتے ہیں۔"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"اپ ڈیٹ کریں"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"ہٹائیں"</string>
     <string name="widgets_list" msgid="796804551140113767">"ویجیٹس کی فہرست"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ویجیٹس کی فہرست بند کر دی گئی"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"ہوم اسکرین میں شامل کریں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 58f1f4e..c0267f8 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> oʻrnatlmoqda, <xliff:g id="PROGRESS">%2$s</xliff:g> yakunlandi"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> yuklab olinmoqda, <xliff:g id="PROGRESS">%2$s</xliff:g> bajarildi"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi o‘rnatilishi kutilmoqda"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Ilovani yangilash zarur"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Bu belgi uchun ilova yangilanmagan. Ushbu yorliqni qayta yoqish uchun oddiy usulda yangilashingiz yoki belgini olib tashlashingiz mumkin."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Yangilash"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Olib tashlash"</string>
     <string name="widgets_list" msgid="796804551140113767">"Vidjetlar ro‘yxati"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Vidjetlar ro‘yxati yopildi"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Bosh ekranga chiqarish"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 6a9a9b3..8e47f0c 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Đang cài đặt <xliff:g id="NAME">%1$s</xliff:g>, hoàn tất <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Đang tải xuống <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> hoàn tất"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Đang chờ cài đặt <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Cần cập nhật ứng dụng"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Ứng dụng cho biểu tượng này chưa được cập nhật. Bạn có thể cập nhật theo cách thủ công để bật lại phím tắt này hoặc xóa biểu tượng."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Cập nhật"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Xóa"</string>
     <string name="widgets_list" msgid="796804551140113767">"Danh sách tiện ích"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Đã đóng danh sách tiện ích"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Thêm vào màn hình chính"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index ea7d37e..2a80399 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -32,7 +32,7 @@
     <string name="split_screen_position_left" msgid="7537793098851830883">"左分屏"</string>
     <string name="split_screen_position_right" msgid="1569377524925193369">"右分屏"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的应用信息"</string>
-    <string name="long_press_widget_to_add" msgid="3587712543577675817">"轻触并按住微件即可移动该微件。"</string>
+    <string name="long_press_widget_to_add" msgid="3587712543577675817">"轻触并按住即可移动微件。"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"点按两次并按住微件即可移动该微件或使用自定义操作。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"宽 %1$d,高 %2$d"</string>
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"正在安装<xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"正在下载<xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>正在等待安装"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"需要更新应用"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"此图标对应的应用未更新。您可以手动更新以重新启用该快捷方式,或者移除此图标。"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"更新"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"移除"</string>
     <string name="widgets_list" msgid="796804551140113767">"微件列表"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"微件列表已关闭"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"添加到主屏幕"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 4e2c060..2d9b463 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"正在安裝「<xliff:g id="NAME">%1$s</xliff:g>」(已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"正在下載 <xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"正在等待安裝 <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"必須更新應用程式"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"您尚未更新這個圖示代表的應用程式。您可以手動更新以重新啟用此快速鍵,或者移除圖示。"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"更新"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"移除"</string>
     <string name="widgets_list" msgid="796804551140113767">"小工具清單"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"已經關閉嘅小工具清單"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"加去主畫面"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 8394459..5c2f3cc 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"正在安裝「<xliff:g id="NAME">%1$s</xliff:g>」(已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"正在下載「<xliff:g id="NAME">%1$s</xliff:g>」,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"正在等待安裝「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"必須更新應用程式"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"這個圖示代表的應用程式未更新。手動更新即可重新啟用這個捷徑,你也可以移除圖示。"</string>
+    <string name="dialog_update" msgid="2178028071796141234">"更新"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"移除"</string>
     <string name="widgets_list" msgid="796804551140113767">"小工具清單"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"已關閉小工具清單"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"新增至主畫面"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index dc378f7..cc09ea3 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -124,14 +124,10 @@
     <string name="app_installing_title" msgid="5864044122733792085">"I-<xliff:g id="NAME">%1$s</xliff:g> iyafakwa, seyiqede <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"I-<xliff:g id="NAME">%1$s</xliff:g> iyalandwa, <xliff:g id="PROGRESS">%2$s</xliff:g> kuqediwe"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ilinde ukufakwa"</string>
-    <!-- no translation found for dialog_update_title (114234265740994042) -->
-    <skip />
-    <!-- no translation found for dialog_update_message (4176784553982226114) -->
-    <skip />
-    <!-- no translation found for dialog_update (2178028071796141234) -->
-    <skip />
-    <!-- no translation found for dialog_remove (6510806469849709407) -->
-    <skip />
+    <string name="dialog_update_title" msgid="114234265740994042">"Kudingeka isibuyekezo se-app"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"I-app yalesi sithonjana ibuyekeziwe. Ungabuyekeza mathupha ukuze uphinde unike amandla lesi sinqamuleli, noma ususe isithonjana."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Vuselela"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Susa"</string>
     <string name="widgets_list" msgid="796804551140113767">"Uhlu lwamawijethi"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Uhlu lwamawijethi luvaliwe"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"Faka kusikrini sasekhaya"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 52ff3f0..098c694 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -100,7 +100,7 @@
     <dimen name="fastscroll_end_margin">-26dp</dimen>
 
     <!-- All Apps -->
-    <dimen name="all_apps_starting_vertical_translate">320dp</dimen>
+    <dimen name="all_apps_starting_vertical_translate">300dp</dimen>
     <dimen name="all_apps_search_bar_field_height">48dp</dimen>
     <!-- all_apps_search_bar_field_height / 2 -->
     <dimen name="all_apps_search_bar_content_overlap">24dp</dimen>
@@ -129,6 +129,7 @@
     <dimen name="all_apps_height_extra">6dp</dimen>
     <dimen name="all_apps_bottom_sheet_horizontal_padding">0dp</dimen>
     <dimen name="all_apps_paged_view_top_padding">40dp</dimen>
+    <dimen name="all_apps_personal_work_tabs_vertical_margin">16dp</dimen>
 
     <!-- The size of corner radius of the arrow in the arrow toast. -->
     <dimen name="arrow_toast_corner_radius">2dp</dimen>
@@ -148,10 +149,12 @@
     <dimen name="work_card_padding_horizontal">10dp</dimen>
     <dimen name="work_card_button_height">52dp</dimen>
     <dimen name="work_fab_margin">16dp</dimen>
+    <dimen name="work_fab_margin_bottom">20dp</dimen>
     <dimen name="work_mode_fab_padding">16dp</dimen>
     <dimen name="work_profile_footer_padding">20dp</dimen>
     <dimen name="work_edu_card_margin">16dp</dimen>
     <dimen name="work_edu_card_radius">16dp</dimen>
+    <dimen name="work_edu_card_bottom_margin">26dp</dimen>
 
     <dimen name="work_card_margin">24dp</dimen>
     <!-- (x) icon button inside work edu card -->
@@ -368,9 +371,7 @@
     <dimen name="overview_actions_height">0dp</dimen>
     <dimen name="overview_actions_button_spacing">0dp</dimen>
     <dimen name="overview_actions_margin_gesture">0dp</dimen>
-    <dimen name="overview_actions_top_margin_gesture">0dp</dimen>
-    <dimen name="overview_actions_bottom_margin_gesture">0dp</dimen>
-    <dimen name="overview_actions_margin_three_button">0dp</dimen>
+    <dimen name="overview_actions_top_margin">0dp</dimen>
     <dimen name="overview_grid_side_margin">0dp</dimen>
     <dimen name="overview_grid_row_spacing">0dp</dimen>
     <dimen name="overview_page_spacing">0dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ffa1e3f..ee5e024 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -428,7 +428,7 @@
     <string name="work_apps_paused_edu_accept">Got it</string>
 
     <!-- button string shown pause work profile -->
-    <string name="work_apps_pause_btn_text">Turn off work apps</string>
+    <string name="work_apps_pause_btn_text">Pause work apps</string>
     <!-- button string shown enable work profile -->
     <string name="work_apps_enable_btn_text">Turn on work apps</string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 864bb58..2109510 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -76,7 +76,7 @@
     </style>
 
     <style name="LauncherTheme.DarkMainColor" parent="@style/LauncherTheme">
-        <item name="disabledIconAlpha">.254</item>
+        <item name="disabledIconAlpha">.54</item>
 
     </style>
 
diff --git a/res/xml/paddings_6x5.xml b/res/xml/paddings_6x5.xml
index a958ec7..a72f554 100644
--- a/res/xml/paddings_6x5.xml
+++ b/res/xml/paddings_6x5.xml
@@ -32,7 +32,7 @@
     </device-padding>
 
     <device-padding
-        launcher:maxEmptySpace="80dp">
+        launcher:maxEmptySpace="170dp">
         <workspaceTopPadding
             launcher:a="0"
             launcher:b="20dp"/>
@@ -47,7 +47,7 @@
     </device-padding>
 
     <device-padding
-        launcher:maxEmptySpace="280dp">
+        launcher:maxEmptySpace="410dp">
         <workspaceTopPadding
             launcher:a="0"
             launcher:b="112dp"/>
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
similarity index 89%
rename from src/com/android/launcher3/FastScrollRecyclerView.java
rename to src/com/android/launcher3/BaseRecyclerView.java
index a60d143..b6d3fc5 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -23,7 +23,6 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityNodeInfo;
 
-import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -37,19 +36,19 @@
  *   <li> Enable fast scroller.
  * </ul>
  */
-public abstract class FastScrollRecyclerView extends RecyclerView  {
+public abstract class BaseRecyclerView extends RecyclerView  {
 
     protected RecyclerViewFastScroller mScrollbar;
 
-    public FastScrollRecyclerView(Context context) {
+    public BaseRecyclerView(Context context) {
         this(context, null);
     }
 
-    public FastScrollRecyclerView(Context context, AttributeSet attrs) {
+    public BaseRecyclerView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public FastScrollRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public BaseRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
     }
 
@@ -197,13 +196,6 @@
         if (mScrollbar != null) {
             mScrollbar.reattachThumbToScroll();
         }
-        if (getLayoutManager() instanceof LinearLayoutManager) {
-            LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
-            if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
-                // We are at the top, so don't scrollToPosition (would cause unnecessary relayout).
-                return;
-            }
-        }
         scrollToPosition(0);
     }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 74ec7ee..6302739 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -96,7 +96,6 @@
     private static final int MAX_SEARCH_LOOP_COUNT = 20;
 
     private static final int[] STATE_PRESSED = new int[]{android.R.attr.state_pressed};
-    private static final float HIGHLIGHT_SCALE = 1.16f;
 
     private final PointF mTranslationForReorderBounce = new PointF(0, 0);
     private final PointF mTranslationForReorderPreview = new PointF(0, 0);
@@ -259,6 +258,12 @@
         mDotParams.scale = 0f;
         mForceHideDot = false;
         setBackground(null);
+
+        setTag(null);
+        if (mIconLoadRequest != null) {
+            mIconLoadRequest.cancel();
+            mIconLoadRequest = null;
+        }
     }
 
     private void cancelDotScaleAnim() {
@@ -363,8 +368,7 @@
         }
     }
 
-    public void setBubbleTextHolder(
-            BubbleTextHolder bubbleTextHolder) {
+    public void setBubbleTextHolder(BubbleTextHolder bubbleTextHolder) {
         mBubbleTextHolder = bubbleTextHolder;
     }
 
@@ -1020,19 +1024,6 @@
         getIconBounds(mIconSize, bounds);
     }
 
-    private int getIconSizeForDisplay(int display) {
-        DeviceProfile grid = mActivity.getDeviceProfile();
-        switch (display) {
-            case DISPLAY_ALL_APPS:
-                return grid.allAppsIconSizePx;
-            case DISPLAY_FOLDER:
-                return grid.folderChildIconSizePx;
-            case DISPLAY_WORKSPACE:
-            default:
-                return grid.iconSizePx;
-        }
-    }
-
     public void getSourceVisualDragBounds(Rect bounds) {
         getIconBounds(mIconSize, bounds);
     }
@@ -1045,8 +1036,8 @@
     }
 
     private void resetIconScale() {
-        if (mIcon instanceof FastBitmapDrawable) {
-            ((FastBitmapDrawable) mIcon).resetScale();
+        if (mIcon != null) {
+            mIcon.resetScale();
         }
     }
 
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index af85594..4daca8b 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -7,15 +7,19 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.os.Bundle;
+import android.os.Process;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.util.Thunk;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -23,6 +27,7 @@
 
 import java.io.IOException;
 import java.net.URISyntaxException;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -43,6 +48,8 @@
     private static final String ATTR_CONTAINER = "container";
     private static final String ATTR_SCREEN = "screen";
     private static final String ATTR_FOLDER_ITEMS = "folderItems";
+    private static final String ATTR_SHORTCUT_ID = "shortcutId";
+    private static final String ATTR_PACKAGE_NAME = "packageName";
 
     // TODO: Remove support for this broadcast, instead use widget options to send bind time options
     private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
@@ -178,7 +185,6 @@
         }
     }
 
-
     /**
      * Shortcut parser which allows any uri and not just web urls.
      */
@@ -189,6 +195,35 @@
         }
 
         @Override
+        public int parseAndAdd(XmlPullParser parser) {
+            final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
+            final String shortcutId = getAttributeValue(parser, ATTR_SHORTCUT_ID);
+            if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(shortcutId)) {
+                return parseAndAddDeepShortcut(shortcutId, packageName);
+            }
+            return super.parseAndAdd(parser);
+        }
+
+        /**
+         * This method parses and adds a deep shortcut.
+         * @return item id if the shortcut is successfully added else -1
+         */
+        private int parseAndAddDeepShortcut(String shortcutId, String packageName) {
+            try {
+                LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
+                launcherApps.pinShortcuts(packageName, Collections.singletonList(shortcutId),
+                        Process.myUserHandle());
+                Intent intent = ShortcutKey.makeIntent(shortcutId, packageName);
+                mValues.put(Favorites.RESTORED, WorkspaceItemInfo.FLAG_RESTORED_ICON);
+                return addShortcut(null, intent, Favorites.ITEM_TYPE_DEEP_SHORTCUT);
+            } catch (Exception e) {
+                Log.e(TAG, "Unable to pin the shortcut for shortcut id = " + shortcutId
+                        + " and package name = " + packageName);
+            }
+            return -1;
+        }
+
+        @Override
         protected Intent parseIntent(XmlPullParser parser) {
             String uri = null;
             try {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 33bb0a5..31f1da8 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -195,9 +195,7 @@
     public int overviewTaskIconDrawableSizeGridPx;
     public int overviewTaskThumbnailTopMarginPx;
     public final int overviewActionsHeight;
-    public final int overviewActionsMarginThreeButtonPx;
-    public final int overviewActionsTopMarginGesturePx;
-    public final int overviewActionsBottomMarginGesturePx;
+    public final int overviewActionsTopMarginPx;
     public final int overviewActionsButtonSpacing;
     public int overviewPageSpacing;
     public int overviewRowSpacing;
@@ -408,16 +406,14 @@
         overviewTaskIconDrawableSizeGridPx =
                 res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size_grid);
         overviewTaskThumbnailTopMarginPx = overviewTaskIconSizePx + overviewTaskMarginPx * 2;
-        overviewActionsTopMarginGesturePx = res.getDimensionPixelSize(
-                R.dimen.overview_actions_top_margin_gesture);
-        overviewActionsBottomMarginGesturePx = res.getDimensionPixelSize(
-                R.dimen.overview_actions_bottom_margin_gesture);
+        // In vertical bar, use the smaller task margin for the top regardless of mode.
+        overviewActionsTopMarginPx = isVerticalBarLayout()
+                ? overviewTaskMarginPx
+                : res.getDimensionPixelSize(R.dimen.overview_actions_top_margin);
         overviewPageSpacing = res.getDimensionPixelSize(R.dimen.overview_page_spacing);
         overviewActionsButtonSpacing = res.getDimensionPixelSize(
                 R.dimen.overview_actions_button_spacing);
         overviewActionsHeight = res.getDimensionPixelSize(R.dimen.overview_actions_height);
-        overviewActionsMarginThreeButtonPx = res.getDimensionPixelSize(
-                R.dimen.overview_actions_margin_three_button);
         // Grid task's top margin is only overviewTaskIconSizePx + overviewTaskMarginGridPx, but
         // overviewTaskThumbnailTopMarginPx is applied to all TaskThumbnailView, so exclude the
         // extra  margin when calculating row spacing.
@@ -658,7 +654,7 @@
         Point workspacePadding = getTotalWorkspacePadding();
 
         // Check to see if the icons fit within the available height.
-        float usedHeight = getCellLayoutHeight();
+        float usedHeight = getCellLayoutHeightSpecification();
         final int maxHeight = getWorkspaceHeight(workspacePadding);
         float extraHeight = Math.max(0, maxHeight - usedHeight);
         float scaleY = maxHeight / usedHeight;
@@ -669,7 +665,8 @@
             // We scale to fit the cellWidth and cellHeight in the available space.
             // The benefit of scalable grids is that we can get consistent aspect ratios between
             // devices.
-            float usedWidth = getCellLayoutWidth() + (desiredWorkspaceHorizontalMarginPx * 2);
+            float usedWidth =
+                    getCellLayoutWidthSpecification() + (desiredWorkspaceHorizontalMarginPx * 2);
             // We do not subtract padding here, as we also scale the workspace padding if needed.
             scaleX = availableWidthPx / usedWidth;
             shouldScale = true;
@@ -678,19 +675,19 @@
         if (shouldScale) {
             float scale = Math.min(scaleX, scaleY);
             updateIconSize(scale, res);
-            extraHeight = Math.max(0, maxHeight - getCellLayoutHeight());
+            extraHeight = Math.max(0, maxHeight - getCellLayoutHeightSpecification());
         }
 
         updateAvailableFolderCellDimensions(res);
         return Math.round(extraHeight);
     }
 
-    private int getCellLayoutHeight() {
+    private int getCellLayoutHeightSpecification() {
         return (cellHeightPx * inv.numRows) + (cellLayoutBorderSpacePx.y * (inv.numRows - 1))
                 + cellLayoutPaddingPx.top + cellLayoutPaddingPx.bottom;
     }
 
-    private int getCellLayoutWidth() {
+    private int getCellLayoutWidthSpecification() {
         int numColumns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns;
         return (cellWidthPx * numColumns) + (cellLayoutBorderSpacePx.x * (numColumns - 1))
                 + cellLayoutPaddingPx.left + cellLayoutPaddingPx.right;
@@ -920,7 +917,7 @@
     /**
      * Gets the scaled bottom of the workspace in px for the spring-loaded edit state.
      */
-    public float getWorkspaceSpringLoadShrunkBottom() {
+    private float getWorkspaceSpringLoadShrunkBottom() {
         int topOfHotseat = hotseatBarSizePx + springLoadedHotseatBarTopMarginPx;
         workspaceSpringLoadShrunkBottom =
                 heightPx - (isVerticalBarLayout() ? getVerticalHotseatLastItemBottomOffset()
@@ -931,10 +928,30 @@
     /**
      * Gets the minimum visible amount of the next workspace page when in the spring-loaded state.
      */
-    public float getWorkspaceSpringLoadedMinimumNextPageVisible() {
+    private float getWorkspaceSpringLoadedMinimumNextPageVisible() {
         return getCellSize().x / 2f;
     }
 
+    /**
+     * Gets the scale of the workspace for the spring-loaded edit state.
+     */
+    public float getWorkspaceSpringLoadScale() {
+        float cellLayoutHeight = availableHeightPx - workspacePadding.top - workspacePadding.bottom;
+        float scale = (getWorkspaceSpringLoadShrunkBottom() - getWorkspaceSpringLoadShrunkTop())
+                / cellLayoutHeight;
+        scale = Math.min(scale, 1f);
+
+        // Reduce scale if next pages would not be visible after scaling the workspace
+        int workspaceWidth = getWorkspaceWidth();
+        float scaledWorkspaceWidth = workspaceWidth * scale;
+        float maxAvailableWidth =
+                workspaceWidth - (2 * getWorkspaceSpringLoadedMinimumNextPageVisible());
+        if (scaledWorkspaceWidth > maxAvailableWidth) {
+            scale *= maxAvailableWidth / scaledWorkspaceWidth;
+        }
+        return scale;
+    }
+
     public int getWorkspaceWidth() {
         return getWorkspaceWidth(getTotalWorkspacePadding());
     }
@@ -1104,6 +1121,24 @@
     }
 
     /**
+     * Returns the number of pixels required below OverviewActions excluding insets.
+     */
+    public int getOverviewActionsClaimedSpaceBelow() {
+        if (isTaskbarPresent && !isGestureMode) {
+            // Align vertically to where nav buttons are.
+            return  ((taskbarSize - overviewActionsHeight) / 2) + getTaskbarOffsetY();
+        }
+
+        return 0;
+    }
+
+    /** Gets the space that the overview actions will take, including bottom margin. */
+    public int getOverviewActionsClaimedSpace() {
+        return overviewActionsTopMarginPx + overviewActionsHeight
+                + getOverviewActionsClaimedSpaceBelow();
+    }
+
+    /**
      * @return the bounds for which the open folders should be contained within
      */
     public Rect getAbsoluteOpenFolderBounds() {
@@ -1323,12 +1358,10 @@
                 overviewTaskIconDrawableSizeGridPx));
         writer.println(prefix + pxToDpStr("overviewTaskThumbnailTopMarginPx",
                 overviewTaskThumbnailTopMarginPx));
-        writer.println(prefix + pxToDpStr("overviewActionsMarginThreeButtonPx",
-                overviewActionsMarginThreeButtonPx));
-        writer.println(prefix + pxToDpStr("overviewActionsTopMarginGesturePx",
-                overviewActionsTopMarginGesturePx));
-        writer.println(prefix + pxToDpStr("overviewActionsBottomMarginGesturePx",
-                overviewActionsBottomMarginGesturePx));
+        writer.println(prefix + pxToDpStr("overviewActionsTopMarginPx",
+                overviewActionsTopMarginPx));
+        writer.println(prefix + pxToDpStr("overviewActionsHeight",
+                overviewActionsHeight));
         writer.println(prefix + pxToDpStr("overviewActionsButtonSpacing",
                 overviewActionsButtonSpacing));
         writer.println(prefix + pxToDpStr("overviewPageSpacing", overviewPageSpacing));
@@ -1344,6 +1377,8 @@
                 prefix + pxToDpStr("workspaceSpringLoadShrunkTop", workspaceSpringLoadShrunkTop));
         writer.println(prefix + pxToDpStr("workspaceSpringLoadShrunkBottom",
                 workspaceSpringLoadShrunkBottom));
+        writer.println(
+                prefix + pxToDpStr("getWorkspaceSpringLoadScale()", getWorkspaceSpringLoadScale()));
     }
 
     private static Context getContext(Context c, Info info, int orientation, WindowBounds bounds) {
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index ec3629d..2e3f26c 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -237,10 +237,8 @@
                         rightButton.getMeasuredHeight());
             } else if (dp.isPhone) {
                 // Buttons aligned to outer edges of scaled workspace.
-                float shrunkTop = dp.getWorkspaceSpringLoadShrunkTop();
-                float shrunkBottom = dp.getWorkspaceSpringLoadShrunkBottom();
-                float scale =
-                        (shrunkBottom - shrunkTop) / launcher.getWorkspace().getNormalChildHeight();
+                float scale = dp.getWorkspaceSpringLoadScale();
+
                 int workspaceWidth = (int) (launcher.getWorkspace().getNormalChildWidth() * scale);
                 int start = barCenter - (workspaceWidth / 2);
                 int end = barCenter + (workspaceWidth / 2);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 36c1797..1f92079 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -61,6 +61,8 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -625,8 +627,21 @@
 
         float screenWidth = config.screenWidthDp * res.getDisplayMetrics().density;
         float screenHeight = config.screenHeightDp * res.getDisplayMetrics().density;
-        return getBestMatch(screenWidth, screenHeight,
-                WindowManagerProxy.INSTANCE.get(context).getRotation(context));
+        int rotation = WindowManagerProxy.INSTANCE.get(context).getRotation(context);
+
+        if (Utilities.IS_DEBUG_DEVICE) {
+            StringWriter stringWriter = new StringWriter();
+            PrintWriter printWriter = new PrintWriter(stringWriter);
+            DisplayController.INSTANCE.get(context).dump(printWriter);
+            printWriter.flush();
+            Log.d("b/231312158", "getDeviceProfile -"
+                            + "\nconfig: " + config
+                            + "\ndisplayMetrics: " + res.getDisplayMetrics()
+                            + "\nrotation: " + rotation
+                            + "\n" + stringWriter.toString(),
+                    new Exception());
+        }
+        return getBestMatch(screenWidth, screenHeight, rotation);
     }
 
     /**
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 463280b..ad87451 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -182,7 +182,6 @@
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.OnboardingPrefs;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
@@ -1280,13 +1279,16 @@
      * @param info The data structure describing the shortcut.
      */
     View createShortcut(WorkspaceItemInfo info) {
-        return createShortcut((ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), info);
+        // This can be called before PagedView#pageScrollsInitialized returns true, so use the
+        // first page, which we always assume to be present.
+        return createShortcut((ViewGroup) mWorkspace.getChildAt(0), info);
     }
 
     /**
      * Creates a view representing a shortcut inflated from the specified resource.
      *
-     * @param parent The group the shortcut belongs to.
+     * @param parent The group the shortcut belongs to. This is not necessarily the group where
+     *               the shortcut should be added.
      * @param info   The data structure describing the shortcut.
      * @return A View inflated from layoutResId.
      */
@@ -2739,9 +2741,9 @@
      */
     public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user,
             boolean supportsAllAppsState) {
-        final ItemInfoMatcher preferredItem = (info, cn) ->
+        final Predicate<ItemInfo> preferredItem = info ->
                 info != null && info.id == preferredItemId;
-        final ItemInfoMatcher packageAndUserAndApp = (info, cn) ->
+        final Predicate<ItemInfo> packageAndUserAndApp = info ->
                 info != null
                         && info.itemType == ITEM_TYPE_APPLICATION
                         && info.user.equals(user)
@@ -2750,7 +2752,7 @@
                         packageName);
 
         if (supportsAllAppsState && isInState(LauncherState.ALL_APPS)) {
-            return getFirstMatch(Collections.singletonList(mAppsView.getActiveAppsRecyclerView()),
+            return getFirstMatch(Collections.singletonList(mAppsView.getActiveRecyclerView()),
                     preferredItem, packageAndUserAndApp);
         } else {
             List<ViewGroup> containers = new ArrayList<>(mWorkspace.getPanelCount() + 1);
@@ -2770,8 +2772,8 @@
      * @param operators List of operators, in order starting from best matching operator.
      */
     private static View getFirstMatch(Iterable<ViewGroup> containers,
-            final ItemInfoMatcher... operators) {
-        for (ItemInfoMatcher operator : operators) {
+            final Predicate<ItemInfo>... operators) {
+        for (Predicate<ItemInfo> operator : operators) {
             for (ViewGroup container : containers) {
                 View match = mapOverViewGroup(container, operator);
                 if (match != null) {
@@ -2786,11 +2788,11 @@
      * Returns the first view matching the operator in the given ViewGroups, or null if none.
      * Forward iteration matters.
      */
-    private static View mapOverViewGroup(ViewGroup container, ItemInfoMatcher op) {
+    private static View mapOverViewGroup(ViewGroup container, Predicate<ItemInfo> op) {
         final int itemCount = container.getChildCount();
         for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
             View item = container.getChildAt(itemIdx);
-            if (op.matchesInfo((ItemInfo) item.getTag())) {
+            if (op.test((ItemInfo) item.getTag())) {
                 return item;
             }
         }
@@ -2887,7 +2889,7 @@
      * package-removal should clear all items by package name.
      */
     @Override
-    public void bindWorkspaceComponentsRemoved(final ItemInfoMatcher matcher) {
+    public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
         mWorkspace.removeItemsByMatcher(matcher);
         mDragController.onAppsRemoved(matcher);
         PopupContainerWithArrow.dismissInvalidPopup(this);
@@ -3168,6 +3170,24 @@
         return new DragOptions();
     }
 
+    /**
+     * Animates Launcher elements during a transition to the All Apps page.
+     *
+     * @param progress Transition progress from 0 to 1; where 0 => home and 1 => all apps.
+     */
+    public void onAllAppsTransition(float progress) {
+        // No-Op
+    }
+
+    /**
+     * Animates Launcher elements during a transition to the Widgets pages.
+     *
+     * @param progress Transition progress from 0 to 1; where 0 => home and 1 => widgets.
+     */
+    public void onWidgetsTransition(float progress) {
+        // No-Op
+    }
+
     private static class NonConfigInstance {
         public Configuration config;
         public Bitmap snapshot;
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 4501159..597bc8d 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3;
 
+import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+
 import static com.android.launcher3.Utilities.getDevicePrefs;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_THEMED_ICONS;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -97,7 +99,8 @@
         modelChangeReceiver.register(mContext, Intent.ACTION_LOCALE_CHANGED,
                 Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
                 Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
-                Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
+                Intent.ACTION_MANAGED_PROFILE_UNLOCKED,
+                ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
         if (FeatureFlags.IS_STUDIO_BUILD) {
             modelChangeReceiver.register(mContext, Context.RECEIVER_EXPORTED, ACTION_FORCE_ROLOAD);
         }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index ee6f51e..5c5c101 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3;
 
+import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+
 import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
 import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -51,6 +53,7 @@
 import com.android.launcher3.model.PackageIncrementalDownloadUpdatedTask;
 import com.android.launcher3.model.PackageInstallStateChangedTask;
 import com.android.launcher3.model.PackageUpdatedTask;
+import com.android.launcher3.model.ReloadStringCacheTask;
 import com.android.launcher3.model.ShortcutsChangedTask;
 import com.android.launcher3.model.UserLockStateChangedTask;
 import com.android.launcher3.model.data.AppInfo;
@@ -278,6 +281,8 @@
                             user, Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)));
                 }
             }
+        } else if (ACTION_DEVICE_POLICY_RESOURCE_UPDATED.equals(action)) {
+            enqueueModelUpdateTask(new ReloadStringCacheTask(mModelDelegate));
         } else if (IS_STUDIO_BUILD && ACTION_FORCE_ROLOAD.equals(action)) {
             for (Callbacks cb : getCallbacks()) {
                 if (cb instanceof Launcher) {
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index baee49f..ea6a919 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -80,6 +80,9 @@
     public static final int FLAG_CLOSE_POPUPS = BaseState.getFlag(6);
     public static final int FLAG_OVERVIEW_UI = BaseState.getFlag(7);
 
+    // Flag indicating that hotseat and its contents are not accessible.
+    public static final int FLAG_HOTSEAT_INACCESSIBLE = BaseState.getFlag(8);
+
 
     public static final float NO_OFFSET = 0;
     public static final float NO_SCALE = 1;
@@ -110,7 +113,7 @@
             FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED | FLAG_HIDE_BACK_BUTTON |
                     FLAG_HAS_SYS_UI_SCRIM) {
         @Override
-        public int getTransitionDuration(Context context) {
+        public int getTransitionDuration(Context context, boolean isToState) {
             // Arbitrary duration, when going to NORMAL we use the state we're coming from instead.
             return 0;
         }
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 0a1d25c..95a8a2a 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -129,7 +129,10 @@
     private boolean mAllowEasyFling;
     protected PagedOrientationHandler mOrientationHandler = PagedOrientationHandler.PORTRAIT;
 
-    protected int[] mPageScrolls;
+    private final ArrayList<Runnable> mOnPageScrollsInitializedCallbacks = new ArrayList<>();
+
+    // We should always check pageScrollsInitialized() is true when using mPageScrolls.
+    @Nullable protected int[] mPageScrolls = null;
     private boolean mIsBeingDragged;
 
     // The amount of movement to begin scrolling
@@ -684,14 +687,37 @@
         setMeasuredDimension(widthSize, heightSize);
     }
 
+    /** Returns true iff this PagedView's scroll amounts are initialized to each page index. */
+    protected boolean pageScrollsInitialized() {
+        return mPageScrolls != null && mPageScrolls.length == getChildCount();
+    }
+
+    /**
+     * Queues the given callback to be run once {@code mPageScrolls} has been initialized.
+     */
+    public void runOnPageScrollsInitialized(Runnable callback) {
+        mOnPageScrollsInitializedCallbacks.add(callback);
+        if (pageScrollsInitialized()) {
+            onPageScrollsInitialized();
+        }
+    }
+
+    private void onPageScrollsInitialized() {
+        for (Runnable callback : mOnPageScrollsInitializedCallbacks) {
+            callback.run();
+        }
+        mOnPageScrollsInitializedCallbacks.clear();
+    }
+
     @SuppressLint("DrawAllocation")
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         mIsLayoutValid = true;
         final int childCount = getChildCount();
+        int[] pageScrolls = mPageScrolls;
         boolean pageScrollChanged = false;
-        if (mPageScrolls == null || childCount != mPageScrolls.length) {
-            mPageScrolls = new int[childCount];
+        if (!pageScrollsInitialized()) {
+            pageScrolls = new int[childCount];
             pageScrollChanged = true;
         }
 
@@ -701,10 +727,8 @@
 
         if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
 
-        boolean isScrollChanged = getPageScrolls(mPageScrolls, true, SIMPLE_SCROLL_LOGIC);
-        if (isScrollChanged) {
-            pageScrollChanged = true;
-        }
+        pageScrollChanged |= getPageScrolls(pageScrolls, true, SIMPLE_SCROLL_LOGIC);
+        mPageScrolls = pageScrolls;
 
         final LayoutTransition transition = getLayoutTransition();
         // If the transition is running defer updating max scroll, as some empty pages could
@@ -738,6 +762,7 @@
         if (mScroller.isFinished() && pageScrollChanged) {
             setCurrentPage(getNextPage());
         }
+        onPageScrollsInitialized();
     }
 
     /**
@@ -849,8 +874,10 @@
     @Override
     public void onViewRemoved(View child) {
         super.onViewRemoved(child);
-        mCurrentPage = validateNewPage(mCurrentPage);
-        mCurrentScrollOverPage = mCurrentPage;
+        runOnPageScrollsInitialized(() -> {
+            mCurrentPage = validateNewPage(mCurrentPage);
+            mCurrentScrollOverPage = mCurrentPage;
+        });
         dispatchPageCountChanged();
     }
 
@@ -1153,7 +1180,7 @@
     }
 
     public int getScrollForPage(int index) {
-        if (mPageScrolls == null || index >= mPageScrolls.length || index < 0) {
+        if (!pageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
             return 0;
         } else {
             return mPageScrolls[index];
@@ -1163,7 +1190,7 @@
     // While layout transitions are occurring, a child's position may stray from its baseline
     // position. This method returns the magnitude of this stray at any given time.
     public int getLayoutTransitionOffsetForPage(int index) {
-        if (mPageScrolls == null || index >= mPageScrolls.length || index < 0) {
+        if (!pageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
             return 0;
         } else {
             View child = getChildAt(index);
diff --git a/src/com/android/launcher3/ResourceUtils.java b/src/com/android/launcher3/ResourceUtils.java
index 1c36db1..f709aca 100644
--- a/src/com/android/launcher3/ResourceUtils.java
+++ b/src/com/android/launcher3/ResourceUtils.java
@@ -31,6 +31,10 @@
     public static final String NAVBAR_HEIGHT = "navigation_bar_height";
     public static final String NAVBAR_HEIGHT_LANDSCAPE = "navigation_bar_height_landscape";
 
+    public static final String STATUS_BAR_HEIGHT = "status_bar_height";
+    public static final String STATUS_BAR_HEIGHT_LANDSCAPE = "status_bar_height_landscape";
+    public static final String STATUS_BAR_HEIGHT_PORTRAIT = "status_bar_height_portrait";
+
     public static int getNavbarSize(String resName, Resources res) {
         return getDimenByName(resName, res, DEFAULT_NAVBAR_VALUE);
     }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 8358f2a..7b96838 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -273,6 +273,16 @@
     }
 
     /**
+     * Similar to {@link #mapCoordInSelfToDescendant(View descendant, View root, float[] coord)}
+     * but accepts a Rect instead of float[].
+     */
+    public static void mapRectInSelfToDescendant(View descendant, View root, Rect rect) {
+        float[] coords = new float[]{rect.left, rect.top, rect.right, rect.bottom};
+        mapCoordInSelfToDescendant(descendant, root, coords);
+        rect.set((int) coords[0], (int) coords[1], (int) coords[2], (int) coords[3]);
+    }
+
+    /**
      * Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, float[], boolean)}.
      */
     public static void mapCoordInSelfToDescendant(View descendant, View root, float[] coord) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index ed01660..fb028b9 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -102,7 +102,6 @@
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.IntSparseArrayMap;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.util.OverlayEdgeEffect;
 import com.android.launcher3.util.PackageUserKey;
@@ -200,6 +199,7 @@
 
     private final int[] mTempXY = new int[2];
     private final float[] mTempFXY = new float[2];
+    private final Rect mTempRect = new Rect();
     @Thunk float[] mDragViewVisualCenter = new float[2];
 
     private SpringLoadedDragController mSpringLoadedDragController;
@@ -906,7 +906,11 @@
      * two panel UI is enabled.
      */
     public int getScreenPair(int screenId) {
-        if (screenId % 2 == 0) {
+        if (screenId == EXTRA_EMPTY_SCREEN_ID) {
+            return EXTRA_EMPTY_SCREEN_SECOND_ID;
+        } else if (screenId == EXTRA_EMPTY_SCREEN_SECOND_ID) {
+            return EXTRA_EMPTY_SCREEN_ID;
+        } else if (screenId % 2 == 0) {
             return screenId + 1;
         } else {
             return screenId - 1;
@@ -1730,7 +1734,7 @@
         // If it's an external drop (e.g. from All Apps), check if it should be accepted
         CellLayout dropTargetLayout = mDropToLayout;
         if (d.dragSource != this) {
-            // Don't accept the drop if we're not over a screen at time of drop
+            // Don't accept the drop if we're not over a valid drop target at time of drop
             if (dropTargetLayout == null) {
                 return false;
             }
@@ -2113,7 +2117,7 @@
                     final Runnable onCompleteCallback = onCompleteRunnable;
                     mLauncher.getDragController().animateDragViewToOriginalPosition(
                             /* onComplete= */ callbackList::executeAllAndDestroy, cell,
-                            SPRING_LOADED.getTransitionDuration(mLauncher));
+                            SPRING_LOADED.getTransitionDuration(mLauncher, true /* isToState */));
                     mLauncher.getStateManager().goToState(NORMAL, /* delay= */ 0,
                             onCompleteCallback == null
                                     ? null
@@ -2331,17 +2335,6 @@
         xy[1] = xy[1] - v.getTop();
     }
 
-    boolean isPointInSelfOverHotseat(int x, int y) {
-        mTempFXY[0] = x;
-        mTempFXY[1] = y;
-        mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempFXY, true);
-        View hotseat = mLauncher.getHotseat();
-        return mTempFXY[0] >= hotseat.getLeft()
-                && mTempFXY[0] <= hotseat.getRight()
-                && mTempFXY[1] >= hotseat.getTop()
-                && mTempFXY[1] <= hotseat.getBottom();
-    }
-
     /**
      * Updates the point in {@param xy} to point to the co-ordinate space of {@param layout}
      * @param layout either hotseat of a page in workspace
@@ -2379,7 +2372,7 @@
 
         final View child = (mDragInfo == null) ? null : mDragInfo.cell;
         if (setDropLayoutForDragObject(d, mDragViewVisualCenter[0], mDragViewVisualCenter[1])) {
-            if (mLauncher.isHotseatLayout(mDragTargetLayout)) {
+            if (mDragTargetLayout == null || mLauncher.isHotseatLayout(mDragTargetLayout)) {
                 mSpringLoadedDragController.cancel();
             } else {
                 mSpringLoadedDragController.setAlarm(mDragTargetLayout);
@@ -2458,52 +2451,25 @@
      */
     private boolean setDropLayoutForDragObject(DragObject d, float centerX, float centerY) {
         CellLayout layout = null;
-        // Test to see if we are over the hotseat first
-        if (mLauncher.getHotseat() != null && !isDragWidget(d)) {
-            if (isPointInSelfOverHotseat(d.x, d.y)) {
-                layout = mLauncher.getHotseat();
+        if (shouldUseHotseatAsDropLayout(d)) {
+            layout = mLauncher.getHotseat();
+        } else if (!isDragObjectOverSmartSpace(d)) {
+            // If the object is over qsb/smartspace, we don't want to highlight anything.
+
+            // Check neighbour pages
+            layout = checkDragObjectIsOverNeighbourPages(d, centerX);
+
+            if (layout == null) {
+                // Check visible pages
+                IntSet visiblePageIndices = getVisiblePageIndices();
+                for (int visiblePageIndex : visiblePageIndices) {
+                    layout = verifyInsidePage(visiblePageIndex, d.x, d.y);
+                    if (layout != null) break;
+                }
             }
         }
 
-        // Note, centerX represents the center of the object that is being dragged, visually. d.x
-        // represents the location of the finger within the dragged item.
-        float touchX;
-        float touchY = d.y;
-
-        // Go through the pages and check if the dragged item is inside one of them. This block
-        // is responsible for  determining whether we need to snap to a different screen.
-        int nextPage = getNextPage();
-        IntSet pageIndexesToVerify = IntSet.wrap(nextPage - 1, nextPage
-                + (isTwoPanelEnabled() ? 2 : 1));
-        for (int pageIndex : pageIndexesToVerify) {
-            if (layout != null || isPageInTransition()) {
-                break;
-            }
-
-            // When deciding whether to perform a page switch, we need to consider the most extreme
-            // X coordinate between the finger location and the center of the object being dragged.
-            // This is either the max or the min of the two depending on whether dragging to the
-            // left / right, respectively.
-            touchX = ((((pageIndex < nextPage) && !mIsRtl) || pageIndex > nextPage && mIsRtl)
-                    ? Math.min(d.x, centerX) : Math.max(d.x, centerX));
-            layout = verifyInsidePage(pageIndex, touchX, touchY);
-        }
-
-        // If the dragged item isn't located in one of the pages above, the icon will stay on the
-        // current screen. For two panel pick the closest panel on the current screen,
-        // on one panel just choose the current page.
-        if (layout == null && nextPage >= 0 && nextPage < getPageCount()) {
-            if (isTwoPanelEnabled()) {
-                // When determining which panel to use within a single screen, we always use
-                // the centroid of the object rather than the finger.
-                touchX = centerX;
-                nextPage = getScreenCenter(getScrollX()) > touchX
-                        ? (mIsRtl ? nextPage + 1 : nextPage) // left side
-                        : (mIsRtl ? nextPage : nextPage + 1); // right side
-            }
-            layout = (CellLayout) getChildAt(nextPage);
-        }
-
+        // Update the current drop layout if the target changed
         if (layout != mDragTargetLayout) {
             setCurrentDropLayout(layout);
             setCurrentDragOverlappingLayout(layout);
@@ -2512,6 +2478,69 @@
         return false;
     }
 
+    private boolean shouldUseHotseatAsDropLayout(DragObject dragObject) {
+        if (mLauncher.getHotseat() == null
+                || mLauncher.getHotseat().getShortcutsAndWidgets() == null
+                || isDragWidget(dragObject)) {
+            return false;
+        }
+        View hotseatShortcuts = mLauncher.getHotseat().getShortcutsAndWidgets();
+        getViewBoundsRelativeToWorkspace(hotseatShortcuts, mTempRect);
+        return mTempRect.contains(dragObject.x, dragObject.y);
+    }
+
+    private boolean isDragObjectOverSmartSpace(DragObject dragObject) {
+        if (mQsb == null) {
+            return false;
+        }
+        getViewBoundsRelativeToWorkspace(mQsb, mTempRect);
+        return mTempRect.contains(dragObject.x, dragObject.y);
+    }
+
+    private CellLayout checkDragObjectIsOverNeighbourPages(DragObject d, float centerX) {
+        if (isPageInTransition()) {
+            return null;
+        }
+
+        // Check the workspace pages whether the object is over any of them
+
+        // Note, centerX represents the center of the object that is being dragged, visually.
+        // d.x represents the location of the finger within the dragged item.
+        float touchX;
+        float touchY = d.y;
+
+        // Go through the pages and check if the dragged item is inside one of them. This block
+        // is responsible for determining whether we need to snap to a different screen.
+        int nextPage = getNextPage();
+        IntSet pageIndexesToVerify = IntSet.wrap(nextPage - 1,
+                nextPage + (isTwoPanelEnabled() ? 2 : 1));
+
+        for (int pageIndex : pageIndexesToVerify) {
+            // When deciding whether to perform a page switch, we need to consider the most
+            // extreme X coordinate between the finger location and the center of the object
+            // being dragged. This is either the max or the min of the two depending on whether
+            // dragging to the left / right, respectively.
+            touchX = (((pageIndex < nextPage) && !mIsRtl) || (pageIndex > nextPage && mIsRtl))
+                    ? Math.min(d.x, centerX) : Math.max(d.x, centerX);
+            CellLayout layout = verifyInsidePage(pageIndex, touchX, touchY);
+            if (layout != null) {
+                return layout;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the given view's bounds relative to Workspace
+     */
+    private void getViewBoundsRelativeToWorkspace(View view, Rect outRect) {
+        mLauncher.getDragLayer()
+                .getDescendantRectRelativeToSelf(view, mTempRect);
+        // map draglayer relative bounds to workspace
+        mLauncher.getDragLayer().mapRectInSelfToDescendant(this, mTempRect);
+        outRect.set(mTempRect);
+    }
+
     /**
      * Returns the child CellLayout if the point is inside the page coordinates, null otherwise.
      */
@@ -3205,7 +3234,7 @@
      * as a part of an update, this is called to ensure that other widgets and application
      * shortcuts are not removed.
      */
-    public void removeItemsByMatcher(final ItemInfoMatcher matcher) {
+    public void removeItemsByMatcher(final Predicate<ItemInfo> matcher) {
         for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
             ShortcutAndWidgetContainer container = layout.getShortcutsAndWidgets();
             // Iterate in reverse order as we are removing items
@@ -3213,7 +3242,7 @@
                 View child = container.getChildAt(i);
                 ItemInfo info = (ItemInfo) child.getTag();
 
-                if (matcher.matchesInfo(info)) {
+                if (matcher.test(info)) {
                     layout.removeViewInLayout(child);
                     if (child instanceof DropTarget) {
                         mDragController.removeDropTarget((DropTarget) child);
@@ -3221,7 +3250,7 @@
                 } else if (child instanceof FolderIcon) {
                     FolderInfo folderInfo = (FolderInfo) info;
                     List<WorkspaceItemInfo> matches = folderInfo.contents.stream()
-                            .filter(matcher::matchesInfo)
+                            .filter(matcher)
                             .collect(Collectors.toList());
                     if (!matches.isEmpty()) {
                         folderInfo.removeAll(matches, false);
@@ -3300,7 +3329,7 @@
      *
      * @param matcher  the matcher generated by the caller.
      */
-    public void persistRemoveItemsByMatcher(ItemInfoMatcher matcher) {
+    public void persistRemoveItemsByMatcher(Predicate<ItemInfo> matcher) {
         mLauncher.getModelWriter().deleteItemsFromDatabase(matcher);
         removeItemsByMatcher(matcher);
     }
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 84b95ec..a991c2f 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -25,6 +25,7 @@
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY;
 import static com.android.launcher3.LauncherState.FLAG_HAS_SYS_UI_SCRIM;
+import static com.android.launcher3.LauncherState.FLAG_HOTSEAT_INACCESSIBLE;
 import static com.android.launcher3.LauncherState.HINT_STATE;
 import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
 import static com.android.launcher3.LauncherState.NORMAL;
@@ -35,6 +36,7 @@
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
 import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
@@ -116,8 +118,6 @@
         }
 
         int elements = state.getVisibleElements(mLauncher);
-        Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
-                pageAlphaProvider.interpolator);
         Hotseat hotseat = mWorkspace.getHotseat();
         Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
         LauncherState fromState = mLauncher.getStateManager().getState();
@@ -145,11 +145,21 @@
                     hotseatScaleInterpolator);
         }
 
-        float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
-        propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
+        Interpolator workspaceFadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
+                pageAlphaProvider.interpolator);
         float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
         propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
-                workspacePageIndicatorAlpha, fadeInterpolator);
+                workspacePageIndicatorAlpha, workspaceFadeInterpolator);
+        Interpolator hotseatFadeInterpolator = config.getInterpolator(ANIM_HOTSEAT_FADE,
+                workspaceFadeInterpolator);
+        float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
+        propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, hotseatFadeInterpolator);
+
+        // Update the accessibility flags for hotseat based on launcher state.
+        hotseat.setImportantForAccessibility(
+                state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE)
+                        ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+                        : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
 
         Interpolator translationInterpolator =
                 config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 16a2823..47f2dd5 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -29,11 +29,13 @@
 import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.views.AppLauncher;
 
+import java.util.ArrayList;
 import java.util.Objects;
 
 /**
@@ -80,7 +82,7 @@
         OnClickListener marketSearchClickListener = (v) -> mActivityContext.startActivitySafely(v,
                 marketSearchIntent, null);
         for (int i = 0; i < mAH.size(); i++) {
-            mAH.get(i).mAdapter.setLastSearchQuery(query, marketSearchClickListener);
+            mAH.get(i).adapter.setLastSearchQuery(query, marketSearchClickListener);
         }
         mIsSearching = true;
         rebindAdapters();
@@ -95,11 +97,15 @@
         mHeader.reset(false);
     }
 
-    /** Invoke when the search results change. */
-    public void onSearchResultsChanged() {
-        for (int i = 0; i < mAH.size(); i++) {
-            if (mAH.get(i).mRecyclerView != null) {
-                mAH.get(i).mRecyclerView.onSearchResultsChanged();
+    /**
+     * Sets results list for search
+     */
+    public void setSearchResults(ArrayList<AdapterItem> results) {
+        if (getApps().setSearchResults(results)) {
+            for (int i = 0; i < mAH.size(); i++) {
+                if (mAH.get(i).mRecyclerView != null) {
+                    mAH.get(i).mRecyclerView.onSearchResultsChanged();
+                }
             }
         }
     }
@@ -142,7 +148,7 @@
 
     @Override
     public String getDescription() {
-        if (!mUsingTabs && isSearching()) {
+        if (!mUsingTabs && mIsSearching) {
             return getContext().getString(R.string.all_apps_search_results);
         } else {
             return super.getDescription();
@@ -150,13 +156,8 @@
     }
 
     @Override
-    protected boolean shouldShowTabs() {
-        return super.shouldShowTabs() && !isSearching();
-    }
-
-    @Override
-    public boolean isSearching() {
-        return mIsSearching;
+    protected boolean showTabs() {
+        return super.showTabs() && !mIsSearching;
     }
 
     @Override
@@ -178,19 +179,15 @@
     }
 
     @Override
-    protected View replaceAppsRVContainer(boolean showTabs) {
-        View rvContainer = super.replaceAppsRVContainer(showTabs);
+    protected View replaceRVContainer(boolean showTabs) {
+        View rvContainer = super.replaceRVContainer(showTabs);
 
         removeCustomRules(rvContainer);
-        removeCustomRules(getSearchRecyclerView());
         if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
             alignParentTop(rvContainer, showTabs);
-            alignParentTop(getSearchRecyclerView(), showTabs);
             layoutAboveSearchContainer(rvContainer);
-            layoutAboveSearchContainer(getSearchRecyclerView());
         } else {
             layoutBelowSearchContainer(rvContainer, showTabs);
-            layoutBelowSearchContainer(getSearchRecyclerView(), showTabs);
         }
 
         return rvContainer;
@@ -217,7 +214,7 @@
 
         float prog = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
         boolean bgVisible = mSearchUiManager.getBackgroundVisibility();
-        if (scrolledOffset == 0 && !isSearching()) {
+        if (scrolledOffset == 0 && !mIsSearching) {
             bgVisible = true;
         } else if (scrolledOffset > mHeaderThreshold) {
             bgVisible = false;
@@ -251,7 +248,7 @@
         int topMargin = getContext().getResources().getDimensionPixelSize(
                 R.dimen.all_apps_header_top_margin);
         if (includeTabsMargin) {
-            topMargin += getContext().getResources().getDimensionPixelSize(
+            topMargin = topMargin + getContext().getResources().getDimensionPixelSize(
                     R.dimen.all_apps_header_pill_height);
         }
         layoutParams.topMargin = topMargin;
@@ -292,9 +289,9 @@
     }
 
     @Override
-    protected BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> appsList,
+    protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
             BaseAdapterProvider[] adapterProviders) {
-        return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
+        return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
                 adapterProviders);
     }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
index f97eb28..7067fa2 100644
--- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
+++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
@@ -37,10 +37,10 @@
      * Smooth scrolls the recycler view to the given section.
      */
     public void smoothScrollToSection(FastScrollSectionInfo info) {
-        if (mTargetFastScrollPosition == info.fastScrollToItem.position) {
+        if (mTargetFastScrollPosition == info.position) {
             return;
         }
-        mTargetFastScrollPosition = info.fastScrollToItem.position;
+        mTargetFastScrollPosition = info.position;
         mRv.getLayoutManager().startSmoothScroll(new MyScroller(mTargetFastScrollPosition));
     }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 58df50c..33d2f2b 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -118,7 +118,7 @@
             List<AdapterItem> items = mApps.getAdapterItems();
             adapterPosition = Math.max(adapterPosition, items.size() - 1);
             int extraRows = 0;
-            for (int i = 0; i <= adapterPosition; i++) {
+            for (int i = 0; i <= adapterPosition && i < items.size(); i++) {
                 if (!isViewType(items.get(i).viewType, VIEW_TYPE_MASK_ICON)) {
                     extraRows++;
                 }
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 18c6788..bdfeada 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -37,8 +37,8 @@
 
 import androidx.recyclerview.widget.RecyclerView;
 
+import com.android.launcher3.BaseRecyclerView;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.FastScrollRecyclerView;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -53,13 +53,13 @@
 /**
  * A RecyclerView with custom fast scroll support for the all apps view.
  */
-public class AllAppsRecyclerView extends FastScrollRecyclerView {
-    protected static final String TAG = "AllAppsRecyclerView";
+public class AllAppsRecyclerView extends BaseRecyclerView {
+    private static final String TAG = "AllAppsContainerView";
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_LATENCY = Utilities.isPropertyEnabled(SEARCH_LOGGING);
 
-    protected AlphabeticalAppsList<?> mApps;
-    protected final int mNumAppsPerRow;
+    private AlphabeticalAppsList<?> mApps;
+    private final int mNumAppsPerRow;
 
     // The specific view heights that we use to calculate scroll
     private final SparseIntArray mViewHeights = new SparseIntArray();
@@ -71,11 +71,31 @@
         public void onChanged() {
             mCachedScrollPositions.clear();
         }
+
+        @Override
+        public void onItemRangeChanged(int positionStart, int itemCount) {
+            onChanged();
+        }
+
+        @Override
+        public void onItemRangeInserted(int positionStart, int itemCount) {
+            onChanged();
+        }
+
+        @Override
+        public void onItemRangeRemoved(int positionStart, int itemCount) {
+            onChanged();
+        }
+
+        @Override
+        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+            onChanged();
+        }
     };
 
     // The empty-search result background
-    protected AllAppsBackgroundDrawable mEmptySearchBackground;
-    protected int mEmptySearchBackgroundTopOffset;
+    private AllAppsBackgroundDrawable mEmptySearchBackground;
+    private int mEmptySearchBackgroundTopOffset;
 
     private ArrayList<View> mAutoSizedOverlays = new ArrayList<>();
 
@@ -112,7 +132,7 @@
         return mApps;
     }
 
-    protected void updatePoolSize() {
+    private void updatePoolSize() {
         DeviceProfile grid = ActivityContext.lookupContext(getContext()).getDeviceProfile();
         RecyclerView.RecycledViewPool pool = getRecycledViewPool();
         int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
@@ -137,8 +157,8 @@
             Log.d(TAG, "onDraw at = " + System.currentTimeMillis());
         }
         if (DEBUG_LATENCY) {
-            Log.d(SEARCH_LOGGING,  getClass().getSimpleName() + " onDraw; time stamp = "
-                    + System.currentTimeMillis());
+            Log.d(SEARCH_LOGGING,
+                    "-- Recycle view onDraw, time stamp = " + System.currentTimeMillis());
         }
         super.onDraw(c);
     }
@@ -223,7 +243,8 @@
                 && mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
             mEmptySearchBackground.setHotspot(e.getX(), e.getY());
         }
-        hideKeyboardAsync(ActivityContext.lookupContext(getContext()), getApplicationWindowToken());
+        hideKeyboardAsync(ActivityContext.lookupContext(getContext()),
+                getApplicationWindowToken());
         return result;
     }
 
@@ -240,17 +261,14 @@
         // Find the fastscroll section that maps to this touch fraction
         List<AlphabeticalAppsList.FastScrollSectionInfo> fastScrollSections =
                 mApps.getFastScrollerSections();
-        AlphabeticalAppsList.FastScrollSectionInfo lastInfo = fastScrollSections.get(0);
-        for (int i = 1; i < fastScrollSections.size(); i++) {
-            AlphabeticalAppsList.FastScrollSectionInfo info = fastScrollSections.get(i);
-            if (info.touchFraction > touchFraction) {
-                break;
-            }
-            lastInfo = info;
+        int count = fastScrollSections.size();
+        if (count == 0) {
+            return "";
         }
-
-        mFastScrollHelper.smoothScrollToSection(lastInfo);
-        return lastInfo.sectionName;
+        int index = Utilities.boundToRange((int) (touchFraction * count), 0, count - 1);
+        AlphabeticalAppsList.FastScrollSectionInfo section = fastScrollSections.get(index);
+        mFastScrollHelper.smoothScrollToSection(section);
+        return section.sectionName;
     }
 
     @Override
@@ -271,12 +289,6 @@
     }
 
     @Override
-    protected float getBottomFadingEdgeStrength() {
-        // No bottom fading edge.
-        return 0;
-    }
-
-    @Override
     protected boolean isPaddingOffsetRequired() {
         return true;
     }
@@ -359,6 +371,13 @@
     }
 
     @Override
+    public boolean supportsFastScrolling() {
+        // Only allow fast scrolling when the user is not searching, since the results are not
+        // grouped in a meaningful order
+        return !mApps.hasFilter();
+    }
+
+    @Override
     public int getCurrentScrollY() {
         // Return early if there are no items or we haven't been measured
         List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
@@ -368,7 +387,7 @@
 
         // Calculate the y and offset for the item
         View child = getChildAt(0);
-        int position = getChildAdapterPosition(child);
+        int position = getChildPosition(child);
         if (position == NO_POSITION) {
             return -1;
         }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 723bc65..3600bd2 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -84,8 +84,7 @@
                 @Override
                 public Float get(AllAppsTransitionController controller) {
                     if (controller.mIsTablet) {
-                        return controller.mAppsView.getAppsRecyclerViewContainer()
-                                .getTranslationY();
+                        return controller.mAppsView.getRecyclerViewContainer().getTranslationY();
                     } else {
                         return controller.getAppsViewPullbackTranslationY().get(
                                 controller.mAppsView);
@@ -95,7 +94,7 @@
                 @Override
                 public void setValue(AllAppsTransitionController controller, float translation) {
                     if (controller.mIsTablet) {
-                        controller.mAppsView.getAppsRecyclerViewContainer().setTranslationY(
+                        controller.mAppsView.getRecyclerViewContainer().setTranslationY(
                                 translation);
                     } else {
                         controller.getAppsViewPullbackTranslationY().set(controller.mAppsView,
@@ -110,7 +109,7 @@
                 @Override
                 public Float get(AllAppsTransitionController controller) {
                     if (controller.mIsTablet) {
-                        return controller.mAppsView.getAppsRecyclerViewContainer().getAlpha();
+                        return controller.mAppsView.getRecyclerViewContainer().getAlpha();
                     } else {
                         return controller.getAppsViewPullbackAlpha().getValue();
                     }
@@ -119,7 +118,7 @@
                 @Override
                 public void setValue(AllAppsTransitionController controller, float alpha) {
                     if (controller.mIsTablet) {
-                        controller.mAppsView.getAppsRecyclerViewContainer().setAlpha(alpha);
+                        controller.mAppsView.getRecyclerViewContainer().setAlpha(alpha);
                     } else {
                         controller.getAppsViewPullbackAlpha().setValue(alpha);
                     }
@@ -191,6 +190,7 @@
     public void setProgress(float progress) {
         mProgress = progress;
         getAppsViewProgressTranslationY().set(mAppsView, mProgress * mShiftRange);
+        mLauncher.onAllAppsTransition(1 - progress);
     }
 
     public float getProgress() {
@@ -255,8 +255,6 @@
         anim.setInterpolator(verticalProgressInterpolator);
         anim.addListener(getProgressAnimatorListener());
         builder.add(anim);
-        // Use ANIM_VERTICAL_PROGRESS's interpolator to determine state transition threshold.
-        builder.setInterpolator(verticalProgressInterpolator);
 
         setAlphas(toState, config, builder);
 
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 42374b8..4ccfd39 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -15,25 +15,29 @@
  */
 package com.android.launcher3.allapps;
 
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ALL_APPS_DIVIDER;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_EMPTY_SEARCH;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_SEARCH_MARKET;
 
 import android.content.Context;
 
-import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.DiffUtil;
 
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.LabelComparator;
 import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Objects;
 import java.util.TreeMap;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * The alphabetically sorted list of applications.
@@ -45,10 +49,6 @@
 
     public static final String TAG = "AlphabeticalAppsList";
 
-    private static final int FAST_SCROLL_FRACTION_DISTRIBUTE_BY_ROWS_FRACTION = 0;
-    private static final int FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS = 1;
-
-    private final int mFastScrollDistributionMode = FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS;
     private final WorkAdapterProvider mWorkAdapterProvider;
 
     /**
@@ -57,14 +57,13 @@
      */
     public static class FastScrollSectionInfo {
         // The section name
-        public String sectionName;
-        // The AdapterItem to scroll to for this section
-        public AdapterItem fastScrollToItem;
-        // The touch fraction that should map to this fast scroll section info
-        public float touchFraction;
+        public final String sectionName;
+        // The item position
+        public final int position;
 
-        public FastScrollSectionInfo(String sectionName) {
+        public FastScrollSectionInfo(String sectionName, int position) {
             this.sectionName = sectionName;
+            this.position = position;
         }
     }
 
@@ -73,7 +72,6 @@
 
     // The set of apps from the system
     private final List<AppInfo> mApps = new ArrayList<>();
-    @Nullable
     private final AllAppsStore mAllAppsStore;
 
     // The number of results in current adapter
@@ -89,21 +87,19 @@
     private AppInfoComparator mAppNameComparator;
     private final int mNumAppsPerRowAllApps;
     private int mNumAppRowsInAdapter;
-    private ItemInfoMatcher mItemFilter;
+    private Predicate<ItemInfo> mItemFilter;
 
-    public AlphabeticalAppsList(Context context, @Nullable AllAppsStore appsStore,
+    public AlphabeticalAppsList(Context context, AllAppsStore appsStore,
             WorkAdapterProvider adapterProvider) {
         mAllAppsStore = appsStore;
         mActivityContext = ActivityContext.lookupContext(context);
         mAppNameComparator = new AppInfoComparator(context);
         mWorkAdapterProvider = adapterProvider;
         mNumAppsPerRowAllApps = mActivityContext.getDeviceProfile().inv.numAllAppsColumns;
-        if (mAllAppsStore != null) {
-            mAllAppsStore.addUpdateListener(this);
-        }
+        mAllAppsStore.addUpdateListener(this);
     }
 
-    public void updateItemFilter(ItemInfoMatcher itemFilter) {
+    public void updateItemFilter(Predicate<ItemInfo> itemFilter) {
         this.mItemFilter = itemFilter;
         onAppsUpdated();
     }
@@ -116,13 +112,6 @@
     }
 
     /**
-     * Returns all the apps.
-     */
-    public List<AppInfo> getApps() {
-        return mApps;
-    }
-
-    /**
      * Returns fast scroller sections of all the current filtered applications.
      */
     public List<FastScrollSectionInfo> getFastScrollerSections() {
@@ -173,9 +162,9 @@
     }
 
     /**
-     * Returns whether there are search results which will hide the A-Z list.
+     * Returns whether there are is a filter set.
      */
-    public boolean hasSearchResults() {
+    public boolean hasFilter() {
         return !mSearchResults.isEmpty();
     }
 
@@ -183,7 +172,7 @@
      * Returns whether there are no filtered results.
      */
     public boolean hasNoFilteredResults() {
-        return hasSearchResults() && mAccessibilityResultsCount == 0;
+        return hasFilter() && mAccessibilityResultsCount == 0;
     }
 
     /**
@@ -201,45 +190,19 @@
         return true;
     }
 
-    /** Appends results to search. */
-    public void appendSearchResults(ArrayList<AdapterItem> results) {
-        if (hasSearchResults() && results != null && results.size() > 0) {
-            updateSearchAdapterItems(results, mSearchResults.size());
-            mSearchResults.addAll(results);
-            refreshRecyclerView();
-        }
-    }
-
-    void updateSearchAdapterItems(ArrayList<AdapterItem> list, int offset) {
-        for (int i = 0; i < list.size(); i++) {
-            AdapterItem adapterItem = list.get(i);
-            adapterItem.position = offset + i;
-            mAdapterItems.add(adapterItem);
-
-            if (adapterItem.isCountedForAccessibility()) {
-                mAccessibilityResultsCount++;
-            }
-        }
-    }
-
     /**
      * Updates internals when the set of apps are updated.
      */
     @Override
     public void onAppsUpdated() {
-        if (mAllAppsStore == null) {
-            return;
-        }
         // Sort the list of apps
         mApps.clear();
 
-        for (AppInfo app : mAllAppsStore.getApps()) {
-            if (mItemFilter == null || mItemFilter.matches(app, null) || hasSearchResults()) {
-                mApps.add(app);
-            }
+        Stream<AppInfo> appSteam = Stream.of(mAllAppsStore.getApps());
+        if (!hasFilter() && mItemFilter != null) {
+            appSteam = appSteam.filter(mItemFilter);
         }
-
-        Collections.sort(mApps, mAppNameComparator);
+        appSteam = appSteam.sorted(mAppNameComparator);
 
         // As a special case for some languages (currently only Simplified Chinese), we may need to
         // coalesce sections
@@ -248,27 +211,16 @@
         if (localeRequiresSectionSorting) {
             // Compute the section headers. We use a TreeMap with the section name comparator to
             // ensure that the sections are ordered when we iterate over it later
-            TreeMap<String, ArrayList<AppInfo>> sectionMap = new TreeMap<>(new LabelComparator());
-            for (AppInfo info : mApps) {
-                // Add the section to the cache
-                String sectionName = info.sectionName;
-
-                // Add it to the mapping
-                ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
-                if (sectionApps == null) {
-                    sectionApps = new ArrayList<>();
-                    sectionMap.put(sectionName, sectionApps);
-                }
-                sectionApps.add(info);
-            }
-
-            // Add each of the section apps to the list in order
-            mApps.clear();
-            for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
-                mApps.addAll(entry.getValue());
-            }
+            appSteam = appSteam.collect(Collectors.groupingBy(
+                    info -> info.sectionName,
+                    () -> new TreeMap<>(new LabelComparator()),
+                    Collectors.toCollection(ArrayList::new)))
+                    .values()
+                    .stream()
+                    .flatMap(ArrayList::stream);
         }
 
+        appSteam.forEachOrdered(mApps::add);
         // Recompose the set of adapter items from the current set of apps
         if (mSearchResults.isEmpty()) {
             updateAdapterItems();
@@ -280,69 +232,49 @@
      * mCachedSectionNames to have been calculated for the set of all apps in mApps.
      */
     public void updateAdapterItems() {
-        refillAdapterItems();
-        refreshRecyclerView();
-    }
-
-    private void refreshRecyclerView() {
-        if (mAdapter != null) {
-            mAdapter.notifyDataSetChanged();
-        }
-    }
-
-    private void refillAdapterItems() {
-        String lastSectionName = null;
-        FastScrollSectionInfo lastFastScrollerSectionInfo = null;
-        int position = 0;
-        int appIndex = 0;
-
+        List<AdapterItem> oldItems = new ArrayList<>(mAdapterItems);
         // Prepare to update the list of sections, filtered apps, etc.
-        mAccessibilityResultsCount = 0;
         mFastScrollerSections.clear();
         mAdapterItems.clear();
+        mAccessibilityResultsCount = 0;
 
         // Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
         // ordered set of sections
-
-        if (hasSearchResults()) {
-            if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
-                // Append the search market item
-                if (hasNoFilteredResults()) {
-                    mSearchResults.add(AdapterItem.asEmptySearch(position++));
-                } else {
-                    mSearchResults.add(AdapterItem.asAllAppsDivider(position++));
-                }
-                mSearchResults.add(AdapterItem.asMarketSearch(position++));
-            }
-            updateSearchAdapterItems(mSearchResults, 0);
-        } else {
-            mAccessibilityResultsCount = mApps.size();
+        if (!hasFilter()) {
+            int position = 0;
             if (mWorkAdapterProvider != null) {
                 position += mWorkAdapterProvider.addWorkItems(mAdapterItems);
                 if (!mWorkAdapterProvider.shouldShowWorkApps()) {
                     return;
                 }
             }
+            String lastSectionName = null;
             for (AppInfo info : mApps) {
-                String sectionName = info.sectionName;
+                mAdapterItems.add(AdapterItem.asApp(info));
 
+                String sectionName = info.sectionName;
                 // Create a new section if the section names do not match
                 if (!sectionName.equals(lastSectionName)) {
                     lastSectionName = sectionName;
-                    lastFastScrollerSectionInfo = new FastScrollSectionInfo(sectionName);
-                    mFastScrollerSections.add(lastFastScrollerSectionInfo);
+                    mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, position));
                 }
-
-                // Create an app item
-                AdapterItem appItem = AdapterItem.asApp(position++, sectionName, info,
-                        appIndex++);
-                if (lastFastScrollerSectionInfo.fastScrollToItem == null) {
-                    lastFastScrollerSectionInfo.fastScrollToItem = appItem;
+                position++;
+            }
+        } else {
+            mAdapterItems.addAll(mSearchResults);
+            if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+                // Append the search market item
+                if (hasNoFilteredResults()) {
+                    mAdapterItems.add(new AdapterItem(VIEW_TYPE_EMPTY_SEARCH));
+                } else {
+                    mAdapterItems.add(new AdapterItem(VIEW_TYPE_ALL_APPS_DIVIDER));
                 }
-
-                mAdapterItems.add(appItem);
+                mAdapterItems.add(new AdapterItem(VIEW_TYPE_SEARCH_MARKET));
             }
         }
+        mAccessibilityResultsCount = (int) mAdapterItems.stream()
+                .filter(AdapterItem::isCountedForAccessibility).count();
+
         if (mNumAppsPerRowAllApps != 0) {
             // Update the number of rows in the adapter after we do all the merging (otherwise, we
             // would have to shift the values again)
@@ -365,37 +297,43 @@
                 }
             }
             mNumAppRowsInAdapter = rowIndex + 1;
+        }
 
-            // Pre-calculate all the fast scroller fractions
-            switch (mFastScrollDistributionMode) {
-                case FAST_SCROLL_FRACTION_DISTRIBUTE_BY_ROWS_FRACTION:
-                    float rowFraction = 1f / mNumAppRowsInAdapter;
-                    for (FastScrollSectionInfo info : mFastScrollerSections) {
-                        AdapterItem item = info.fastScrollToItem;
-                        if (!BaseAllAppsAdapter.isIconViewType(item.viewType)) {
-                            info.touchFraction = 0f;
-                            continue;
-                        }
-
-                        float subRowFraction =
-                                item.rowAppIndex * (rowFraction / mNumAppsPerRowAllApps);
-                        info.touchFraction = item.rowIndex * rowFraction + subRowFraction;
-                    }
-                    break;
-                case FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS:
-                    float perSectionTouchFraction = 1f / mFastScrollerSections.size();
-                    float cumulativeTouchFraction = 0f;
-                    for (FastScrollSectionInfo info : mFastScrollerSections) {
-                        AdapterItem item = info.fastScrollToItem;
-                        if (!BaseAllAppsAdapter.isIconViewType(item.viewType)) {
-                            info.touchFraction = 0f;
-                            continue;
-                        }
-                        info.touchFraction = cumulativeTouchFraction;
-                        cumulativeTouchFraction += perSectionTouchFraction;
-                    }
-                    break;
-            }
+        if (mAdapter != null) {
+            DiffUtil.calculateDiff(new MyDiffCallback(oldItems, mAdapterItems), false)
+                    .dispatchUpdatesTo(mAdapter);
         }
     }
+
+    private static class MyDiffCallback extends DiffUtil.Callback {
+
+        private final List<AdapterItem> mOldList;
+        private final List<AdapterItem> mNewList;
+
+        MyDiffCallback(List<AdapterItem> oldList, List<AdapterItem> newList) {
+            mOldList = oldList;
+            mNewList = newList;
+        }
+
+        @Override
+        public int getOldListSize() {
+            return mOldList.size();
+        }
+
+        @Override
+        public int getNewListSize() {
+            return mNewList.size();
+        }
+
+        @Override
+        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
+            return mOldList.get(oldItemPosition).isSameAs(mNewList.get(newItemPosition));
+        }
+
+        @Override
+        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
+            return mOldList.get(oldItemPosition).isContentSame(mNewList.get(newItemPosition));
+        }
+    }
+
 }
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 976284d..c7c4607 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -36,7 +36,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.views.ActivityContext;
 
 import java.util.Arrays;
@@ -89,72 +88,47 @@
      */
     public static class AdapterItem {
         /** Common properties */
-        // The index of this adapter item in the list
-        public int position;
         // The type of this item
-        public int viewType;
+        public final int viewType;
 
-        // The section name of this item.  Note that there can be multiple items with different
-        // sectionNames in the same section
-        public String sectionName = null;
         // The row that this item shows up on
         public int rowIndex;
         // The index of this app in the row
         public int rowAppIndex;
         // The associated ItemInfoWithIcon for the item
-        public ItemInfoWithIcon itemInfo = null;
-        // The index of this app not including sections
-        public int appIndex = -1;
-        // Search section associated to result
-        public DecorationInfo decorationInfo = null;
+        public AppInfo itemInfo = null;
+
+        public AdapterItem(int viewType) {
+            this.viewType = viewType;
+        }
 
         /**
          * Factory method for AppIcon AdapterItem
          */
-        public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
-                int appIndex) {
-            AdapterItem item = new AdapterItem();
-            item.viewType = VIEW_TYPE_ICON;
-            item.position = pos;
-            item.sectionName = sectionName;
+        public static AdapterItem asApp(AppInfo appInfo) {
+            AdapterItem item = new AdapterItem(VIEW_TYPE_ICON);
             item.itemInfo = appInfo;
-            item.appIndex = appIndex;
-            return item;
-        }
-
-        /**
-         * Factory method for empty search results view
-         */
-        public static AdapterItem asEmptySearch(int pos) {
-            AdapterItem item = new AdapterItem();
-            item.viewType = VIEW_TYPE_EMPTY_SEARCH;
-            item.position = pos;
-            return item;
-        }
-
-        /**
-         * Factory method for a dividerView in AllAppsSearch
-         */
-        public static AdapterItem asAllAppsDivider(int pos) {
-            AdapterItem item = new AdapterItem();
-            item.viewType = VIEW_TYPE_ALL_APPS_DIVIDER;
-            item.position = pos;
-            return item;
-        }
-
-        /**
-         * Factory method for a market search button
-         */
-        public static AdapterItem asMarketSearch(int pos) {
-            AdapterItem item = new AdapterItem();
-            item.viewType = VIEW_TYPE_SEARCH_MARKET;
-            item.position = pos;
             return item;
         }
 
         protected boolean isCountedForAccessibility() {
             return viewType == VIEW_TYPE_ICON || viewType == VIEW_TYPE_SEARCH_MARKET;
         }
+
+        /**
+         * Returns true if the items represent the same object
+         */
+        public boolean isSameAs(AdapterItem other) {
+            return (other.viewType != viewType) && (other.getClass() == getClass());
+        }
+
+        /**
+         * This is called only if {@link #isSameAs} returns true to check if the contents are same
+         * as well. Returning true will prevent redrawing of thee item.
+         */
+        public boolean isContentSame(AdapterItem other) {
+            return itemInfo == null && other.itemInfo == null;
+        }
     }
 
     protected final T mActivityContext;
@@ -267,11 +241,7 @@
                 AdapterItem adapterItem = mApps.getAdapterItems().get(position);
                 BubbleTextView icon = (BubbleTextView) holder.itemView;
                 icon.reset();
-                if (adapterItem.itemInfo instanceof AppInfo) {
-                    icon.applyFromApplicationInfo((AppInfo) adapterItem.itemInfo);
-                } else {
-                    icon.applyFromItemInfoWithIcon(adapterItem.itemInfo);
-                }
+                icon.applyFromApplicationInfo(adapterItem.itemInfo);
                 break;
             case VIEW_TYPE_EMPTY_SEARCH:
                 TextView emptyViewText = (TextView) holder.itemView;
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index 6a44989..72ca5a7 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -58,7 +58,7 @@
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
 import com.android.launcher3.keyboard.FocusedItemDecorator;
 import com.android.launcher3.model.StringCache;
-import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
@@ -69,6 +69,8 @@
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 /**
  * Base all apps view container.
@@ -80,7 +82,7 @@
         OnDeviceProfileChangeListener, OnActivePageChangedListener,
         ScrimView.ScrimDrawingController {
 
-    protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
+    private static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
 
     public static final float PULL_MULTIPLIER = .02f;
     public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
@@ -91,7 +93,7 @@
     /** Context of an activity or window that is inflating this container. */
     protected final T mActivityContext;
     protected final List<AdapterHolder> mAH;
-    protected final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(
+    protected final Predicate<ItemInfo> mPersonalMatcher = ItemInfoMatcher.ofUser(
             Process.myUserHandle());
     private final SearchAdapterProvider<?> mMainAdapterProvider;
     private final AllAppsStore mAllAppsStore = new AllAppsStore();
@@ -109,7 +111,6 @@
     private int mNavBarScrimHeight = 0;
 
     private AllAppsPagedView mViewPager;
-    private SearchRecyclerView mSearchRecyclerView;
 
     protected FloatingHeaderView mHeader;
     private View mBottomSheetBackground;
@@ -141,11 +142,10 @@
         mWorkManager = new WorkProfileManager(
                 mActivityContext.getSystemService(UserManager.class),
                 this,
-                Utilities.getPrefs(mActivityContext));
-        mAH = Arrays.asList(null, null, null);
-        mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN));
-        mAH.set(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
-        mAH.set(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
+                Utilities.getPrefs(mActivityContext), mActivityContext.getDeviceProfile());
+        mAH = Arrays.asList(null, null);
+        mAH.set(AdapterHolder.MAIN, new AdapterHolder(false /* isWork */));
+        mAH.set(AdapterHolder.WORK, new AdapterHolder(true /* isWork */));
 
         mNavBarScrimPaint = new Paint();
         mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
@@ -177,7 +177,7 @@
         Bundle state = (Bundle) sparseArray.get(R.id.work_tab_state_id, null);
         if (state != null) {
             int currentPage = state.getInt(BUNDLE_KEY_CURRENT_PAGE, 0);
-            if (currentPage == AdapterHolder.WORK && mViewPager != null) {
+            if (currentPage != 0 && mViewPager != null) {
                 mViewPager.setCurrentPage(currentPage);
                 rebindAdapters();
             } else {
@@ -200,7 +200,7 @@
      */
     public void setOnIconLongClickListener(OnLongClickListener listener) {
         for (AdapterHolder holder : mAH) {
-            holder.mAdapter.setOnIconLongClickListener(listener);
+            holder.adapter.setOnIconLongClickListener(listener);
         }
     }
 
@@ -215,7 +215,7 @@
     @Override
     public void onDeviceProfileChanged(DeviceProfile dp) {
         for (AdapterHolder holder : mAH) {
-            holder.mAdapter.setAppsPerRow(dp.numShownAllAppsColumns);
+            holder.adapter.setAppsPerRow(dp.numShownAllAppsColumns);
             if (holder.mRecyclerView != null) {
                 // Remove all views and clear the pool, while keeping the data same. After this
                 // call, all the viewHolders will be recreated.
@@ -231,17 +231,10 @@
     }
 
     private void onAppsUpdated() {
-        boolean hasWorkApps = false;
-        for (AppInfo app : mAllAppsStore.getApps()) {
-            if (mWorkManager.getMatcher().matches(app, null)) {
-                hasWorkApps = true;
-                break;
-            }
-        }
-        mHasWorkApps = hasWorkApps;
-        if (!mAH.get(AdapterHolder.MAIN).mAppsList.hasSearchResults()) {
+        mHasWorkApps = Stream.of(mAllAppsStore.getApps()).anyMatch(mWorkManager.getMatcher());
+        if (!mAH.get(AdapterHolder.MAIN).mAppsList.hasFilter()) {
             rebindAdapters();
-            if (hasWorkApps) {
+            if (mHasWorkApps) {
                 mWorkManager.reset();
             }
         }
@@ -258,11 +251,7 @@
         if (mActivityContext.getDragLayer().isEventOverView(mBottomSheetHandleArea, ev)) {
             return true;
         }
-        if (isSearching()) {
-            return mAH.get(AdapterHolder.SEARCH).mRecyclerView
-                    .shouldContainerScroll(ev, mActivityContext.getDragLayer());
-        }
-        AllAppsRecyclerView rv = getActiveAppsRecyclerView();
+        AllAppsRecyclerView rv = getActiveRecyclerView();
         if (rv == null) {
             return true;
         }
@@ -276,7 +265,7 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            AllAppsRecyclerView rv = getActiveAppsRecyclerView();
+            AllAppsRecyclerView rv = getActiveRecyclerView();
             if (rv != null && rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(),
                     mFastScrollerOffset)) {
                 mTouchHandler = rv.getScrollbar();
@@ -293,7 +282,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            AllAppsRecyclerView rv = getActiveAppsRecyclerView();
+            AllAppsRecyclerView rv = getActiveRecyclerView();
             if (rv != null && rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(),
                     mFastScrollerOffset)) {
                 mTouchHandler = rv.getScrollbar();
@@ -326,8 +315,8 @@
         return getContext().getString(R.string.all_apps_button_label);
     }
 
-    /** The current apps recycler view in the container (may be hidden for search results). */
-    public AllAppsRecyclerView getActiveAppsRecyclerView() {
+    /** The current recycler view visible in the container. */
+    public AllAppsRecyclerView getActiveRecyclerView() {
         if (!mUsingTabs || isPersonalTab()) {
             return mAH.get(AdapterHolder.MAIN).mRecyclerView;
         } else {
@@ -376,15 +365,12 @@
         // This is a focus listener that proxies focus from a view into the list view.  This is to
         // work around the search box from getting first focus and showing the cursor.
         setOnFocusChangeListener((v, hasFocus) -> {
-            if (hasFocus && getActiveAppsRecyclerView() != null) {
-                getActiveAppsRecyclerView().requestFocus();
+            if (hasFocus && getActiveRecyclerView() != null) {
+                getActiveRecyclerView().requestFocus();
             }
         });
 
         mHeader = findViewById(R.id.all_apps_header);
-        mSearchRecyclerView = findViewById(R.id.search_results_list_view);
-        mAH.get(AdapterHolder.SEARCH).setup(mSearchRecyclerView,
-                /* Filter out A-Z apps */ (itemInfo, componentName) -> false);
         rebindAdapters(true /* force */);
 
         mBottomSheetBackground = findViewById(R.id.bottom_sheet_background);
@@ -447,19 +433,17 @@
     }
 
     protected void rebindAdapters(boolean force) {
-        updateSearchResultsVisibility();
-
-        boolean showTabs = shouldShowTabs();
+        boolean showTabs = showTabs();
         if (showTabs == mUsingTabs && !force) {
             return;
         }
+
+        // replaceRVcontainer() needs to use both mUsingTabs value to remove the old view AND
+        // showTabs value to create new view. Hence the mUsingTabs new value assignment MUST happen
+        // after this call.
+        replaceRVContainer(showTabs);
         mUsingTabs = showTabs;
 
-        if (isSearching()) {
-            return;
-        }
-
-        replaceAppsRVContainer(mUsingTabs);
         mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.MAIN).mRecyclerView);
         mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
 
@@ -494,17 +478,6 @@
         mAllAppsStore.registerIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
     }
 
-    private void updateSearchResultsVisibility() {
-        if (isSearching()) {
-            getSearchRecyclerView().setVisibility(VISIBLE);
-            getAppsRecyclerViewContainer().setVisibility(GONE);
-        } else {
-            getSearchRecyclerView().setVisibility(GONE);
-            getAppsRecyclerViewContainer().setVisibility(VISIBLE);
-        }
-        mHeader.setActiveRV(getCurrentPage());
-    }
-
     private void setDeviceManagementResources() {
         if (mActivityContext.getStringCache() != null) {
             Button personalTab = findViewById(R.id.tab_personal);
@@ -515,23 +488,18 @@
         }
     }
 
-    protected boolean shouldShowTabs() {
+    protected boolean showTabs() {
         return mHasWorkApps;
     }
 
-    protected boolean isSearching() {
-        return false;
-    }
-
-    protected View replaceAppsRVContainer(boolean showTabs) {
-        for (int i = AdapterHolder.MAIN; i <= AdapterHolder.WORK; i++) {
-            AdapterHolder adapterHolder = mAH.get(i);
+    protected View replaceRVContainer(boolean showTabs) {
+        for (AdapterHolder adapterHolder : mAH) {
             if (adapterHolder.mRecyclerView != null) {
                 adapterHolder.mRecyclerView.setLayoutManager(null);
                 adapterHolder.mRecyclerView.setAdapter(null);
             }
         }
-        View oldView = getAppsRecyclerViewContainer();
+        View oldView = getRecyclerViewContainer();
         int index = indexOfChild(oldView);
         removeView(oldView);
         int layout = showTabs ? R.layout.all_apps_tabs : R.layout.all_apps_rv_layout;
@@ -552,17 +520,13 @@
         return newView;
     }
 
-    public View getAppsRecyclerViewContainer() {
+    public View getRecyclerViewContainer() {
         return mViewPager != null ? mViewPager : findViewById(R.id.apps_list_view);
     }
 
-    public SearchRecyclerView getSearchRecyclerView() {
-        return mSearchRecyclerView;
-    }
-
     @Override
     public void onActivePageChanged(int currentActivePage) {
-        mHeader.setActiveRV(currentActivePage);
+        mHeader.setMainActive(currentActivePage == AdapterHolder.MAIN);
         if (mAH.get(currentActivePage).mRecyclerView != null) {
             mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar();
         }
@@ -591,8 +555,8 @@
         return isDescendantViewVisible(R.id.tab_work);
     }
 
-    public AlphabeticalAppsList<T> getSearchResultList() {
-        return mAH.get(AdapterHolder.SEARCH).mAppsList;
+    public AlphabeticalAppsList<T> getApps() {
+        return mAH.get(AdapterHolder.MAIN).mAppsList;
     }
 
     public FloatingHeaderView getFloatingHeaderView() {
@@ -601,19 +565,17 @@
 
     @VisibleForTesting
     public View getContentView() {
-        return mViewPager == null ? getActiveAppsRecyclerView() : mViewPager;
+        return mViewPager == null ? getActiveRecyclerView() : mViewPager;
     }
 
     /** The current page visible in all apps. */
     public int getCurrentPage() {
-        return isSearching()
-                ? AdapterHolder.SEARCH
-                : mViewPager == null ? AdapterHolder.MAIN : mViewPager.getCurrentPage();
+        return mViewPager != null ? mViewPager.getCurrentPage() : AdapterHolder.MAIN;
     }
 
     /** The scroll bar for the active recycler view. */
     public RecyclerViewFastScroller getScrollBar() {
-        AllAppsRecyclerView rv = getActiveAppsRecyclerView();
+        AllAppsRecyclerView rv = getActiveRecyclerView();
         return rv == null ? null : rv.getScrollbar();
     }
 
@@ -622,9 +584,7 @@
         mHeader.setup(
                 mAH.get(AdapterHolder.MAIN).mRecyclerView,
                 mAH.get(AdapterHolder.WORK).mRecyclerView,
-                (SearchRecyclerView) mAH.get(AdapterHolder.SEARCH).mRecyclerView,
-                getCurrentPage(),
-                /* tabsHidden= */ mAH.get(AdapterHolder.WORK).mRecyclerView == null);
+                mAH.get(AdapterHolder.WORK).mRecyclerView == null);
 
         int padding = mHeader.getMaxTranslation();
         for (int i = 0; i < mAH.size(); i++) {
@@ -636,13 +596,6 @@
         }
     }
 
-    /** @see View#setVerticalFadingEdgeEnabled(boolean). */
-    public void setRecyclerViewVerticalFadingEdgeEnabled(boolean enabled) {
-        for (int i = 0; i < mAH.size(); i++) {
-            mAH.get(i).applyVerticalFadingEdgeEnabled(enabled);
-        }
-    }
-
     public boolean isHeaderVisible() {
         return mHeader != null && mHeader.getVisibility() == View.VISIBLE;
     }
@@ -735,90 +688,73 @@
         return ColorUtils.blendARGB(mScrimColor, mHeaderProtectionColor, blendRatio);
     }
 
-    protected abstract BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> mAppsList,
+    protected abstract BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
             BaseAdapterProvider[] adapterProviders);
 
     protected int getHeaderBottom() {
         return (int) getTranslationY();
     }
 
+    /** Holds a {@link BaseAllAppsAdapter} and related fields. */
+    public class AdapterHolder {
+        public static final int MAIN = 0;
+        public static final int WORK = 1;
+
+        private final boolean mIsWork;
+        public final BaseAllAppsAdapter<T> adapter;
+        final RecyclerView.LayoutManager mLayoutManager;
+        final AlphabeticalAppsList<T> mAppsList;
+        final Rect mPadding = new Rect();
+        AllAppsRecyclerView mRecyclerView;
+
+        AdapterHolder(boolean isWork) {
+            mIsWork = isWork;
+            mAppsList = new AlphabeticalAppsList<>(mActivityContext, mAllAppsStore,
+                    isWork ? mWorkManager.getAdapterProvider() : null);
+
+            BaseAdapterProvider[] adapterProviders =
+                    isWork ? new BaseAdapterProvider[]{mMainAdapterProvider,
+                            mWorkManager.getAdapterProvider()}
+                            : new BaseAdapterProvider[]{mMainAdapterProvider};
+
+            adapter = getAdapter(mAppsList, adapterProviders);
+            mAppsList.setAdapter(adapter);
+            mLayoutManager = adapter.getLayoutManager();
+        }
+
+        void setup(@NonNull View rv, @Nullable Predicate<ItemInfo> matcher) {
+            mAppsList.updateItemFilter(matcher);
+            mRecyclerView = (AllAppsRecyclerView) rv;
+            mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
+            mRecyclerView.setApps(mAppsList);
+            mRecyclerView.setLayoutManager(mLayoutManager);
+            mRecyclerView.setAdapter(adapter);
+            mRecyclerView.setHasFixedSize(true);
+            // No animations will occur when changes occur to the items in this RecyclerView.
+            mRecyclerView.setItemAnimator(null);
+            mRecyclerView.addOnScrollListener(mScrollListener);
+            FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mRecyclerView);
+            mRecyclerView.addItemDecoration(focusedItemDecorator);
+            adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
+            applyPadding();
+        }
+
+        void applyPadding() {
+            if (mRecyclerView != null) {
+                int bottomOffset = 0;
+                if (mIsWork && mWorkManager.getWorkModeSwitch() != null) {
+                    bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
+                }
+                mRecyclerView.setPadding(mPadding.left, mPadding.top, mPadding.right,
+                        mPadding.bottom + bottomOffset);
+            }
+        }
+    }
+
     /**
      * Returns a view that denotes the visible part of all apps container view.
      */
     public View getVisibleContainerView() {
         return mActivityContext.getDeviceProfile().isTablet ? mBottomSheetBackground : this;
     }
-
-    /** Holds a {@link BaseAllAppsAdapter} and related fields. */
-    public class AdapterHolder {
-        public static final int MAIN = 0;
-        public static final int WORK = 1;
-        public static final int SEARCH = 2;
-
-        private final int mType;
-        public final BaseAllAppsAdapter<T> mAdapter;
-        final RecyclerView.LayoutManager mLayoutManager;
-        final AlphabeticalAppsList<T> mAppsList;
-        final Rect mPadding = new Rect();
-        AllAppsRecyclerView mRecyclerView;
-        boolean mVerticalFadingEdge;
-
-        AdapterHolder(int type) {
-            mType = type;
-            mAppsList = new AlphabeticalAppsList<>(mActivityContext,
-                    isSearch() ? null : mAllAppsStore,
-                    isWork() ? mWorkManager.getAdapterProvider() : null);
-
-            BaseAdapterProvider[] adapterProviders =
-                    isWork() ? new BaseAdapterProvider[]{mMainAdapterProvider,
-                            mWorkManager.getAdapterProvider()}
-                            : new BaseAdapterProvider[]{mMainAdapterProvider};
-
-            mAdapter = createAdapter(mAppsList, adapterProviders);
-            mAppsList.setAdapter(mAdapter);
-            mLayoutManager = mAdapter.getLayoutManager();
-        }
-
-        void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
-            mAppsList.updateItemFilter(matcher);
-            mRecyclerView = (AllAppsRecyclerView) rv;
-            mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
-            mRecyclerView.setApps(mAppsList);
-            mRecyclerView.setLayoutManager(mLayoutManager);
-            mRecyclerView.setAdapter(mAdapter);
-            mRecyclerView.setHasFixedSize(true);
-            // No animations will occur when changes occur to the items in this RecyclerView.
-            mRecyclerView.setItemAnimator(null);
-            mRecyclerView.addOnScrollListener(mScrollListener);
-            FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mRecyclerView);
-            mRecyclerView.addItemDecoration(focusedItemDecorator);
-            mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
-            applyVerticalFadingEdgeEnabled(mVerticalFadingEdge);
-            applyPadding();
-        }
-
-        void applyPadding() {
-            if (mRecyclerView != null) {
-                int bottomOffset = 0;
-                if (isWork() && mWorkManager.getWorkModeSwitch() != null) {
-                    bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
-                }
-                mRecyclerView.setPadding(mPadding.left, mPadding.top, mPadding.right,
-                        mPadding.bottom + bottomOffset);
-            }
-        }
-
-        private void applyVerticalFadingEdgeEnabled(boolean enabled) {
-            mVerticalFadingEdge = enabled;
-            mRecyclerView.setVerticalFadingEdgeEnabled(!mUsingTabs && mVerticalFadingEdge);
-        }
-
-        private boolean isWork() {
-            return mType == WORK;
-        }
-
-        private boolean isSearch() {
-            return mType == SEARCH;
-        }
-    }
 }
diff --git a/src/com/android/launcher3/allapps/DecorationInfo.java b/src/com/android/launcher3/allapps/DecorationInfo.java
deleted file mode 100644
index 50b250c..0000000
--- a/src/com/android/launcher3/allapps/DecorationInfo.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2021 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.allapps;
-
-public class DecorationInfo {
-}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 3e717bd..72f14a8 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -33,7 +33,6 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
-import com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.views.ActivityContext;
@@ -91,8 +90,8 @@
     protected ViewGroup mTabLayout;
     private AllAppsRecyclerView mMainRV;
     private AllAppsRecyclerView mWorkRV;
-    private SearchRecyclerView mSearchRV;
     private AllAppsRecyclerView mCurrentRV;
+    private ViewGroup mParent;
     public boolean mHeaderCollapsed;
     protected int mSnappedScrolledY;
     private int mTranslationY;
@@ -101,6 +100,7 @@
 
     protected boolean mTabsHidden;
     protected int mMaxTranslation;
+    private boolean mMainRVActive = true;
 
     private boolean mCollapsed = false;
 
@@ -232,8 +232,7 @@
         return super.getFocusedChild();
     }
 
-    void setup(AllAppsRecyclerView mainRV, AllAppsRecyclerView workRV, SearchRecyclerView searchRV,
-            int activeRV, boolean tabsHidden) {
+    void setup(AllAppsRecyclerView mainRV, AllAppsRecyclerView workRV, boolean tabsHidden) {
         for (FloatingHeaderRow row : mAllRows) {
             row.setup(this, mAllRows, tabsHidden);
         }
@@ -243,8 +242,8 @@
         mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE);
         mMainRV = setupRV(mMainRV, mainRV);
         mWorkRV = setupRV(mWorkRV, workRV);
-        mSearchRV = (SearchRecyclerView) setupRV(mSearchRV, searchRV);
-        setActiveRV(activeRV);
+        mParent = (ViewGroup) mMainRV.getParent();
+        setMainActive(mMainRVActive || mWorkRV == null);
         reset(false);
     }
 
@@ -268,10 +267,9 @@
         }
     }
 
-    public void setActiveRV(int rvType) {
-        mCurrentRV =
-                rvType == AdapterHolder.MAIN ? mMainRV
-                : rvType == AdapterHolder.WORK ? mWorkRV : mSearchRV;
+    public void setMainActive(boolean active) {
+        mCurrentRV = active ? mMainRV : mWorkRV;
+        mMainRVActive = active;
     }
 
     public int getMaxTranslation() {
@@ -334,15 +332,10 @@
         mHeaderClip.top = clipTop;
         // clipping on a draw might cause additional redraw
         setClipBounds(mHeaderClip);
-        if (mMainRV != null) {
-            mMainRV.setClipBounds(mRVClip);
-        }
+        mMainRV.setClipBounds(mRVClip);
         if (mWorkRV != null) {
             mWorkRV.setClipBounds(mRVClip);
         }
-        if (mSearchRV != null) {
-            mSearchRV.setClipBounds(mRVClip);
-        }
     }
 
     /**
@@ -409,8 +402,8 @@
     }
 
     private void calcOffset(Point p) {
-        p.x = getLeft() - mCurrentRV.getLeft() - ((ViewGroup) mCurrentRV.getParent()).getLeft();
-        p.y = getTop() - mCurrentRV.getTop() - ((ViewGroup) mCurrentRV.getParent()).getTop();
+        p.x = getLeft() - mCurrentRV.getLeft() - mParent.getLeft();
+        p.y = getTop() - mCurrentRV.getTop() - mParent.getTop();
     }
 
     public boolean hasVisibleContent() {
diff --git a/src/com/android/launcher3/allapps/SearchRecyclerView.java b/src/com/android/launcher3/allapps/SearchRecyclerView.java
deleted file mode 100644
index 435668a..0000000
--- a/src/com/android/launcher3/allapps/SearchRecyclerView.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2022 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.allapps;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-/** A RecyclerView for AllApps Search results. */
-public class SearchRecyclerView extends AllAppsRecyclerView {
-    private static final String TAG = "SearchRecyclerView";
-
-    public SearchRecyclerView(Context context) {
-        this(context, null);
-    }
-
-    public SearchRecyclerView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SearchRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public SearchRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    @Override
-    protected void updatePoolSize() {
-        RecycledViewPool pool = getRecycledViewPool();
-        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, mNumAppsPerRow);
-        // TODO(b/206905515): Add maxes for other View types.
-    }
-
-    @Override
-    public boolean supportsFastScrolling() {
-        return false;
-    }
-}
diff --git a/src/com/android/launcher3/allapps/WorkAdapterProvider.java b/src/com/android/launcher3/allapps/WorkAdapterProvider.java
index ce44958..76d08c8 100644
--- a/src/com/android/launcher3/allapps/WorkAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/WorkAdapterProvider.java
@@ -19,10 +19,10 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Button;
 import android.widget.TextView;
 
 import com.android.launcher3.R;
+import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.views.ActivityContext;
 
@@ -107,13 +107,9 @@
     public int addWorkItems(ArrayList<AllAppsGridAdapter.AdapterItem> adapterItems) {
         if (mState == WorkProfileManager.STATE_DISABLED) {
             //add disabled card here.
-            AllAppsGridAdapter.AdapterItem disabledCard = new AllAppsGridAdapter.AdapterItem();
-            disabledCard.viewType = VIEW_TYPE_WORK_DISABLED_CARD;
-            adapterItems.add(disabledCard);
+            adapterItems.add(new AdapterItem(VIEW_TYPE_WORK_DISABLED_CARD));
         } else if (mState == WorkProfileManager.STATE_ENABLED && !isEduSeen()) {
-            AllAppsGridAdapter.AdapterItem eduCard = new AllAppsGridAdapter.AdapterItem();
-            eduCard.viewType = VIEW_TYPE_WORK_EDU_CARD;
-            adapterItems.add(eduCard);
+            adapterItems.add(new AdapterItem(VIEW_TYPE_WORK_EDU_CARD));
         }
 
         return adapterItems.size();
diff --git a/src/com/android/launcher3/allapps/WorkEduCard.java b/src/com/android/launcher3/allapps/WorkEduCard.java
index fa9a8f6..c336496 100644
--- a/src/com/android/launcher3/allapps/WorkEduCard.java
+++ b/src/com/android/launcher3/allapps/WorkEduCard.java
@@ -71,7 +71,7 @@
         super.onFinishInflate();
         findViewById(R.id.action_btn).setOnClickListener(this);
         MarginLayoutParams lp = ((MarginLayoutParams) findViewById(R.id.wrapper).getLayoutParams());
-        lp.width = mActivityContext.getAppsView().getActiveAppsRecyclerView().getTabWidth();
+        lp.width = mActivityContext.getAppsView().getActiveRecyclerView().getTabWidth();
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 6203cea..dc9f18c 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -27,19 +27,20 @@
 import android.os.UserManager;
 import android.util.Log;
 import android.view.ViewGroup;
-import android.view.WindowInsets;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.function.Predicate;
 
 /**
  * Companion class for {@link BaseAllAppsContainerView} to manage work tab and personal tab
@@ -70,18 +71,20 @@
 
     private final BaseAllAppsContainerView<?> mAllApps;
     private final WorkAdapterProvider mAdapterProvider;
-    private final ItemInfoMatcher mMatcher;
+    private final Predicate<ItemInfo> mMatcher;
 
     private WorkModeSwitch mWorkModeSwitch;
+    private final DeviceProfile mDeviceProfile;
 
     @WorkProfileState
     private int mCurrentState;
 
 
     public WorkProfileManager(UserManager userManager, BaseAllAppsContainerView<?> allApps,
-            SharedPreferences preferences) {
+            SharedPreferences preferences, DeviceProfile deviceProfile) {
         mUserManager = userManager;
         mAllApps = allApps;
+        mDeviceProfile = deviceProfile;
         mAdapterProvider = new WorkAdapterProvider(allApps.mActivityContext, preferences);
         mMatcher = mAllApps.mPersonalMatcher.negate();
     }
@@ -141,8 +144,11 @@
             mWorkModeSwitch = (WorkModeSwitch) mAllApps.getLayoutInflater().inflate(
                     R.layout.work_mode_fab, mAllApps, false);
         }
+        ViewGroup.MarginLayoutParams lp =
+                (ViewGroup.MarginLayoutParams) mWorkModeSwitch.getLayoutParams();
         int workFabMarginBottom =
-                mWorkModeSwitch.getResources().getDimensionPixelSize(R.dimen.work_fab_margin);
+                mWorkModeSwitch.getResources().getDimensionPixelSize(
+                        R.dimen.work_fab_margin_bottom);
         if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
             workFabMarginBottom <<= 1;  // Double margin to add space above search bar.
             workFabMarginBottom +=
@@ -151,8 +157,11 @@
         if (!mAllApps.mActivityContext.getDeviceProfile().isGestureMode){
             workFabMarginBottom += mAllApps.mActivityContext.getDeviceProfile().getInsets().bottom;
         }
-        ((ViewGroup.MarginLayoutParams) mWorkModeSwitch.getLayoutParams()).bottomMargin =
-                workFabMarginBottom;
+        lp.bottomMargin = workFabMarginBottom;
+        int totalScreenWidth = mDeviceProfile.widthPx;
+        int personalWorkTabWidth =
+                mAllApps.mActivityContext.getAppsView().getActiveRecyclerView().getTabWidth();
+        lp.rightMargin = lp.leftMargin = (totalScreenWidth - personalWorkTabWidth) / 2;
         if (mWorkModeSwitch.getParent() != mAllApps) {
             mAllApps.addView(mWorkModeSwitch);
         }
@@ -176,7 +185,7 @@
         return mAdapterProvider;
     }
 
-    public ItemInfoMatcher getMatcher() {
+    public Predicate<ItemInfo> getMatcher() {
         return mMatcher;
     }
 
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 4bd106f..6539c05 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -38,7 +38,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsStore;
-import com.android.launcher3.allapps.AlphabeticalAppsList;
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
 import com.android.launcher3.allapps.SearchUiManager;
 import com.android.launcher3.search.SearchCallback;
@@ -57,7 +56,6 @@
     private final AllAppsSearchBarController mSearchBarController;
     private final SpannableStringBuilder mSearchQueryBuilder;
 
-    private AlphabeticalAppsList<?> mSearchResultsList;
     private ActivityAllAppsContainerView<?> mAppsView;
 
     // The amount of pixels to shift down and overlap with the rest of the content.
@@ -102,8 +100,8 @@
         // Update the width to match the grid padding
         DeviceProfile dp = mLauncher.getDeviceProfile();
         int myRequestedWidth = getSize(widthMeasureSpec);
-        int rowWidth = myRequestedWidth - mAppsView.getActiveAppsRecyclerView().getPaddingLeft()
-                - mAppsView.getActiveAppsRecyclerView().getPaddingRight();
+        int rowWidth = myRequestedWidth - mAppsView.getActiveRecyclerView().getPaddingLeft()
+                - mAppsView.getActiveRecyclerView().getPaddingRight();
 
         int cellWidth = DeviceProfile.calculateCellWidth(rowWidth,
                 dp.cellLayoutBorderSpacePx.x, dp.numShownHotseatIcons);
@@ -131,7 +129,6 @@
 
     @Override
     public void initializeSearch(ActivityAllAppsContainerView<?> appsView) {
-        mSearchResultsList = appsView.getSearchResultList();
         mAppsView = appsView;
         mSearchBarController.initialize(
                 new DefaultAppSearchAlgorithm(getContext()),
@@ -170,25 +167,14 @@
     @Override
     public void onSearchResult(String query, ArrayList<AdapterItem> items) {
         if (items != null) {
-            mSearchResultsList.setSearchResults(items);
-            notifyResultChanged();
+            mAppsView.setSearchResults(items);
             mAppsView.setLastSearchQuery(query);
         }
     }
 
     @Override
-    public void onAppendSearchResult(String query, ArrayList<AdapterItem> items) {
-        if (items != null) {
-            mSearchResultsList.appendSearchResults(items);
-            notifyResultChanged();
-        }
-    }
-
-    @Override
     public void clearSearchResult() {
-        if (mSearchResultsList.setSearchResults(null)) {
-            notifyResultChanged();
-        }
+        mAppsView.setSearchResults(null);
 
         // Clear the search query
         mSearchQueryBuilder.clear();
@@ -197,10 +183,6 @@
         mAppsView.onClearSearchResult();
     }
 
-    private void notifyResultChanged() {
-        mAppsView.onSearchResultsChanged();
-    }
-
     @Override
     public void setInsets(Rect insets) {
         MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index 222c8fe..4eceb71 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -85,8 +85,7 @@
         for (int i = 0; i < total && resultCount < MAX_RESULTS_COUNT; i++) {
             AppInfo info = apps.get(i);
             if (StringMatcherUtility.matches(queryTextLower, info.title.toString(), matcher)) {
-                AdapterItem appItem = AdapterItem.asApp(resultCount, "", info, resultCount);
-                result.add(appItem);
+                result.add(AdapterItem.asApp(info));
                 resultCount++;
             }
         }
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 5a46ce1..c38cf9a 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -47,13 +47,6 @@
     public static final Interpolator DEACCEL_2_5 = new DecelerateInterpolator(2.5f);
     public static final Interpolator DEACCEL_3 = new DecelerateInterpolator(3f);
 
-    /**
-     * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
-     * is appearing e.g. when coming from off screen
-     */
-    public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
-            0.05f, 0.7f, 0.1f, 1f);
-
     public static final Interpolator ACCEL_DEACCEL = new AccelerateDecelerateInterpolator();
 
     public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -64,6 +57,11 @@
     public static final Interpolator DECELERATED_EASE = new PathInterpolator(0, 0, .2f, 1f);
     public static final Interpolator ACCELERATED_EASE = new PathInterpolator(0.4f, 0, 1f, 1f);
 
+    public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
+            0.3f, 0f, 0.8f, 0.15f);
+    public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
+            0.05f, 0.7f, 0.1f, 1f);
+
     public static final Interpolator EXAGGERATED_EASE;
 
     public static final Interpolator INSTANT = t -> 1;
@@ -163,14 +161,18 @@
                     String.format("upperBound (%f) must be greater than lowerBound (%f)",
                             upperBound, lowerBound));
         }
-        return t -> clampToProgress(t, lowerBound, upperBound);
+        return t -> clampToProgress(interpolator, t, lowerBound, upperBound);
     }
 
     /**
      * Returns the progress value's progress between the lower and upper bounds. That is, the
      * progress will be 0f from 0f to lowerBound, and reach 1f by upperBound.
+     *
+     * Between lowerBound and upperBound, the progress value will be interpolated using the provided
+     * interpolator.
      */
-    public static float clampToProgress(float progress, float lowerBound, float upperBound) {
+    public static float clampToProgress(
+            Interpolator interpolator, float progress, float lowerBound, float upperBound) {
         if (upperBound < lowerBound) {
             throw new IllegalArgumentException(
                     String.format("upperBound (%f) must be greater than lowerBound (%f)",
@@ -186,7 +188,15 @@
         if (progress > upperBound) {
             return 1;
         }
-        return (progress - lowerBound) / (upperBound - lowerBound);
+        return interpolator.getInterpolation((progress - lowerBound) / (upperBound - lowerBound));
+    }
+
+    /**
+     * Returns the progress value's progress between the lower and upper bounds. That is, the
+     * progress will be 0f from 0f to lowerBound, and reach 1f by upperBound.
+     */
+    public static float clampToProgress(float progress, float lowerBound, float upperBound) {
+        return clampToProgress(Interpolators.LINEAR, progress, lowerBound, upperBound);
     }
 
     /**
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 626e15c..54edb33 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -261,6 +261,10 @@
     public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = new DeviceFlag(
             "ENABLE_ONE_SEARCH_MOTION", true, "Enables animations in OneSearch.");
 
+    public static final BooleanFlag ENABLE_SHOW_KEYBOARD_IN_ALL_APPS = getDebugFlag(
+            "ENABLE_SHOW_KEYBOARD_IN_ALL_APPS", false,
+            "Enable option to show keyboard when going to all-apps");
+
     public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(
             "USE_LOCAL_ICON_OVERRIDES", true,
             "Use inbuilt monochrome icons if app doesn't provide one");
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index fdb2799..35cdfef 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -18,7 +18,6 @@
 
 import static com.android.launcher3.Utilities.ATLEAST_Q;
 
-import android.content.ComponentName;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -36,12 +35,12 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
 import java.util.Optional;
+import java.util.function.Predicate;
 
 /**
  * Class for initiating a drag within a view or across multiple views.
@@ -275,15 +274,12 @@
 
     protected abstract void exitDrag();
 
-    public void onAppsRemoved(ItemInfoMatcher matcher) {
+    public void onAppsRemoved(Predicate<ItemInfo> matcher) {
         // Cancel the current drag if we are removing an app that we are dragging
         if (mDragObject != null) {
             ItemInfo dragInfo = mDragObject.dragInfo;
-            if (dragInfo instanceof WorkspaceItemInfo) {
-                ComponentName cn = dragInfo.getTargetComponent();
-                if (cn != null && matcher.matches(dragInfo, cn)) {
-                    cancelDrag();
-                }
+            if (dragInfo instanceof WorkspaceItemInfo && matcher.test(dragInfo)) {
+                cancelDrag();
             }
         }
     }
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index 29e7c18..f9916d0 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -87,7 +87,8 @@
         // Total duration for the drop animation to complete.
         long duration = mContext.getResources().getInteger(R.integer.config_dropAnimMaxDuration) +
                 LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY +
-                LauncherState.SPRING_LOADED.getTransitionDuration(Launcher.getLauncher(mContext));
+                LauncherState.SPRING_LOADED.getTransitionDuration(Launcher.getLauncher(mContext),
+                        true /* isToState */);
         // Delay the actual accept() call until the drop animation is complete.
         return PinRequestHelper.createWorkspaceItemFromPinItemRequest(
                 mContext, mRequest, duration);
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index 2b621bd..5021644 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.folder;
 
+import android.annotation.SuppressLint;
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Process;
@@ -22,11 +24,15 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.WorkerThread;
+
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.model.AllAppsList;
 import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -94,6 +100,7 @@
     /**
      * Generate and rank the suggested Folder names.
      */
+    @WorkerThread
     public void getSuggestedFolderName(Context context,
             ArrayList<WorkspaceItemInfo> workspaceItemInfos,
             FolderNameInfos nameInfos) {
@@ -107,8 +114,7 @@
         Set<UserHandle> users = workspaceItemInfos.stream().map(w -> w.user)
                 .collect(Collectors.toSet());
         if (users.size() == 1 && !users.contains(Process.myUserHandle())) {
-            String workFolderName = context.getString(R.string.work_folder_name);
-            setAsLastSuggestion(nameInfos, workFolderName);
+            setAsLastSuggestion(nameInfos, getWorkFolderName(context));
         }
 
         // If all the icons are from same package (e.g., main icon, shortcut, shortcut)
@@ -130,6 +136,17 @@
         }
     }
 
+    @WorkerThread
+    @SuppressLint("NewApi")
+    private String getWorkFolderName(Context context) {
+        if (!Utilities.ATLEAST_T) {
+            return context.getString(R.string.work_folder_name);
+        }
+        return context.getSystemService(DevicePolicyManager.class).getResources()
+                .getString(StringCache.WORK_FOLDER_NAME, () ->
+                        context.getString(R.string.work_folder_name));
+    }
+
     private Optional<AppInfo> getAppInfoByPackageName(String packageName) {
         if (mAppInfos == null || mAppInfos.isEmpty()) {
             return Optional.empty();
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index a11bd4f..d5bcb0c 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -83,6 +83,7 @@
 import com.android.launcher3.uioverrides.PredictedAppIconInflater;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
@@ -129,7 +130,7 @@
             super(base, UserCache.INSTANCE, InstallSessionHelper.INSTANCE,
                     LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
                     CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE,
-                    WindowManagerProxy.INSTANCE);
+                    WindowManagerProxy.INSTANCE, DisplayController.INSTANCE);
             mIdp = idp;
             mObjectMap.put(InvariantDeviceProfile.INSTANCE, idp);
             mObjectMap.put(LauncherAppState.INSTANCE,
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index b8c9762..4875d83 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -36,9 +36,9 @@
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.PackageInstallInfo;
 import com.android.launcher3.util.FlagOp;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.SafeCloseable;
 
@@ -47,6 +47,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 
 /**
@@ -257,11 +258,11 @@
     /**
      * Updates the disabled flags of apps matching {@param matcher} based on {@param op}.
      */
-    public void updateDisabledFlags(ItemInfoMatcher matcher, FlagOp op) {
+    public void updateDisabledFlags(Predicate<ItemInfo> matcher, FlagOp op) {
         final List<AppInfo> data = this.data;
         for (int i = data.size() - 1; i >= 0; i--) {
             AppInfo info = data.get(i);
-            if (matcher.matches(info, info.componentName)) {
+            if (matcher.test(info)) {
                 info.runtimeStatusFlags = op.apply(info.runtimeStatusFlags);
                 mDataChanged = true;
             }
diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java
index a3a4717..832c1dd 100644
--- a/src/com/android/launcher3/model/BaseModelUpdateTask.java
+++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java
@@ -27,7 +27,6 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 
 import java.util.ArrayList;
@@ -35,6 +34,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 /**
@@ -128,7 +128,7 @@
         scheduleCallbackTask(c -> c.bindAllWidgets(widgets));
     }
 
-    public void deleteAndBindComponentsRemoved(final ItemInfoMatcher matcher) {
+    public void deleteAndBindComponentsRemoved(final Predicate<ItemInfo> matcher) {
         getModelWriter().deleteItemsFromDatabase(matcher);
 
         // Call the components-removed callback
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 866d18a..d52537e 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -50,7 +50,6 @@
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.IntSparseArrayMap;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 
@@ -66,6 +65,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -495,7 +495,7 @@
         default void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) { }
         default void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) { }
         default void bindRestoreItemsChange(HashSet<ItemInfo> updates) { }
-        default void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) { }
+        default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { }
         default void bindAllWidgets(List<WidgetsListBaseEntry> widgets) { }
 
         default void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks) {
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
index e36d4cf..ef9250c 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
@@ -216,14 +216,15 @@
             return false;
         }
 
+        // Sort the items by the reading order.
+        Collections.sort(mHotseatDiff);
+        Collections.sort(mWorkspaceDiff);
+
         // Migrate hotseat
         HotseatPlacementSolution hotseatSolution = new HotseatPlacementSolution(mDb, mSrcReader,
                 mDestReader, mContext, mDestHotseatSize, mHotseatItems, mHotseatDiff);
         hotseatSolution.find();
 
-        // Sort the items by the reading order.
-        Collections.sort(mWorkspaceDiff);
-
         // Migrate workspace.
         // First we create a collection of the screens
         List<Integer> screens = new ArrayList<>();
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 94e06d1..015abe9 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -53,6 +53,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
@@ -278,10 +279,9 @@
     /**
      * Removes all the items from the database matching {@param matcher}.
      */
-    public void deleteItemsFromDatabase(ItemInfoMatcher matcher) {
+    public void deleteItemsFromDatabase(Predicate<ItemInfo> matcher) {
         deleteItemsFromDatabase(StreamSupport.stream(mBgDataModel.itemsIdMap.spliterator(), false)
-                        .filter(matcher::matchesInfo)
-                        .collect(Collectors.toList()));
+                        .filter(matcher).collect(Collectors.toList()));
     }
 
     /**
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index d47edff..239dd45 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -57,6 +57,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Handles updates due to changes in package manager (app installed/updated/removed)
@@ -95,7 +96,7 @@
         final int N = packages.length;
         final FlagOp flagOp;
         final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
-        final ItemInfoMatcher matcher = mOp == OP_USER_AVAILABILITY_CHANGE
+        final Predicate<ItemInfo> matcher = mOp == OP_USER_AVAILABILITY_CHANGE
                 ? ItemInfoMatcher.ofUser(mUser) // We want to update all packages for this user
                 : ItemInfoMatcher.ofPackages(packageSet, mUser);
         final HashSet<ComponentName> removedComponents = new HashSet<>();
@@ -206,7 +207,7 @@
                     }
 
                     ComponentName cn = si.getTargetComponent();
-                    if (cn != null && matcher.matches(si, cn)) {
+                    if (cn != null && matcher.test(si)) {
                         String packageName = cn.getPackageName();
 
                         if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
@@ -336,7 +337,7 @@
         }
 
         if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
-            ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
+            Predicate<ItemInfo> removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
                     .or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
                     .and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
             deleteAndBindComponentsRemoved(removeMatch);
diff --git a/src/com/android/launcher3/model/ReloadStringCacheTask.java b/src/com/android/launcher3/model/ReloadStringCacheTask.java
new file mode 100644
index 0000000..f4d4298
--- /dev/null
+++ b/src/com/android/launcher3/model/ReloadStringCacheTask.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 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 com.android.launcher3.LauncherAppState;
+
+/**
+ * Handles updates due to changes in Device Policy Management resources triggered by
+ * {@link android.app.admin.DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED}.
+ */
+public class ReloadStringCacheTask extends BaseModelUpdateTask {
+    private ModelDelegate mModelDelegate;
+
+    public ReloadStringCacheTask(ModelDelegate modelDelegate) {
+        mModelDelegate = modelDelegate;
+    }
+
+    @Override
+    public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
+        synchronized (dataModel) {
+            mModelDelegate.loadStringCache(dataModel.stringCache);
+            StringCache cloneSC = dataModel.stringCache.clone();
+            scheduleCallbackTask(c -> c.bindStringCache(cloneSC));
+        }
+    }
+}
diff --git a/src/com/android/launcher3/model/StringCache.java b/src/com/android/launcher3/model/StringCache.java
index 663a463..9859ddc 100644
--- a/src/com/android/launcher3/model/StringCache.java
+++ b/src/com/android/launcher3/model/StringCache.java
@@ -35,6 +35,11 @@
     private static final String PREFIX = "Launcher.";
 
     /**
+     * Work folder name.
+     */
+    public static final String WORK_FOLDER_NAME = PREFIX + "WORK_FOLDER_NAME";
+
+    /**
      * User on-boarding title for work profile apps.
      */
     private static final String WORK_PROFILE_EDU = PREFIX + "WORK_PROFILE_EDU";
@@ -91,11 +96,6 @@
             PREFIX + "ALL_APPS_PERSONAL_TAB_ACCESSIBILITY";
 
     /**
-     * Work folder name.
-     */
-    private static final String WORK_FOLDER_NAME = PREFIX + "WORK_FOLDER_NAME";
-
-    /**
      * Label on widget tab to indicate work app widgets.
      */
     private static final String WIDGETS_WORK_TAB = PREFIX + "WIDGETS_WORK_TAB";
diff --git a/src/com/android/launcher3/search/SearchCallback.java b/src/com/android/launcher3/search/SearchCallback.java
index 5796116..495a303 100644
--- a/src/com/android/launcher3/search/SearchCallback.java
+++ b/src/com/android/launcher3/search/SearchCallback.java
@@ -32,13 +32,6 @@
     void onSearchResult(String query, ArrayList<T> items);
 
     /**
-     * Called when the search from secondary source is complete.
-     *
-     * @param items list of search results
-     */
-    void onAppendSearchResult(String query, ArrayList<T> items);
-
-    /**
      * Called when the search results should be cleared.
      */
     void clearSearchResult();
diff --git a/src/com/android/launcher3/shortcuts/ShortcutKey.java b/src/com/android/launcher3/shortcuts/ShortcutKey.java
index 0c6d675..9af68c0 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutKey.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutKey.java
@@ -57,11 +57,17 @@
     }
 
     public static Intent makeIntent(ShortcutInfo si) {
+        return makeIntent(si.getId(), si.getPackage()).setComponent(si.getActivity());
+    }
+
+    /**
+     * Creates an intent for shortcut id and package name.
+     */
+    public static Intent makeIntent(String shortcutId, String packageName) {
         return new Intent(Intent.ACTION_MAIN)
                 .addCategory(INTENT_CATEGORY)
-                .setComponent(si.getActivity())
-                .setPackage(si.getPackage())
+                .setPackage(packageName)
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
-                .putExtra(EXTRA_SHORTCUT_ID, si.getId());
+                .putExtra(EXTRA_SHORTCUT_ID, shortcutId);
     }
 }
diff --git a/src/com/android/launcher3/statemanager/BaseState.java b/src/com/android/launcher3/statemanager/BaseState.java
index 122573c..f9a36ad 100644
--- a/src/com/android/launcher3/statemanager/BaseState.java
+++ b/src/com/android/launcher3/statemanager/BaseState.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 
 /**
  * Interface representing a state of a StatefulActivity
@@ -36,7 +37,8 @@
     /**
      * @return How long the animation to this state should take (or from this state to NORMAL).
      */
-    int getTransitionDuration(Context context);
+    <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable>
+    int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState);
 
     /**
      * Returns the state to go back to from this state
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 1767939..2aa9dde 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -253,8 +253,8 @@
         // Since state mBaseState can be reached from multiple states, just assume that the
         // transition plays in reverse and use the same duration as previous state.
         mConfig.duration = state == mBaseState
-                ? fromState.getTransitionDuration(mActivity)
-                : state.getTransitionDuration(mActivity);
+                ? fromState.getTransitionDuration(mActivity, false /* isToState */)
+                : state.getTransitionDuration(mActivity, true /* isToState */);
         prepareForAtomicAnimation(fromState, state, mConfig);
         AnimatorSet animation = createAnimationToNewWorkspaceInternal(state).buildAnim();
         if (listener != null) {
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index 8b52016..4cfced8 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -43,7 +43,7 @@
     }
 
     @Override
-    public int getTransitionDuration(Context context) {
+    public int getTransitionDuration(Context context, boolean isToState) {
         return 80;
     }
 
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 7e9d56d..15cdc20 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -39,7 +39,7 @@
     }
 
     @Override
-    public int getTransitionDuration(Context context) {
+    public int getTransitionDuration(Context context, boolean isToState) {
         return 150;
     }
 
@@ -52,16 +52,7 @@
         }
 
         float shrunkTop = grid.getWorkspaceSpringLoadShrunkTop();
-        float shrunkBottom = grid.getWorkspaceSpringLoadShrunkBottom();
-        float scale = Math.min((shrunkBottom - shrunkTop) / ws.getNormalChildHeight(), 1f);
-
-        // Reduce scale if next pages would not be visible after scaling the workspace
-        float scaledWorkspaceWidth = ws.getWidth() * scale;
-        float maxAvailableWidth =
-                ws.getWidth() - (2 * grid.getWorkspaceSpringLoadedMinimumNextPageVisible());
-        if (scaledWorkspaceWidth > maxAvailableWidth) {
-            scale *= maxAvailableWidth / scaledWorkspaceWidth;
-        }
+        float scale = grid.getWorkspaceSpringLoadScale();
 
         float halfHeight = ws.getHeight() / 2;
         float myCenter = ws.getTop() + halfHeight;
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index f04e685..f99519d 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -53,6 +53,7 @@
             ANIM_WORKSPACE_FADE,
             ANIM_HOTSEAT_SCALE,
             ANIM_HOTSEAT_TRANSLATE,
+            ANIM_HOTSEAT_FADE,
             ANIM_OVERVIEW_SCALE,
             ANIM_OVERVIEW_TRANSLATE_X,
             ANIM_OVERVIEW_TRANSLATE_Y,
@@ -72,6 +73,7 @@
     public static final int ANIM_WORKSPACE_FADE = 3;
     public static final int ANIM_HOTSEAT_SCALE = 4;
     public static final int ANIM_HOTSEAT_TRANSLATE = 5;
+    public static final int ANIM_HOTSEAT_FADE = 16;
     public static final int ANIM_OVERVIEW_SCALE = 6;
     public static final int ANIM_OVERVIEW_TRANSLATE_X = 7;
     public static final int ANIM_OVERVIEW_TRANSLATE_Y = 8;
@@ -83,7 +85,7 @@
     public static final int ANIM_OVERVIEW_ACTIONS_FADE = 14;
     public static final int ANIM_WORKSPACE_PAGE_TRANSLATE_X = 15;
 
-    private static final int ANIM_TYPES_COUNT = 16;
+    private static final int ANIM_TYPES_COUNT = 17;
 
     protected final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
 
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index ee8f85d..242d2d4 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -108,7 +108,7 @@
 
             case TestProtocol.REQUEST_APPS_LIST_SCROLL_Y: {
                 return getLauncherUIProperty(Bundle::putInt,
-                        l -> l.getAppsView().getActiveAppsRecyclerView().getCurrentScrollY());
+                        l -> l.getAppsView().getActiveRecyclerView().getCurrentScrollY());
             }
 
             case TestProtocol.REQUEST_WIDGETS_SCROLL_Y: {
@@ -198,6 +198,12 @@
                     return new Point(cellRect.centerX(), cellRect.centerY());
                 });
 
+            case TestProtocol.REQUEST_HAS_TIS: {
+                response.putBoolean(
+                        TestProtocol.REQUEST_HAS_TIS, false);
+                return response;
+            }
+
             default:
                 return null;
         }
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index e8fd2ff..3a030a8 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -110,6 +110,7 @@
     public static final String REQUEST_GET_ACTIVITIES_CREATED_COUNT =
             "get-activities-created-count";
     public static final String REQUEST_GET_ACTIVITIES = "get-activities";
+    public static final String REQUEST_HAS_TIS = "has-touch-interaction-service";
 
     public static final String REQUEST_WORKSPACE_CELL_LAYOUT_SIZE = "workspace-cell-layout-size";
     public static final String REQUEST_WORKSPACE_CELL_CENTER = "workspace-cell-center";
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index a125fbe..09b8228 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -21,6 +21,7 @@
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
@@ -330,9 +331,6 @@
                         Math.min(progress, 1) - endProgress) * durationMultiplier;
             }
         }
-        if (targetState != mStartState) {
-            logReachedState(targetState);
-        }
         mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState));
         ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
         anim.setFloatValues(startProgress, endProgress);
@@ -361,6 +359,8 @@
         boolean shouldGoToTargetState = mGoingBetweenStates || (mToState != targetState);
         if (shouldGoToTargetState) {
             goToTargetState(targetState);
+        } else {
+            logReachedState(mToState);
         }
     }
 
@@ -368,13 +368,19 @@
         if (!mLauncher.isInState(targetState)) {
             // If we're already in the target state, don't jump to it at the end of the animation in
             // case the user started interacting with it before the animation finished.
-            mLauncher.getStateManager().goToState(targetState, false /* animated */);
+            mLauncher.getStateManager().goToState(targetState, false /* animated */,
+                    forEndCallback(() -> logReachedState(targetState)));
+        } else {
+            logReachedState(targetState);
         }
         mLauncher.getRootView().getSysUiScrim().createSysuiMultiplierAnim(
                 1f).setDuration(0).start();
     }
 
     private void logReachedState(LauncherState targetState) {
+        if (mStartState == targetState) {
+            return;
+        }
         // Transition complete. log the action
         mLauncher.getStatsLogManager().logger()
                 .withSrcState(mStartState.statsLogOrdinal)
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index 5aac3f3..9d7fd9a 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -17,11 +17,19 @@
 
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.Interpolators.DECELERATED_EASE;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED_DECELERATE;
 import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
 
 import android.view.MotionEvent;
 import android.view.animation.Interpolator;
@@ -39,11 +47,41 @@
 
     private static final float ALLAPPS_STAGGERED_FADE_THRESHOLD = 0.5f;
 
+    // Custom timing for NORMAL -> ALL_APPS on phones only.
+    private static final float WORKSPACE_MOTION_START = 0.1667f;
+    private static final float ALL_APPS_STATE_TRANSITION = 0.305f;
+    private static final float ALL_APPS_FADE_END = 0.4717f;
+
     public static final Interpolator ALLAPPS_STAGGERED_FADE_EARLY_RESPONDER =
             Interpolators.clampToProgress(LINEAR, 0, ALLAPPS_STAGGERED_FADE_THRESHOLD);
     public static final Interpolator ALLAPPS_STAGGERED_FADE_LATE_RESPONDER =
             Interpolators.clampToProgress(LINEAR, ALLAPPS_STAGGERED_FADE_THRESHOLD, 1f);
 
+    // Custom interpolators for NORMAL -> ALL_APPS on phones only.
+    public static final Interpolator BLUR =
+            Interpolators.clampToProgress(
+                    EMPHASIZED_DECELERATE, WORKSPACE_MOTION_START, ALL_APPS_STATE_TRANSITION);
+    public static final Interpolator WORKSPACE_SCALE =
+            Interpolators.clampToProgress(
+                    EMPHASIZED_DECELERATE, WORKSPACE_MOTION_START, ALL_APPS_STATE_TRANSITION);
+    public static final Interpolator HOTSEAT_FADE =
+            Interpolators.clampToProgress(FINAL_FRAME, 0f, ALL_APPS_STATE_TRANSITION);
+    public static final Interpolator HOTSEAT_TRANSLATE =
+            Interpolators.clampToProgress(
+                    EMPHASIZED_ACCELERATE, WORKSPACE_MOTION_START, ALL_APPS_STATE_TRANSITION);
+    public static final Interpolator SCRIM_FADE =
+            Interpolators.clampToProgress(
+                    Interpolators.mapToProgress(LINEAR, 0f, 0.8f),
+                    WORKSPACE_MOTION_START, ALL_APPS_STATE_TRANSITION);
+    public static final Interpolator ALL_APPS_FADE =
+            Interpolators.clampToProgress(
+                    Interpolators.mapToProgress(DECELERATED_EASE, 0.2f, 1.0f),
+                    ALL_APPS_STATE_TRANSITION, ALL_APPS_FADE_END);
+    public static final Interpolator ALL_APPS_VERTICAL_PROGRESS =
+            Interpolators.clampToProgress(
+                    Interpolators.mapToProgress(EMPHASIZED_DECELERATE, 0.4f, 1.0f),
+                    ALL_APPS_STATE_TRANSITION, 1.0f);
+
     public AllAppsSwipeController(Launcher l) {
         super(l, SingleAxisSwipeDetector.VERTICAL);
     }
@@ -118,11 +156,17 @@
      */
     public static void applyNormalToAllAppsAnimConfig(Launcher launcher,
             StateAnimationConfig config) {
-        boolean isTablet = launcher.getDeviceProfile().isTablet;
-        config.setInterpolator(ANIM_SCRIM_FADE, ALLAPPS_STAGGERED_FADE_EARLY_RESPONDER);
-        config.setInterpolator(ANIM_ALL_APPS_FADE, isTablet
-                ? INSTANT : ALLAPPS_STAGGERED_FADE_LATE_RESPONDER);
+        if (launcher.getDeviceProfile().isTablet) {
+            config.setInterpolator(ANIM_SCRIM_FADE, ALLAPPS_STAGGERED_FADE_EARLY_RESPONDER);
+            config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT);
+        } else {
+            config.setInterpolator(ANIM_DEPTH, BLUR);
+            config.setInterpolator(ANIM_WORKSPACE_SCALE, WORKSPACE_SCALE);
+            config.setInterpolator(ANIM_HOTSEAT_FADE, HOTSEAT_FADE);
+            config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, HOTSEAT_TRANSLATE);
+            config.setInterpolator(ANIM_SCRIM_FADE, SCRIM_FADE);
+            config.setInterpolator(ANIM_ALL_APPS_FADE, ALL_APPS_FADE);
+            config.setInterpolator(ANIM_VERTICAL_PROGRESS, ALL_APPS_VERTICAL_PROGRESS);
+        }
     }
-
-
 }
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 8005181..777da23 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -242,7 +242,9 @@
             change |= CHANGE_SUPPORTED_BOUNDS;
 
             Point currentS = newInfo.currentSize;
-            Point expectedS = oldInfo.mPerDisplayBounds.get(newInfo.displayId).first.size;
+            Pair<CachedDisplayInfo, WindowBounds[]> cachedBounds =
+                    oldInfo.mPerDisplayBounds.get(newInfo.displayId);
+            Point expectedS = cachedBounds == null ? null : cachedBounds.first.size;
             if (newInfo.supportedBounds.size() != oldInfo.supportedBounds.size()) {
                 Log.e("b/198965093",
                         "Inconsistent number of displays"
@@ -250,10 +252,12 @@
                                 + "\noldInfo.supportedBounds: " + oldInfo.supportedBounds
                                 + "\nnewInfo.supportedBounds: " + newInfo.supportedBounds);
             }
-            if ((Math.min(currentS.x, currentS.y) != Math.min(expectedS.x, expectedS.y)
+            if (expectedS != null
+                    && (Math.min(currentS.x, currentS.y) != Math.min(expectedS.x, expectedS.y)
                     || Math.max(currentS.x, currentS.y) != Math.max(expectedS.x, expectedS.y))
                     && display.getState() == Display.STATE_OFF) {
-                Log.e("b/198965093", "Display size changed while display is off, ignoring change");
+                Log.e("b/198965093",
+                        "Display size changed while display is off, ignoring change");
                 return;
             }
         }
diff --git a/src/com/android/launcher3/util/Executors.java b/src/com/android/launcher3/util/Executors.java
index 8485371..6978e0c 100644
--- a/src/com/android/launcher3/util/Executors.java
+++ b/src/com/android/launcher3/util/Executors.java
@@ -15,17 +15,12 @@
  */
 package com.android.launcher3.util;
 
-import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
-
-import static java.util.concurrent.Executors.newSingleThreadExecutor;
-
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Process;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -42,7 +37,7 @@
     private static final int KEEP_ALIVE = 1;
 
     /** Dedicated executor instances for work depending on other packages. */
-    private static final Map<String, ExecutorService> PACKAGE_EXECUTORS = new ConcurrentHashMap<>();
+    private static final Map<String, LooperExecutor> PACKAGE_EXECUTORS = new ConcurrentHashMap<>();
 
     /**
      * An {@link ThreadPoolExecutor} to be used with async task with no limit on the queue size.
@@ -90,11 +85,10 @@
      *
      * @param packageName Package associated with the executor.
      */
-    public static ExecutorService getPackageExecutor(String packageName) {
+    public static LooperExecutor getPackageExecutor(String packageName) {
         return PACKAGE_EXECUTORS.computeIfAbsent(
-                packageName,
-                p -> newSingleThreadExecutor(
-                        new SimpleThreadFactory(p, THREAD_PRIORITY_BACKGROUND)));
+                packageName, p -> new LooperExecutor(
+                        createAndStartNewLooper(p, Process.THREAD_PRIORITY_DEFAULT)));
     }
 
     /**
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index 7917410..b6af314 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -19,6 +19,8 @@
 import android.content.ComponentName;
 import android.os.UserHandle;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
@@ -27,90 +29,64 @@
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.function.Predicate;
 
 /**
  * A utility class to check for {@link ItemInfo}
  */
-public interface ItemInfoMatcher {
+public abstract class ItemInfoMatcher {
 
     /**
      * Empty component used for match testing
      */
-    ComponentName EMPTY_COMPONENT = new ComponentName("", "");
+    private static final ComponentName EMPTY_COMPONENT = new ComponentName("", "");
 
-    boolean matches(ItemInfo info, ComponentName cn);
-
-    /**
-     * Returns true if the itemInfo matches this check
-     */
-    default boolean matchesInfo(ItemInfo info) {
-        if (info != null) {
-            ComponentName cn = info.getTargetComponent();
-            return matches(info, cn != null ? cn : EMPTY_COMPONENT);
-        } else {
-            return false;
-        }
+    public static Predicate<ItemInfo> ofUser(UserHandle user) {
+        return info -> info != null && info.user.equals(user);
     }
 
-    /**
-     * Returns a new matcher with returns true if either this or {@param matcher} returns true.
-     */
-    default ItemInfoMatcher or(ItemInfoMatcher matcher) {
-        return (info, cn) -> matches(info, cn) || matcher.matches(info, cn);
+    public static Predicate<ItemInfo> ofComponents(
+            HashSet<ComponentName> components, UserHandle user) {
+        return info -> info != null && info.user.equals(user)
+                && components.contains(getNonNullComponent(info));
     }
 
-    /**
-     * Returns a new matcher with returns true if both this and {@param matcher} returns true.
-     */
-    default ItemInfoMatcher and(ItemInfoMatcher matcher) {
-        return (info, cn) -> matches(info, cn) && matcher.matches(info, cn);
+    public static Predicate<ItemInfo> ofPackages(Set<String> packageNames, UserHandle user) {
+        return info -> info != null && info.user.equals(user)
+                && packageNames.contains(getNonNullComponent(info).getPackageName());
     }
 
-    /**
-     * Returns a new matcher with returns the opposite value of this.
-     */
-    default ItemInfoMatcher negate() {
-        return (info, cn) -> !matches(info, cn);
-    }
-
-    static ItemInfoMatcher ofUser(UserHandle user) {
-        return (info, cn) -> info.user.equals(user);
-    }
-
-    static ItemInfoMatcher ofComponents(HashSet<ComponentName> components, UserHandle user) {
-        return (info, cn) -> components.contains(cn) && info.user.equals(user);
-    }
-
-    static ItemInfoMatcher ofPackages(Set<String> packageNames, UserHandle user) {
-        return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user);
-    }
-
-    static ItemInfoMatcher ofShortcutKeys(Set<ShortcutKey> keys) {
-        return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
+    public static Predicate<ItemInfo> ofShortcutKeys(Set<ShortcutKey> keys) {
+        return info -> info != null && info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
                 && keys.contains(ShortcutKey.fromItemInfo(info));
     }
 
     /**
      * Returns a matcher for items within folders.
      */
-    static ItemInfoMatcher forFolderMatch(ItemInfoMatcher childOperator) {
-        return (info, cn) -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
-                .anyMatch(childOperator::matchesInfo);
+    public static Predicate<ItemInfo> forFolderMatch(Predicate<ItemInfo> childOperator) {
+        return info -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
+                .anyMatch(childOperator);
     }
 
     /**
      * Returns a matcher for items with provided ids
      */
-    static ItemInfoMatcher ofItemIds(IntSet ids) {
-        return (info, cn) -> ids.contains(info.id);
+    public static Predicate<ItemInfo> ofItemIds(IntSet ids) {
+        return info -> info != null && ids.contains(info.id);
     }
 
     /**
      * Returns a matcher for items with provided items
      */
-    static ItemInfoMatcher ofItems(Collection<? extends ItemInfo> items) {
+    public static Predicate<ItemInfo> ofItems(Collection<? extends ItemInfo> items) {
         IntSet ids = new IntSet();
         items.forEach(item -> ids.add(item.id));
         return ofItemIds(ids);
     }
+
+    private static ComponentName getNonNullComponent(@NonNull ItemInfo info) {
+        ComponentName cn = info.getTargetComponent();
+        return cn != null ? cn : EMPTY_COMPONENT;
+    }
 }
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 5aaa275..92f718e 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -22,7 +22,9 @@
 import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT;
 import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT_LANDSCAPE;
 import static com.android.launcher3.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE;
-import static com.android.launcher3.ResourceUtils.getDimenByName;
+import static com.android.launcher3.ResourceUtils.STATUS_BAR_HEIGHT;
+import static com.android.launcher3.ResourceUtils.STATUS_BAR_HEIGHT_LANDSCAPE;
+import static com.android.launcher3.ResourceUtils.STATUS_BAR_HEIGHT_PORTRAIT;
 import static com.android.launcher3.Utilities.dpiFromPx;
 import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
 import static com.android.launcher3.util.RotationUtils.deltaRotation;
@@ -153,20 +155,26 @@
 
         boolean isTablet = config.smallestScreenWidthDp > MIN_TABLET_WIDTH;
         boolean isGesture = isGestureNav(context);
+        boolean isPortrait = config.screenHeightDp > config.screenWidthDp;
 
         int bottomNav = isTablet
                 ? 0
-                : (config.screenHeightDp > config.screenWidthDp
-                        ? getDimenByName(NAVBAR_HEIGHT, systemRes, 0)
+                : (isPortrait
+                        ? getDimenByName(systemRes, NAVBAR_HEIGHT)
                         : (isGesture
-                                ? getDimenByName(NAVBAR_HEIGHT_LANDSCAPE, systemRes, 0)
+                                ? getDimenByName(systemRes, NAVBAR_HEIGHT_LANDSCAPE)
                                 : 0));
         Insets newNavInsets = Insets.of(navInsets.left, navInsets.top, navInsets.right, bottomNav);
         insetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets);
         insetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(), newNavInsets);
 
         Insets statusBarInsets = oldInsets.getInsets(WindowInsets.Type.statusBars());
-        int statusBarHeight = getDimenByName("status_bar_height", systemRes, 0);
+
+
+        int statusBarHeight = getDimenByName(systemRes,
+                (isPortrait) ? STATUS_BAR_HEIGHT_PORTRAIT : STATUS_BAR_HEIGHT_LANDSCAPE,
+                STATUS_BAR_HEIGHT);
+
         Insets newStatusBarInsets = Insets.of(
                 statusBarInsets.left,
                 Math.max(statusBarInsets.top, statusBarHeight),
@@ -222,23 +230,26 @@
         boolean isTabletOrGesture = isTablet
                 || (Utilities.ATLEAST_R && isGestureNav(context));
 
-        int statusBarHeight = getDimenByName("status_bar_height", systemRes, 0);
+        int statusBarHeightPortrait = getDimenByName(systemRes,
+                STATUS_BAR_HEIGHT_PORTRAIT, STATUS_BAR_HEIGHT);
+        int statusBarHeightLandscape = getDimenByName(systemRes,
+                STATUS_BAR_HEIGHT_LANDSCAPE, STATUS_BAR_HEIGHT);
 
         int navBarHeightPortrait, navBarHeightLandscape, navbarWidthLandscape;
 
         navBarHeightPortrait = isTablet
                 ? (mTaskbarDrawnInProcess
                         ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
-                : getDimenByName(NAVBAR_HEIGHT, systemRes, 0);
+                : getDimenByName(systemRes, NAVBAR_HEIGHT);
 
         navBarHeightLandscape = isTablet
                 ? (mTaskbarDrawnInProcess
                         ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
                 : (isTabletOrGesture
-                        ? getDimenByName(NAVBAR_HEIGHT_LANDSCAPE, systemRes, 0) : 0);
+                        ? getDimenByName(systemRes, NAVBAR_HEIGHT_LANDSCAPE) : 0);
         navbarWidthLandscape = isTabletOrGesture
                 ? 0
-                : getDimenByName(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, systemRes, 0);
+                : getDimenByName(systemRes, NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
 
         WindowBounds[] result = new WindowBounds[4];
         Point tempSize = new Point();
@@ -248,13 +259,15 @@
             rotateSize(tempSize, rotationChange);
             Rect bounds = new Rect(0, 0, tempSize.x, tempSize.y);
 
-            int navBarHeight, navbarWidth;
+            int navBarHeight, navbarWidth, statusBarHeight;
             if (tempSize.y > tempSize.x) {
                 navBarHeight = navBarHeightPortrait;
                 navbarWidth = 0;
+                statusBarHeight = statusBarHeightPortrait;
             } else {
                 navBarHeight = navBarHeightLandscape;
                 navbarWidth = navbarWidthLandscape;
+                statusBarHeight = statusBarHeightLandscape;
             }
 
             Rect insets = new Rect(safeCutout);
@@ -274,6 +287,21 @@
         return result;
     }
 
+    /**
+     * Wrapper around the utility method for easier emulation
+     */
+    protected int getDimenByName(Resources res, String resName) {
+        return ResourceUtils.getDimenByName(resName, res, 0);
+    }
+
+    /**
+     * Wrapper around the utility method for easier emulation
+     */
+    protected int getDimenByName(Resources res, String resName, String fallback) {
+        int dimen = ResourceUtils.getDimenByName(resName, res, -1);
+        return dimen > -1 ? dimen : getDimenByName(res, fallback);
+    }
+
     protected boolean isGestureNav(Context context) {
         return ResourceUtils.getIntegerByName("config_navBarInteractionMode",
                 context.getResources(), INVALID_RESOURCE_HANDLE) == 2;
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index ed31e8d..47503b1 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -231,13 +231,17 @@
         if (mSwipeDetector.isIdleState()) {
             mOpenCloseAnimator
                     .setDuration(defaultDuration)
-                    .setInterpolator(Interpolators.ACCEL);
+                    .setInterpolator(getIdleInterpolator());
         } else {
             mOpenCloseAnimator.setInterpolator(mScrollInterpolator);
         }
         mOpenCloseAnimator.start();
     }
 
+    protected Interpolator getIdleInterpolator() {
+        return Interpolators.ACCEL;
+    }
+
     protected void onCloseComplete() {
         mIsOpen = false;
         getPopupContainer().removeView(this);
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index f71aa13..4c001fd 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -413,6 +413,14 @@
     }
 
     /**
+     * Similar to {@link #mapCoordInSelfToDescendant(View descendant, float[] coord)}
+     * but accepts a Rect instead of float[].
+     */
+    public void mapRectInSelfToDescendant(View descendant, Rect rect) {
+        Utilities.mapRectInSelfToDescendant(descendant, this, rect);
+    }
+
+    /**
      * Inverse of {@link #getDescendantCoordRelativeToSelf(View, float[])}.
      */
     public void mapCoordInSelfToDescendant(View descendant, float[] coord) {
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 5f6e453..a982786 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -43,7 +43,7 @@
 import androidx.annotation.RequiresApi;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.android.launcher3.FastScrollRecyclerView;
+import com.android.launcher3.BaseRecyclerView;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.graphics.FastScrollThumbDrawable;
@@ -127,7 +127,7 @@
     private String mPopupSectionName;
     private Insets mSystemGestureInsets;
 
-    protected FastScrollRecyclerView mRv;
+    protected BaseRecyclerView mRv;
     private RecyclerView.OnScrollListener mOnScrollListener;
 
     private int mDownX;
@@ -172,7 +172,7 @@
         ta.recycle();
     }
 
-    public void setRecyclerView(FastScrollRecyclerView rv, TextView popupView) {
+    public void setRecyclerView(BaseRecyclerView rv, TextView popupView) {
         if (mRv != null && mOnScrollListener != null) {
             mRv.removeOnScrollListener(mOnScrollListener);
         }
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index b12574f..c7bb612 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -44,6 +44,7 @@
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.AbstractSlideInView;
+import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.ArrowTipView;
 
 /**
@@ -306,4 +307,11 @@
         return mActivityContext.getSharedPrefs().getBoolean(KEY_WIDGETS_EDUCATION_TIP_SEEN, false)
                 || Utilities.IS_RUNNING_IN_TEST_HARNESS;
     }
+
+    @Override
+    protected void setTranslationShift(float translationShift) {
+        super.setTranslationShift(translationShift);
+        Launcher launcher = ActivityContext.lookupContext(getContext());
+        launcher.onWidgetsTransition(1 - translationShift);
+    }
 }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index b0e2ec1..48df04f 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -95,7 +95,7 @@
         mTitle = findViewById(R.id.app_title);
         mSubtitle = findViewById(R.id.app_subtitle);
         mExpandToggle = findViewById(R.id.toggle);
-        findViewById(R.id.app_container).setAccessibilityDelegate(new AccessibilityDelegate() {
+        setAccessibilityDelegate(new AccessibilityDelegate() {
 
             @Override
             public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index ea62c17..755e4a9 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -27,8 +27,8 @@
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
 
+import com.android.launcher3.BaseRecyclerView;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.FastScrollRecyclerView;
 import com.android.launcher3.R;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.widget.model.WidgetListSpaceEntry;
@@ -41,7 +41,7 @@
 /**
  * The widgets recycler view.
  */
-public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnItemTouchListener {
+public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouchListener {
 
     private WidgetsListAdapter mAdapter;
 
@@ -239,21 +239,6 @@
         mHeaderViewDimensionsProvider = headerViewDimensionsProvider;
     }
 
-    @Override
-    public void scrollToTop() {
-        if (mScrollbar != null) {
-            mScrollbar.reattachThumbToScroll();
-        }
-
-        if (getLayoutManager() instanceof LinearLayoutManager) {
-            if (getCurrentScrollY() == 0) {
-                // We are at the top, so don't scrollToPosition (would cause unnecessary relayout).
-                return;
-            }
-        }
-        scrollToPosition(0);
-    }
-
     /**
      * Returns the sum of the height, in pixels, of this list adapter's items from index 0 until
      * {@code untilIndex}.
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
index 2751a52..a15508a 100644
--- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
@@ -95,11 +95,6 @@
     }
 
     @Override
-    public void onAppendSearchResult(String query, ArrayList<WidgetsListBaseEntry> items) {
-        // Not needed.
-    }
-
-    @Override
     public void clearSearchResult() {
         // Any existing search session will be cancelled by setting text to empty.
         mInput.setText("");
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
index 8a435c9..ec921e8 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 
+import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
@@ -39,8 +40,11 @@
     }
 
     @Override
-    public int getTransitionDuration(Context context) {
-        return 320;
+    public <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable>
+    int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState) {
+        return !context.getDeviceProfile().isTablet && isToState
+                ? 600
+                : isToState ? 500 : 300;
     }
 
     @Override
@@ -55,15 +59,21 @@
 
     @Override
     public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
-        ScaleAndTranslation scaleAndTranslation =
-                new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET);
+        return new ScaleAndTranslation(0.97f, NO_OFFSET, NO_OFFSET);
+    }
+
+    @Override
+    public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
         if (launcher.getDeviceProfile().isTablet) {
-            scaleAndTranslation.scale = 0.97f;
+            return getWorkspaceScaleAndTranslation(launcher);
         } else {
-            scaleAndTranslation.translationY =
-                    -launcher.getAllAppsController().getShiftRange() * PARALLAX_COEFFICIENT;
+            ScaleAndTranslation overviewScaleAndTranslation = LauncherState.OVERVIEW
+                    .getWorkspaceScaleAndTranslation(launcher);
+            return new ScaleAndTranslation(
+                    NO_SCALE,
+                    overviewScaleAndTranslation.translationX,
+                    overviewScaleAndTranslation.translationY);
         }
-        return scaleAndTranslation;
     }
 
     @Override
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
index d154317..7a228c4 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -34,7 +34,7 @@
     }
 
     @Override
-    public int getTransitionDuration(Context context) {
+    public int getTransitionDuration(Context context, boolean isToState) {
         return 250;
     }
 
diff --git a/tests/res/raw/devices.json b/tests/res/raw/devices.json
new file mode 100644
index 0000000..a78dd86
--- /dev/null
+++ b/tests/res/raw/devices.json
@@ -0,0 +1,45 @@
+{
+  "pixel6pro": {
+    "width": 1440,
+    "height": 3120,
+    "density": 560,
+    "name": "pixel6pro",
+    "cutout": "0, 130, 0, 0",
+    "grids": [
+      "normal",
+      "reasonable",
+      "practical",
+      "big",
+      "crazy_big"
+    ],
+    "resourceOverrides": {
+      "status_bar_height": 98,
+      "navigation_bar_height_landscape": 56,
+      "navigation_bar_height": 56,
+      "navigation_bar_width": 56
+    }
+  },
+  "test": {
+    "data needs updating": 0
+  },
+  "pixel5": {
+    "width": 1080,
+    "height": 2340,
+    "density": 440,
+    "name": "pixel5",
+    "cutout": "0, 136, 0, 0",
+    "grids": [
+      "normal",
+      "reasonable",
+      "practical",
+      "big",
+      "crazy_big"
+    ],
+    "resourceOverrides": {
+      "status_bar_height": 66,
+      "navigation_bar_height_landscape": 44,
+      "navigation_bar_height": 44,
+      "navigation_bar_width": 44
+    }
+  }
+}
diff --git a/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java b/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java
new file mode 100644
index 0000000..31468c5
--- /dev/null
+++ b/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 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.deviceemulator;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+import androidx.test.uiautomator.UiDevice;
+
+import com.android.launcher3.deviceemulator.models.DeviceEmulationData;
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.util.window.WindowManagerProxy;
+
+import java.util.concurrent.Callable;
+
+
+public class DisplayEmulator {
+    Context mContext;
+    LauncherInstrumentation mLauncher;
+    DisplayEmulator(Context context, LauncherInstrumentation launcher) {
+        mContext = context;
+        mLauncher = launcher;
+    }
+
+    /**
+     * By changing the WindowManagerProxy we can override the window insets information
+     **/
+    private IWindowManager changeWindowManagerInstance(DeviceEmulationData deviceData) {
+        WindowManagerProxy.INSTANCE.initializeForTesting(
+                new TestWindowManagerProxy(mContext, deviceData));
+        return WindowManagerGlobal.getWindowManagerService();
+    }
+
+    public <T> T emulate(DeviceEmulationData device, String grid, Callable<T> runInEmulation)
+            throws Exception {
+        WindowManagerProxy original = WindowManagerProxy.INSTANCE.get(mContext);
+        // Set up emulation
+        final int userId = UserHandle.myUserId();
+        WindowManagerProxy.INSTANCE.initializeForTesting(
+                new TestWindowManagerProxy(mContext, device));
+        IWindowManager wm = changeWindowManagerInstance(device);
+        // Change density twice to force display controller to reset its state
+        wm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, device.density / 2, userId);
+        wm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, device.density, userId);
+        wm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, device.width, device.height);
+        wm.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 1);
+
+        // Set up grid
+        setGrid(grid);
+        try {
+            return runInEmulation.call();
+        } finally {
+            // Clear emulation
+            WindowManagerProxy.INSTANCE.initializeForTesting(original);
+            UiDevice.getInstance(getInstrumentation()).executeShellCommand("cmd window reset");
+        }
+    }
+
+    private void setGrid(String gridType) {
+        // When the grid changes, the desktop arrangement get stored in SQL and we need to wait to
+        // make sure there is no SQL operations running and get SQL_BUSY error, that's why we need
+        // to call mLauncher.waitForLauncherInitialized();
+        mLauncher.waitForLauncherInitialized();
+        String testProviderAuthority = mContext.getPackageName() + ".grid_control";
+        Uri gridUri = new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(testProviderAuthority)
+                .appendPath("default_grid")
+                .build();
+        ContentValues values = new ContentValues();
+        values.put("name", gridType);
+        mContext.getContentResolver().update(gridUri, values, null, null);
+    }
+}
diff --git a/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java b/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java
new file mode 100644
index 0000000..cbea688
--- /dev/null
+++ b/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 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.deviceemulator;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.WindowInsets;
+
+import com.android.launcher3.deviceemulator.models.DeviceEmulationData;
+import com.android.launcher3.util.RotationUtils;
+import com.android.launcher3.util.WindowBounds;
+import com.android.launcher3.util.window.CachedDisplayInfo;
+import com.android.launcher3.util.window.WindowManagerProxy;
+
+public class TestWindowManagerProxy extends WindowManagerProxy {
+
+    private final DeviceEmulationData mDevice;
+
+    public TestWindowManagerProxy(Context context, DeviceEmulationData device) {
+        super(true);
+        mDevice = device;
+    }
+
+    @Override
+    public boolean isInternalDisplay(Display display) {
+        return display.getDisplayId() == Display.DEFAULT_DISPLAY;
+    }
+
+    @Override
+    protected int getDimenByName(Resources res, String resName) {
+        Integer mock = mDevice.resourceOverrides.get(resName);
+        return mock != null ? mock : super.getDimenByName(res, resName);
+    }
+
+    @Override
+    protected int getDimenByName(Resources res, String resName, String fallback) {
+        return getDimenByName(res, resName);
+    }
+
+    @Override
+    public CachedDisplayInfo getDisplayInfo(Context context, Display display) {
+        int rotation = display.getRotation();
+        Point size = new Point(mDevice.width, mDevice.height);
+        RotationUtils.rotateSize(size, rotation);
+        Rect cutout = new Rect(mDevice.cutout);
+        RotationUtils.rotateRect(cutout, rotation);
+        return new CachedDisplayInfo(getDisplayId(display), size, rotation, cutout);
+    }
+
+    @Override
+    public WindowBounds getRealBounds(Context windowContext, Display display,
+            CachedDisplayInfo info) {
+        return estimateInternalDisplayBounds(windowContext)
+                .get(getDisplayId(display)).second[display.getRotation()];
+    }
+
+    @Override
+    public WindowInsets normalizeWindowInsets(Context context, WindowInsets oldInsets,
+            Rect outInsets) {
+        outInsets.set(getRealBounds(context, context.getDisplay(),
+                getDisplayInfo(context, context.getDisplay())).insets);
+        return oldInsets;
+    }
+}
diff --git a/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java b/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java
new file mode 100644
index 0000000..3623513
--- /dev/null
+++ b/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2022 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.deviceemulator.models;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT;
+import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT_LANDSCAPE;
+import static com.android.launcher3.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE;
+import static com.android.launcher3.ResourceUtils.getDimenByName;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.ArrayMap;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.IOUtils;
+import com.android.launcher3.util.IntArray;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Map;
+
+public class DeviceEmulationData {
+
+    public final int width;
+    public final int height;
+    public final int density;
+    public final String name;
+    public final String[] grids;
+    public final Rect cutout;
+    public final Map<String, Integer> resourceOverrides;
+
+    private static final String[] EMULATED_SYSTEM_RESOURCES = new String[]{
+            NAVBAR_HEIGHT,
+            NAVBAR_HEIGHT_LANDSCAPE,
+            NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE,
+            "status_bar_height",
+    };
+
+    public DeviceEmulationData(int width, int height, int density, Rect cutout, String name,
+            String[] grid,
+            Map<String, Integer> resourceOverrides) {
+        this.width = width;
+        this.height = height;
+        this.density = density;
+        this.name = name;
+        this.grids = grid;
+        this.cutout = cutout;
+        this.resourceOverrides = resourceOverrides;
+    }
+
+    public static DeviceEmulationData deviceFromJSON(JSONObject json) throws JSONException {
+        int width = json.getInt("width");
+        int height = json.getInt("height");
+        int density = json.getInt("density");
+        String name = json.getString("name");
+
+        JSONArray gridArray = json.getJSONArray("grids");
+        String[] grids = new String[gridArray.length()];
+        for (int i = 0, count = grids.length; i < count; i++) {
+            grids[i] = gridArray.getString(i);
+        }
+
+        IntArray deviceCutout = IntArray.fromConcatString(json.getString("cutout"));
+        Rect cutout = new Rect(deviceCutout.get(0), deviceCutout.get(1), deviceCutout.get(2),
+                deviceCutout.get(3));
+
+
+        JSONObject resourceOverridesJson = json.getJSONObject("resourceOverrides");
+        Map<String, Integer> resourceOverrides = new ArrayMap<>();
+        for (String key : resourceOverridesJson.keySet()) {
+            resourceOverrides.put(key, resourceOverridesJson.getInt(key));
+        }
+        return new DeviceEmulationData(width, height, density, cutout, name, grids,
+                resourceOverrides);
+    }
+
+    @Override
+    public String toString() {
+        JSONObject json = new JSONObject();
+        try {
+            json.put("width", width);
+            json.put("height", height);
+            json.put("density", density);
+            json.put("name", name);
+            json.put("cutout", IntArray.wrap(
+                    cutout.left, cutout.top, cutout.right, cutout.bottom).toConcatString());
+
+            JSONArray gridArray = new JSONArray();
+            Arrays.stream(grids).forEach(gridArray::put);
+            json.put("grids", gridArray);
+
+
+            JSONObject resourceOverrides = new JSONObject();
+            for (Map.Entry<String, Integer> e : this.resourceOverrides.entrySet()) {
+                resourceOverrides.put(e.getKey(), e.getValue());
+            }
+            json.put("resourceOverrides", resourceOverrides);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return json.toString();
+    }
+
+    public static DeviceEmulationData getCurrentDeviceData(Context context) {
+        DisplayController.Info info = DisplayController.INSTANCE.get(context).getInfo();
+        String[] grids = InvariantDeviceProfile.INSTANCE.get(context)
+                .parseAllGridOptions(context).stream()
+                .map(go -> go.name).toArray(String[]::new);
+        String code = Build.MODEL.replaceAll("\\s", "").toLowerCase();
+
+        Map<String, Integer> resourceOverrides = new ArrayMap<>();
+        for (String s : EMULATED_SYSTEM_RESOURCES) {
+            resourceOverrides.put(s, getDimenByName(s, context.getResources(), 0));
+        }
+        return new DeviceEmulationData(info.currentSize.x, info.currentSize.y,
+                info.densityDpi, info.cutout, code, grids, resourceOverrides);
+    }
+
+    public static DeviceEmulationData getDevice(String deviceCode) throws Exception {
+        return DeviceEmulationData.deviceFromJSON(readJSON().getJSONObject(deviceCode));
+    }
+
+    private static JSONObject readJSON() throws Exception {
+        Context context = getInstrumentation().getContext();
+        Resources myRes = context.getResources();
+        int resId = myRes.getIdentifier("devices", "raw", context.getPackageName());
+        try (InputStream is = myRes.openRawResource(resId)) {
+            return new JSONObject(new String(IOUtils.toByteArray(is)));
+        }
+    }
+
+}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 9b37741..6f8b9d2 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -525,7 +525,7 @@
     }
 
     protected int getAllAppsScroll(Launcher launcher) {
-        return launcher.getAppsView().getActiveAppsRecyclerView().getCurrentScrollY();
+        return launcher.getAppsView().getActiveRecyclerView().getCurrentScrollY();
     }
 
     private void checkLauncherIntegrity(
@@ -613,6 +613,10 @@
         return createShortcutIfNotExist(name, dimension.x / 2, dimension.y / 2);
     }
 
+    protected HomeAppIcon createShortcutIfNotExist(String name, Point cellPosition) {
+        return createShortcutIfNotExist(name, cellPosition.x, cellPosition.y);
+    }
+
     protected HomeAppIcon createShortcutIfNotExist(String name, int cellX, int cellY) {
         HomeAppIcon homeAppIcon = mLauncher.getWorkspace().tryGetWorkspaceAppIcon(name);
         if (homeAppIcon == null) {
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index f0bef24..15e8f68 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -18,6 +18,8 @@
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -54,11 +56,16 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.IOException;
+import java.util.Map;
+
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
     private static final String APP_NAME = "LauncherTestApp";
     private static final String DUMMY_APP_NAME = "Aardwolf";
+    private static final String MAPS_APP_NAME = "Maps";
+    private static final String STORE_APP_NAME = "Play Store";
 
     @Before
     public void setUp() throws Exception {
@@ -462,15 +469,7 @@
     @Test
     @PortraitLandscape
     public void testDragAppIconToWorkspaceCell() throws Exception {
-        final Point dimensions = mLauncher.getWorkspace().getIconGridDimensions();
-
-        Point[] targets = {
-                new Point(0, 1),
-                new Point(0, dimensions.y - 2),
-                new Point(dimensions.x - 1, 1),
-                new Point(dimensions.x - 1, dimensions.y - 2),
-                new Point(dimensions.x / 2, dimensions.y / 2)
-        };
+        Point[] targets = getCornersAndCenterPositions();
 
         for (Point target : targets) {
             final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
@@ -491,6 +490,48 @@
         }
     }
 
+    @Test
+    public void getIconsPosition_afterIconRemoved_notContained() throws IOException {
+        Point[] gridPositions = getCornersAndCenterPositions();
+        createShortcutIfNotExist(STORE_APP_NAME, gridPositions[0]);
+        createShortcutIfNotExist(MAPS_APP_NAME, gridPositions[1]);
+        TestUtil.installDummyApp();
+        try {
+            createShortcutIfNotExist(DUMMY_APP_NAME, gridPositions[2]);
+            Map<String, Point> initialPositions =
+                    mLauncher.getWorkspace().getWorkspaceIconsPositions();
+            assertThat(initialPositions.keySet())
+                    .containsAtLeast(DUMMY_APP_NAME, MAPS_APP_NAME, STORE_APP_NAME);
+
+            mLauncher.getWorkspace().getWorkspaceAppIcon(DUMMY_APP_NAME).uninstall();
+
+            assertNull(
+                    DUMMY_APP_NAME + " app was found after being uninstalled",
+                    mLauncher.getWorkspace().tryGetWorkspaceAppIcon(DUMMY_APP_NAME));
+
+            Map<String, Point> finalPositions =
+                    mLauncher.getWorkspace().getWorkspaceIconsPositions();
+            assertThat(finalPositions).doesNotContainKey(DUMMY_APP_NAME);
+        } finally {
+            TestUtil.uninstallDummyApp();
+        }
+    }
+
+    /**
+     * @return List of workspace grid coordinates. Those are not pixels. See {@link
+     *     Workspace#getIconGridDimensions()}
+     */
+    private Point[] getCornersAndCenterPositions() {
+        final Point dimensions = mLauncher.getWorkspace().getIconGridDimensions();
+        return new Point[] {
+            new Point(0, 1),
+            new Point(0, dimensions.y - 2),
+            new Point(dimensions.x - 1, 1),
+            new Point(dimensions.x - 1, dimensions.y - 2),
+            new Point(dimensions.x / 2, dimensions.y / 2)
+        };
+    }
+
     public static String getAppPackageName() {
         return getInstrumentation().getContext().getPackageName();
     }
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index 13b93d1..7c1be1d 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -25,11 +25,14 @@
 import android.util.Log;
 import android.view.View;
 
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsPagedView;
 import com.android.launcher3.allapps.WorkAdapterProvider;
 import com.android.launcher3.allapps.WorkEduCard;
+import com.android.launcher3.allapps.WorkPausedCard;
 import com.android.launcher3.allapps.WorkProfileManager;
 import com.android.launcher3.tapl.LauncherInstrumentation;
 
@@ -38,6 +41,7 @@
 import org.junit.Test;
 
 import java.util.Objects;
+import java.util.function.Predicate;
 
 public class WorkProfileTest extends AbstractLauncherUiTest {
 
@@ -130,12 +134,14 @@
             return manager.getCurrentState() == WorkProfileManager.STATE_DISABLED;
         }, LauncherInstrumentation.WAIT_TIME_MS);
 
+        waitForWorkCard("Work paused card not shown", view -> view instanceof WorkPausedCard);
+
         // start work profile toggle ON test
         executeOnLauncher(l -> {
             ActivityAllAppsContainerView<?> allApps = l.getAppsView();
             assertEquals("Work tab is not focused", allApps.getCurrentPage(), WORK_PAGE);
-            View workPausedCard = allApps.getActiveAppsRecyclerView()
-                    .findViewHolderForAdapterPosition(0).itemView;
+            View workPausedCard = allApps.getActiveRecyclerView().findViewHolderForAdapterPosition(
+                    0).itemView;
             workPausedCard.findViewById(R.id.enable_work_apps).performClick();
         });
         waitForLauncherCondition("Work profile toggle ON failed", launcher -> {
@@ -154,9 +160,19 @@
             l.getAppsView().getWorkManager().reset();
         });
 
-        waitForLauncherCondition("Work profile education not shown",
-                l -> l.getAppsView().getActiveAppsRecyclerView()
-                        .findViewHolderForAdapterPosition(0).itemView instanceof WorkEduCard,
-                LauncherInstrumentation.WAIT_TIME_MS);
+        waitForWorkCard("Work profile education not shown", view -> view instanceof WorkEduCard);
+    }
+
+    private void waitForWorkCard(String message, Predicate<View> workCardCheck) {
+        waitForLauncherCondition(message, l -> {
+            l.getAppsView().getAppsStore().disableDeferUpdates(DEFER_UPDATES_TEST);
+            ViewHolder holder = l.getAppsView().getActiveRecyclerView()
+                    .findViewHolderForAdapterPosition(0);
+            try {
+                return holder != null && workCardCheck.test(holder.itemView);
+            } finally {
+                l.getAppsView().getAppsStore().enableDeferUpdates(DEFER_UPDATES_TEST);
+            }
+        }, LauncherInstrumentation.WAIT_TIME_MS);
     }
 }
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 657f213..4c41d7e 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -132,7 +132,9 @@
         dumpCommand("logcat -d -s TestRunner", diagFile(description, "FilteredLogcat", "txt"));
 
         // Dump bugreport
-        if (launcher.getSystemAnomalyMessage(false, false) != null) {
+        final String systemAnomalyMessage = launcher.getSystemAnomalyMessage(false, false);
+        if (systemAnomalyMessage != null) {
+            Log.d(TAG, "Saving bugreport, system anomaly message: " + systemAnomalyMessage, e);
             dumpCommand("bugreportz -s", diagFile(description, "Bugreport", "zip"));
         }
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeQsb.java b/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
new file mode 100644
index 0000000..5f92199
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 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.tapl;
+
+/**
+ * Operations on home screen qsb.
+ */
+public class HomeQsb {
+
+    private final LauncherInstrumentation mLauncher;
+
+    HomeQsb(LauncherInstrumentation launcher) {
+        mLauncher = launcher;
+        mLauncher.waitForLauncherObject("search_container_hotseat");
+    }
+
+    /**
+     * Show search result page from tapping qsb.
+     */
+    public SearchResultFromQsb showSearchResult() {
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to open search result page");
+             LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            mLauncher.clickLauncherObject(
+                    mLauncher.waitForLauncherObject("search_container_hotseat"));
+            try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
+                    "clicked qsb to open search result page")) {
+                return new SearchResultFromQsb(mLauncher);
+            }
+        }
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 45a0196..39cd4ff 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -33,7 +33,7 @@
 /**
  * Ancestor for AppIcon and AppMenuItem.
  */
-abstract class Launchable {
+public abstract class Launchable {
 
     protected static final int DEFAULT_DRAG_STEPS = 10;
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index afb4f8d..2b3583e 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1499,9 +1499,14 @@
                 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
     }
 
+    private boolean hasTIS() {
+        return getTestInfo(TestProtocol.REQUEST_HAS_TIS).getBoolean(TestProtocol.REQUEST_HAS_TIS);
+    }
+
+
     public void sendPointer(long downTime, long currentTime, int action, Point point,
             GestureScope gestureScope) {
-        final boolean notLauncher3 = !isLauncher3();
+        final boolean hasTIS = hasTIS();
         switch (action) {
             case MotionEvent.ACTION_DOWN:
                 if (gestureScope != GestureScope.OUTSIDE_WITH_PILFER
@@ -1509,12 +1514,12 @@
                         && gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE) {
                     expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_DOWN);
                 }
-                if (notLauncher3 && getNavigationModel() != NavigationModel.THREE_BUTTON) {
+                if (hasTIS && getNavigationModel() != NavigationModel.THREE_BUTTON) {
                     expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
                 }
                 break;
             case MotionEvent.ACTION_UP:
-                if (notLauncher3 && gestureScope != GestureScope.INSIDE
+                if (hasTIS && gestureScope != GestureScope.INSIDE
                         && gestureScope != GestureScope.INSIDE_TO_OUTSIDE_WITHOUT_PILFER
                         && (gestureScope == GestureScope.OUTSIDE_WITH_PILFER
                         || gestureScope == GestureScope.INSIDE_TO_OUTSIDE)) {
@@ -1528,7 +1533,7 @@
                                     || gestureScope == GestureScope.OUTSIDE_WITHOUT_PILFER
                                     ? EVENT_TOUCH_UP : EVENT_TOUCH_CANCEL);
                 }
-                if (notLauncher3 && getNavigationModel() != NavigationModel.THREE_BUTTON) {
+                if (hasTIS && getNavigationModel() != NavigationModel.THREE_BUTTON) {
                     expectEvent(TestProtocol.SEQUENCE_TIS,
                             gestureScope == GestureScope.INSIDE_TO_OUTSIDE_WITH_KEYCODE
                                     || gestureScope == GestureScope.OUTSIDE_WITH_KEYCODE
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
new file mode 100644
index 0000000..82652c7
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 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.tapl;
+
+import android.widget.TextView;
+
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Operations on search result page opened from home screen qsb.
+ */
+public class SearchResultFromQsb {
+    // The input resource id in the search box.
+    private static final String INPUT_RES = "input";
+    private final LauncherInstrumentation mLauncher;
+
+    SearchResultFromQsb(LauncherInstrumentation launcher) {
+        mLauncher = launcher;
+        mLauncher.waitForLauncherObject("search_container_all_apps");
+    }
+
+    /** Set the input to the search input edit text and update search results. */
+    public void searchForInput(String input) {
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to search for result with an input");
+             LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            mLauncher.waitForLauncherObject(INPUT_RES).setText(input);
+        }
+    }
+
+    /** Find the app from search results with app name. */
+    public Launchable findAppIcon(String appName) {
+        UiObject2 icon = mLauncher.waitForLauncherObject(By.clazz(TextView.class).text(appName));
+        return new AllAppsAppIcon(mLauncher, icon);
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index fee4490..954af3d 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -43,6 +43,7 @@
 import com.android.launcher3.testing.WorkspaceCellCenterRequest;
 
 import java.util.List;
+import java.util.Map;
 import java.util.function.Supplier;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -111,6 +112,18 @@
     }
 
     /**
+     * Returns the home qsb.
+     *
+     * The qsb must already be visible when calling this method.
+     */
+    public HomeQsb getQsb() {
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to get the home qsb")) {
+            return new HomeQsb(mLauncher);
+        }
+    }
+
+    /**
      * Returns an icon for the app, if currently visible.
      *
      * @param appName name of the app
@@ -222,6 +235,21 @@
                 mHotseat, AppIcon.getAppIconSelector(appName, mLauncher)));
     }
 
+    /**
+     * @return map of text -> center of the view. In case of icons with the same name, the one with
+     *     lower x coordinate is selected.
+     */
+    public Map<String, Point> getWorkspaceIconsPositions() {
+        final UiObject2 workspace = verifyActiveContainer();
+        List<UiObject2> workspaceIcons =
+                mLauncher.waitForObjectsInContainer(workspace, AppIcon.getAnyAppIconSelector());
+        return workspaceIcons.stream()
+                .collect(
+                        Collectors.toMap(
+                                /* keyMapper= */ UiObject2::getText,
+                                /* valueMapper= */ UiObject2::getVisibleCenter,
+                                /* mergeFunction= */ (p1, p2) -> p1.x < p2.x ? p1 : p2));
+    }
     /*
      * Get the center point of the delete/uninstall icon in the drop target bar.
      */
@@ -389,8 +417,7 @@
             // Since the destination can be on another page, we need to drag to the edge first
             // until we reach the target page
             while (targetDest.x > displayX || targetDest.x < 0) {
-                // TODO: b/219919285
-                int edgeX = targetDest.x > 0 ? displayX - 1 : 1;
+                int edgeX = targetDest.x > 0 ? displayX : 0;
                 Point screenEdge = new Point(edgeX, targetDest.y);
                 Point finalDragStart = dragStart;
                 executeAndWaitForPageScroll(launcher,