Merge "Update TaskView fullscreen params when updating the thumbnail matrix" into ub-launcher3-rvc-dev
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index 5f5fab0..d552daf 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -51,6 +51,7 @@
     WidgetsContainer widgets_container = 5;
     PredictionContainer prediction_container = 6;
     SearchResultContainer search_result_container = 7;
+    ShortcutsContainer shortcuts_container = 8;
   }
 }
 
@@ -69,6 +70,11 @@
 message SearchResultContainer {
 }
 
+// Container for package specific shortcuts to deep links and notifications.
+// Typically shown as popup window by longpressing on an icon.
+message ShortcutsContainer {
+}
+
 enum Origin {
   UNKNOWN = 0;
   DEFAULT_LAYOUT = 1;       // icon automatically placed in workspace, folder, hotseat
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index 7c4f3ec..f1ce72e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -52,6 +52,7 @@
 
     private final Launcher mLauncher;
     private final Hotseat mHotseat;
+    private final HotseatRestoreHelper mRestoreHelper;
     private List<WorkspaceItemInfo> mPredictedApps;
     private HotseatEduDialog mActiveDialog;
 
@@ -59,9 +60,10 @@
     private IntArray mNewScreens = null;
     private Runnable mOnOnboardingComplete;
 
-    HotseatEduController(Launcher launcher, Runnable runnable) {
+    HotseatEduController(Launcher launcher, HotseatRestoreHelper restoreHelper, Runnable runnable) {
         mLauncher = launcher;
         mHotseat = launcher.getHotseat();
+        mRestoreHelper = restoreHelper;
         mOnOnboardingComplete = runnable;
     }
 
@@ -69,11 +71,14 @@
      * Checks what type of migration should be used and migrates hotseat
      */
     void migrate() {
+        mRestoreHelper.createBackup();
         if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) {
             migrateToFolder();
         } else {
             migrateHotseatWhole();
         }
+        Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_enabled, R.string.hotseat_turn_off,
+                null, () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
     }
 
     /**
@@ -84,7 +89,6 @@
      */
     private int migrateToFolder() {
         ArrayDeque<FolderInfo> folders = new ArrayDeque<>();
-
         ArrayList<WorkspaceItemInfo> putIntoFolder = new ArrayList<>();
 
         //separate folders and items that can get in folders
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index fa137f8..99cb3b3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -16,7 +16,8 @@
 package com.android.launcher3.hybridhotseat;
 
 import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.HYBRID_HOTSEAT_CANCELED;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType
+        .HYBRID_HOTSEAT_CANCELED;
 
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
@@ -144,11 +145,23 @@
         int rightInset = insets.right - mInsets.right;
         int bottomInset = insets.bottom - mInsets.bottom;
         mInsets.set(insets);
-        setPadding(leftInset, getPaddingTop(), rightInset, 0);
-        mHotseatWrapper.setPadding(mHotseatWrapper.getPaddingLeft(), getPaddingTop(),
-                mHotseatWrapper.getPaddingRight(), bottomInset);
-        mHotseatWrapper.getLayoutParams().height =
-                mLauncher.getDeviceProfile().hotseatBarSizePx + insets.bottom;
+        if (mLauncher.getOrientation() == Configuration.ORIENTATION_PORTRAIT) {
+            setPadding(leftInset, getPaddingTop(), rightInset, 0);
+            mHotseatWrapper.setPadding(mHotseatWrapper.getPaddingLeft(), getPaddingTop(),
+                    mHotseatWrapper.getPaddingRight(), bottomInset);
+            mHotseatWrapper.getLayoutParams().height =
+                    mLauncher.getDeviceProfile().hotseatBarSizePx + insets.bottom;
+
+        } else {
+            setPadding(0, getPaddingTop(), 0, 0);
+            mHotseatWrapper.setPadding(mHotseatWrapper.getPaddingLeft(), getPaddingTop(),
+                    mHotseatWrapper.getPaddingRight(),
+                    (int) getResources().getDimension(R.dimen.bottom_sheet_edu_padding));
+            ((TextView) findViewById(R.id.hotseat_edu_heading)).setText(
+                    R.string.hotseat_edu_title_migrate_landscape);
+            ((TextView) findViewById(R.id.hotseat_edu_content)).setText(
+                    R.string.hotseat_edu_message_migrate_landscape);
+        }
     }
 
     private void logUserAction(boolean migrated, int pageIndex) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 05bcb57..725f516 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -92,6 +92,8 @@
     private Launcher mLauncher;
     private final Hotseat mHotseat;
 
+    private final HotseatRestoreHelper mRestoreHelper;
+
     private List<ComponentKeyMapper> mComponentKeyMappers = new ArrayList<>();
 
     private DynamicItemCache mDynamicItemCache;
@@ -129,6 +131,7 @@
         mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons;
         launcher.getDeviceProfile().inv.addOnChangeListener(this);
         mHotseat.addOnAttachStateChangeListener(this);
+        mRestoreHelper = new HotseatRestoreHelper(mLauncher);
         if (mHotseat.isAttachedToWindow()) {
             onViewAttachedToWindow(mHotseat);
         }
@@ -297,7 +300,8 @@
         });
         setPauseUIUpdate(false);
         if (!isEduSeen()) {
-            mHotseatEduController = new HotseatEduController(mLauncher, this::createPredictor);
+            mHotseatEduController = new HotseatEduController(mLauncher, mRestoreHelper,
+                    this::createPredictor);
         }
     }
 
@@ -320,9 +324,11 @@
         updateDependencies();
         bindItems(items, false, null);
     }
-
     private void setPredictedApps(List<AppTarget> appTargets) {
         mComponentKeyMappers.clear();
+        if (appTargets.isEmpty() && mRestoreHelper.shouldRestoreToBackup()) {
+            mRestoreHelper.restoreBackup();
+        }
         StringBuilder predictionLog = new StringBuilder("predictedApps: [\n");
         ArrayList<ComponentKey> componentKeys = new ArrayList<>();
         for (AppTarget appTarget : appTargets) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java
new file mode 100644
index 0000000..c95ff7a
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 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.hybridhotseat;
+
+import static com.android.launcher3.LauncherSettings.Favorites.HYBRID_HOTSEAT_BACKUP_TABLE;
+import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.model.GridBackupTable;
+import com.android.launcher3.provider.LauncherDbUtils;
+
+/**
+ * A helper class to manage migration revert restoration for hybrid hotseat
+ */
+public class HotseatRestoreHelper {
+    private final Launcher mLauncher;
+    private boolean mBackupExists;
+
+    HotseatRestoreHelper(Launcher context) {
+        mLauncher = context;
+        setupBackupTable();
+    }
+
+    /**
+     * Creates a snapshot backup of Favorite table for future restoration use.
+     */
+    public synchronized void createBackup() {
+        try (LauncherDbUtils.SQLiteTransaction transaction = (LauncherDbUtils.SQLiteTransaction)
+                LauncherSettings.Settings.call(
+                        mLauncher.getContentResolver(),
+                        LauncherSettings.Settings.METHOD_NEW_TRANSACTION)
+                        .getBinder(LauncherSettings.Settings.EXTRA_VALUE)) {
+            InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
+            GridBackupTable backupTable = new GridBackupTable(mLauncher,
+                    transaction.getDb(), idp.numHotseatIcons, idp.numColumns,
+                    idp.numRows);
+            backupTable.createCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE);
+            transaction.commit();
+            LauncherSettings.Settings.call(mLauncher.getContentResolver(),
+                    LauncherSettings.Settings.METHOD_REFRESH_HOTSEAT_RESTORE_TABLE);
+            mBackupExists = true;
+        }
+    }
+
+    /**
+     * Finds and restores a previously saved snapshow of Favorites table
+     */
+    public void restoreBackup() {
+        try (LauncherDbUtils.SQLiteTransaction transaction = (LauncherDbUtils.SQLiteTransaction)
+                LauncherSettings.Settings.call(
+                        mLauncher.getContentResolver(),
+                        LauncherSettings.Settings.METHOD_NEW_TRANSACTION)
+                        .getBinder(LauncherSettings.Settings.EXTRA_VALUE)) {
+            if (!tableExists(transaction.getDb(), HYBRID_HOTSEAT_BACKUP_TABLE)) {
+                mBackupExists = false;
+                return;
+            }
+            InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
+            GridBackupTable backupTable = new GridBackupTable(mLauncher,
+                    transaction.getDb(), idp.numHotseatIcons, idp.numColumns,
+                    idp.numRows);
+            backupTable.restoreFromCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE, true);
+            transaction.commit();
+            mBackupExists = false;
+            mLauncher.getModel().forceReload();
+        }
+    }
+
+    /**
+     * Returns if prediction controller should attempt restoring a backup
+     */
+    public synchronized boolean shouldRestoreToBackup() {
+        return mBackupExists;
+    }
+
+    private synchronized void setupBackupTable() {
+        try (LauncherDbUtils.SQLiteTransaction transaction = (LauncherDbUtils.SQLiteTransaction)
+                LauncherSettings.Settings.call(
+                        mLauncher.getContentResolver(),
+                        LauncherSettings.Settings.METHOD_NEW_TRANSACTION)
+                        .getBinder(LauncherSettings.Settings.EXTRA_VALUE)) {
+            mBackupExists = tableExists(transaction.getDb(), HYBRID_HOTSEAT_BACKUP_TABLE);
+        }
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index a487869..79dc3e2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -37,6 +37,7 @@
 import static com.android.launcher3.anim.Interpolators.clampToProgress;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
 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_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
@@ -210,6 +211,7 @@
             }
             config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
             config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
+            config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2);
             Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
                     && removeShelfFromOverview(mActivity)
                     ? OVERSHOOT_1_2
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index c18a0fd..e5782e7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -33,11 +33,11 @@
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.quickstep.util.RemoteAnimationProvider;
+import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TransformParams;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
 
 /**
  * Provider for the atomic (for 3-button mode) remote window animation from the app to the overview.
@@ -132,8 +132,7 @@
 
         TransformParams params = new TransformParams()
                 .setTargetSet(targets)
-                .setSyncTransactionApplier(
-                        new SyncRtSurfaceTransactionApplierCompat(mActivity.getRootView()));
+                .setSyncTransactionApplier(new SurfaceTransactionApplier(mActivity.getRootView()));
 
         AnimatedFloat recentsAlpha = new AnimatedFloat(() -> { });
         params.setBaseBuilderProxy((builder, app, p)
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 737d837..6cbe794 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -40,13 +40,14 @@
 import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.ActivityInitListener;
+import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.TransformParams;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
 
 import java.util.ArrayList;
 import java.util.function.Consumer;
@@ -114,10 +115,10 @@
     public abstract Intent getLaunchIntent();
 
     protected void linkRecentsViewScroll() {
-        SyncRtSurfaceTransactionApplierCompat.create(mRecentsView, applier -> {
+        SurfaceTransactionApplier.create(mRecentsView, applier -> {
             mTransformParams.setSyncTransactionApplier(applier);
             runOnRecentsAnimationStart(() ->
-                    mRecentsAnimationTargets.addDependentTransactionApplier(applier));
+                    mRecentsAnimationTargets.addReleaseCheck(applier));
         });
 
         mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
@@ -356,7 +357,8 @@
         if (mWindowTransitionController != null) {
             float progress = mCurrentShift.value / mDragLengthFactor;
             mWindowTransitionController.setPlayFraction(progress);
-
+        }
+        if (mRecentsAnimationTargets != null) {
             if (mRecentsViewScrollLinked) {
                 mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
             }
@@ -364,6 +366,17 @@
         }
     }
 
+    @Override
+    protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
+            HomeAnimationFactory homeAnimationFactory) {
+        RectFSpringAnim anim =
+                super.createWindowAnimationToHome(startProgress, homeAnimationFactory);
+        if (mRecentsAnimationTargets != null) {
+            mRecentsAnimationTargets.addReleaseCheck(anim);
+        }
+        return anim;
+    }
+
     public interface Factory {
 
         BaseSwipeUpHandler newHandler(
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
index c92dd50..92e10b1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
@@ -29,6 +29,7 @@
 import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
 import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
 import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
+import static com.android.quickstep.GestureState.STATE_END_TARGET_SET;
 import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
 import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
 import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
@@ -253,6 +254,10 @@
         mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
                 this::notifyTransitionCancelled);
 
+        mGestureState.runOnceAtState(STATE_END_TARGET_SET,
+                () -> mDeviceState.onEndTargetCalculated(mGestureState.getEndTarget(),
+                        mActivityInterface));
+
         if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
                             | STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT,
@@ -1232,7 +1237,6 @@
         }
         ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
         doLogGesture(HOME);
-        mDeviceState.enableMultipleRegions(false);
     }
 
     protected abstract void finishRecentsControllerToHome(Runnable callback);
@@ -1248,7 +1252,6 @@
 
         SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
         doLogGesture(RECENTS);
-        mDeviceState.onSwipeUpToOverview(mActivityInterface);
         reset();
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
index 62eb235..4801d71 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
@@ -310,8 +310,8 @@
     @Override
     protected float getExtraSpace(Context context, DeviceProfile dp,
             PagedOrientationHandler orientationHandler) {
-        if (dp.isVerticalBarLayout() ||
-                hideShelfInTwoButtonLandscape(context, orientationHandler)) {
+        if ((dp.isVerticalBarLayout() && !showOverviewActions(context))
+                || hideShelfInTwoButtonLandscape(context, orientationHandler)) {
             return 0;
         } else {
             Resources res = context.getResources();
@@ -319,12 +319,14 @@
                 //TODO: this needs to account for the swipe gesture height and accessibility
                 // UI when shown.
                 float actionsBottomMargin = 0;
-                if (getMode(context) == Mode.THREE_BUTTONS) {
-                    actionsBottomMargin = res.getDimensionPixelSize(
+                if (!dp.isVerticalBarLayout()) {
+                    if (getMode(context) == Mode.THREE_BUTTONS) {
+                        actionsBottomMargin = res.getDimensionPixelSize(
                             R.dimen.overview_actions_bottom_margin_three_button);
-                } else {
-                    actionsBottomMargin = res.getDimensionPixelSize(
+                    } else {
+                        actionsBottomMargin = res.getDimensionPixelSize(
                             R.dimen.overview_actions_bottom_margin_gesture);
+                    }
                 }
                 float actionsHeight = actionsBottomMargin
                         + res.getDimensionPixelSize(R.dimen.overview_actions_height);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 0d49b2b..a28dabc 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -79,12 +79,13 @@
 
     @Override
     protected Activity getCurrentActivity() {
-        OverviewComponentObserver observer = new OverviewComponentObserver(mContext,
-                new RecentsAnimationDeviceState(mContext));
+        RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(mContext);
+        OverviewComponentObserver observer = new OverviewComponentObserver(mContext, rads);
         try {
             return observer.getActivityInterface().getCreatedActivity();
         } finally {
             observer.onDestroy();
+            rads.destroy();
         }
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java
index 021d39d..5b15c55 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java
@@ -18,6 +18,8 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP;
 import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
 
 import android.app.Activity;
@@ -35,6 +37,8 @@
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
+import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
 import com.android.launcher3.model.WellbeingModel;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.SystemShortcut;
@@ -68,7 +72,16 @@
     static WorkspaceItemInfo dummyInfo(TaskView view) {
         Task task = view.getTask();
 
-        WorkspaceItemInfo dummyInfo = new WorkspaceItemInfo();
+        WorkspaceItemInfo dummyInfo = new WorkspaceItemInfo(){
+            /**
+             * Helps to log events as {@link LauncherAtom.Task}
+             * instead of {@link LauncherAtom.ItemInfo}.
+             */
+            @Override
+            public LauncherAtom.ItemInfo buildProto() {
+                return view.buildProto();
+            }
+        };
         dummyInfo.intent = new Intent();
         ComponentName component = task.getTopComponent();
         dummyInfo.getIntent().setComponent(component);
@@ -83,10 +96,12 @@
 
         private final int mIconRes;
         private final int mTextRes;
+        private final LauncherEvent mLauncherEvent;
 
-        MultiWindowFactory(int iconRes, int textRes) {
+        MultiWindowFactory(int iconRes, int textRes, LauncherEvent launcherEvent) {
             mIconRes = iconRes;
             mTextRes = textRes;
+            mLauncherEvent = launcherEvent;
         }
 
         protected abstract boolean isAvailable(BaseDraggingActivity activity, int displayId);
@@ -102,7 +117,8 @@
             if (!isAvailable(activity, task.key.displayId)) {
                 return null;
             }
-            return new MultiWindowSystemShortcut(mIconRes, mTextRes, activity, taskView, this);
+            return new MultiWindowSystemShortcut(mIconRes, mTextRes, activity, taskView, this,
+                    mLauncherEvent);
         }
     }
 
@@ -114,11 +130,12 @@
         private final TaskThumbnailView mThumbnailView;
         private final TaskView mTaskView;
         private final MultiWindowFactory mFactory;
+        private final LauncherEvent mLauncherEvent;
 
-        public MultiWindowSystemShortcut(int iconRes, int textRes,
-                BaseDraggingActivity activity, TaskView taskView, MultiWindowFactory factory) {
+        public MultiWindowSystemShortcut(int iconRes, int textRes, BaseDraggingActivity activity,
+                TaskView taskView, MultiWindowFactory factory, LauncherEvent launcherEvent) {
             super(iconRes, textRes, activity, dummyInfo(taskView));
-
+            mLauncherEvent = launcherEvent;
             mHandler = new Handler(Looper.getMainLooper());
             mTaskView = taskView;
             mRecentsView = activity.getOverviewPanel();
@@ -203,12 +220,13 @@
                 WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
                         future, animStartedListener, mHandler, true /* scaleUp */,
                         taskKey.displayId);
+                mTarget.getStatsLogManager().log(mLauncherEvent, mTaskView.buildProto());
             }
         }
     }
 
-    TaskShortcutFactory SPLIT_SCREEN = new MultiWindowFactory(
-            R.drawable.ic_split_screen, R.string.recent_task_option_split_screen) {
+    TaskShortcutFactory SPLIT_SCREEN = new MultiWindowFactory(R.drawable.ic_split_screen,
+            R.string.recent_task_option_split_screen, LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP) {
 
         @Override
         protected boolean isAvailable(BaseDraggingActivity activity, int displayId) {
@@ -241,8 +259,8 @@
         }
     };
 
-    TaskShortcutFactory FREE_FORM = new MultiWindowFactory(
-            R.drawable.ic_split_screen, R.string.recent_task_option_freeform) {
+    TaskShortcutFactory FREE_FORM = new MultiWindowFactory(R.drawable.ic_split_screen,
+            R.string.recent_task_option_freeform, LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP) {
 
         @Override
         protected boolean isAvailable(BaseDraggingActivity activity, int displayId) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
index c68d6e2..e2e25f3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
@@ -42,6 +42,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.util.DefaultDisplay;
+import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TransformParams;
 import com.android.quickstep.views.RecentsView;
@@ -49,7 +50,6 @@
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
 
 /**
  * Utility class for helpful methods related to {@link TaskView} objects and their tasks.
@@ -128,11 +128,10 @@
             RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
             PendingAnimation out) {
 
-        SyncRtSurfaceTransactionApplierCompat applier =
-                new SyncRtSurfaceTransactionApplierCompat(v);
+        SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
         final RemoteAnimationTargets targets =
                 new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
-        targets.addDependentTransactionApplier(applier);
+        targets.addReleaseCheck(applier);
 
         TransformParams params = new TransformParams()
                     .setSyncTransactionApplier(applier)
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 4954588..6f596e9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -30,6 +30,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
 
 import android.annotation.TargetApi;
+import android.app.ActivityManager;
 import android.app.PendingIntent;
 import android.app.RemoteAction;
 import android.app.Service;
@@ -81,6 +82,7 @@
 import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
 import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
+import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.AssistantUtilities;
 import com.android.quickstep.util.ProtoTracer;
@@ -133,10 +135,10 @@
     private static final int MAX_BACK_NOTIFICATION_COUNT = 3;
 
     /**
-     * System Action ID to show all apps.  This ID should follow the ones in
-     * com.android.systemui.accessibility.SystemActions.
+     * System Action ID to show all apps.
+     * TODO: Use AccessibilityService's corresponding global action constant in S
      */
-    private static final int SYSTEM_ACTION_ID_ALL_APPS = 100;
+    private static final int SYSTEM_ACTION_ID_ALL_APPS = 14;
 
     private int mBackGestureNotificationCounter = -1;
     @Nullable
@@ -466,10 +468,17 @@
 
         final int action = event.getAction();
         if (action == ACTION_DOWN) {
+            if (TestProtocol.sDebugTracing) {
+                Log.d(TestProtocol.NO_SWIPE_TO_HOME, "TouchInteractionService.onInputEvent:DOWN");
+            }
             mDeviceState.setOrientationTransformIfNeeded(event);
             GestureState newGestureState;
 
             if (mDeviceState.isInSwipeUpTouchRegion(event)) {
+                if (TestProtocol.sDebugTracing) {
+                    Log.d(TestProtocol.NO_SWIPE_TO_HOME,
+                            "TouchInteractionService.onInputEvent:isInSwipeUpTouchRegion");
+                }
                 // Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
                 // onConsumerInactive and wipe the previous gesture state
                 GestureState prevGestureState = new GestureState(mGestureState);
@@ -479,18 +488,22 @@
 
                 ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + mConsumer.getName());
                 mUncheckedConsumer = mConsumer;
-            } else if (mDeviceState.isUserUnlocked()
-                    && mDeviceState.isFullyGesturalNavMode()
-                    && mDeviceState.canTriggerAssistantAction(event)) {
+            } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()) {
                 newGestureState = createGestureState();
-                // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should
-                // not interrupt it. QuickSwitch assumes that interruption can only happen if the
-                // next gesture is also quick switch.
-                mUncheckedConsumer = new AssistantInputConsumer(
-                    this,
-                    newGestureState,
-                    InputConsumer.NO_OP, mInputMonitorCompat,
-                    mOverviewComponentObserver.assistantGestureIsConstrained());
+                ActivityManager.RunningTaskInfo runningTask = newGestureState.getRunningTask();
+                if (mDeviceState.canTriggerAssistantAction(event, runningTask)) {
+                    // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
+                    // should not interrupt it. QuickSwitch assumes that interruption can only
+                    // happen if the next gesture is also quick switch.
+                    mUncheckedConsumer = new AssistantInputConsumer(
+                            this,
+                            newGestureState,
+                            InputConsumer.NO_OP, mInputMonitorCompat,
+                            mOverviewComponentObserver.assistantGestureIsConstrained());
+                } else {
+                    newGestureState = DEFAULT_STATE;
+                    mUncheckedConsumer = InputConsumer.NO_OP;
+                }
             } else {
                 newGestureState = DEFAULT_STATE;
                 mUncheckedConsumer = InputConsumer.NO_OP;
@@ -536,6 +549,9 @@
 
     private InputConsumer newConsumer(GestureState previousGestureState,
             GestureState newGestureState, MotionEvent event) {
+        if (TestProtocol.sDebugTracing) {
+            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer");
+        }
         boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
 
         if (!mDeviceState.isUserUnlocked()) {
@@ -547,6 +563,9 @@
                 return mResetGestureInputConsumer;
             }
         }
+        if (TestProtocol.sDebugTracing) {
+            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer:user is unlocked");
+        }
 
         // When there is an existing recents animation running, bypass systemState check as this is
         // a followup gesture and the first gesture started in a valid system state.
@@ -558,7 +577,7 @@
             handleOrientationSetup(base);
         }
         if (mDeviceState.isFullyGesturalNavMode()) {
-            if (mDeviceState.canTriggerAssistantAction(event)) {
+            if (mDeviceState.canTriggerAssistantAction(event, newGestureState.getRunningTask())) {
                 base = new AssistantInputConsumer(
                     this,
                     newGestureState,
@@ -588,6 +607,13 @@
                 }
             }
 
+            // If Bubbles is expanded, use the overlay input consumer, which will close Bubbles
+            // instead of going all the way home when a swipe up is detected.
+            if (mDeviceState.isBubblesExpanded()) {
+                base = new SysUiOverlayInputConsumer(
+                        getBaseContext(), mDeviceState, mInputMonitorCompat);
+            }
+
             if (mDeviceState.isScreenPinningActive()) {
                 // Note: we only allow accessibility to wrap this, and it replaces the previous
                 // base input consumer (which should be NO_OP anyway since topTaskLocked == true).
@@ -613,7 +639,7 @@
         if (!isFixedRotationTransformEnabled()) {
             return;
         }
-        mDeviceState.enableMultipleRegions(baseInputConsumer instanceof OtherActivityInputConsumer);
+        baseInputConsumer.notifyOrientationSetup();
     }
 
     private InputConsumer newBaseConsumer(GestureState previousGestureState,
@@ -725,12 +751,13 @@
         if (!mDeviceState.isUserUnlocked()) {
             return;
         }
+
         if (mDeviceState.isButtonNavMode() && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
             // Prevent the overview from being started before the real home on first boot.
             return;
         }
 
-        if (RestoreDbTask.isPending(this)) {
+        if (RestoreDbTask.isPending(this) || !mDeviceState.isUserSetupComplete()) {
             // Preloading while a restore is pending may cause launcher to start the restore
             // too early.
             return;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 8b08ea7..14215a1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -404,6 +404,11 @@
     }
 
     @Override
+    public void notifyOrientationSetup() {
+        mDeviceState.onStartGesture();
+    }
+
+    @Override
     public void onConsumerAboutToBeSwitched() {
         Preconditions.assertUIThread();
         mMainThreadHandler.removeCallbacks(mCancelRecentsAnimationRunnable);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
new file mode 100644
index 0000000..3f833c0
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.inputconsumers;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PointF;
+import android.view.MotionEvent;
+
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
+import com.android.quickstep.InputConsumer;
+import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+/**
+ * Input consumer used when a fullscreen System UI overlay is showing (such as the expanded Bubbles
+ * UI).
+ *
+ * This responds to swipes up by sending a closeSystemDialogs broadcast (causing overlays to close)
+ * rather than closing the app behind the overlay and sending the user all the way home.
+ */
+public class SysUiOverlayInputConsumer implements InputConsumer,
+        TriggerSwipeUpTouchTracker.OnSwipeUpListener {
+
+    private final Context mContext;
+    private final InputMonitorCompat mInputMonitor;
+    private final TriggerSwipeUpTouchTracker mTriggerSwipeUpTracker;
+
+    public SysUiOverlayInputConsumer(
+            Context context,
+            RecentsAnimationDeviceState deviceState,
+            InputMonitorCompat inputMonitor) {
+        mContext = context;
+        mInputMonitor = inputMonitor;
+        mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(context, true,
+                deviceState.getNavBarPosition(), this::onInterceptTouch, this);
+    }
+
+    @Override
+    public int getType() {
+        return TYPE_SYSUI_OVERLAY;
+    }
+
+    @Override
+    public boolean allowInterceptByParent() {
+        return !mTriggerSwipeUpTracker.interceptedTouch();
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent ev) {
+        mTriggerSwipeUpTracker.onMotionEvent(ev);
+    }
+
+    private void onInterceptTouch() {
+        if (mInputMonitor != null) {
+            TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
+            mInputMonitor.pilferPointers();
+        }
+    }
+
+    @Override
+    public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
+        // Close system dialogs when a swipe up is detected.
+        mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+    }
+
+    @Override
+    public void onSwipeUpCancelled() {
+
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
index 8a6c4a1..e5d2c53 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -29,6 +29,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.FlingSpringAnim;
 import com.android.launcher3.util.DynamicResource;
+import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
 import com.android.systemui.plugins.ResourceProvider;
 
 import java.util.ArrayList;
@@ -39,7 +40,7 @@
  * Applies spring forces to animate from a starting rect to a target rect,
  * while providing update callbacks to the caller.
  */
-public class RectFSpringAnim {
+public class RectFSpringAnim extends ReleaseCheck {
 
     private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_X =
             new FloatPropertyCompat<RectFSpringAnim>("rectCenterXSpring") {
@@ -116,6 +117,7 @@
         ResourceProvider rp = DynamicResource.provider(context);
         mMinVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
         mYOvershoot = rp.getDimension(R.dimen.swipe_up_y_overshoot);
+        setCanRelease(true);
     }
 
     public void onTargetPositionChanged() {
@@ -190,10 +192,12 @@
                     maybeOnEnd();
                 });
 
+        setCanRelease(false);
+        mAnimsStarted = true;
+
         mRectXAnim.start();
         mRectYAnim.start();
         mRectScaleAnim.start();
-        mAnimsStarted = true;
         for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
             animatorListener.onAnimationStart(null);
         }
@@ -245,6 +249,7 @@
     private void maybeOnEnd() {
         if (mAnimsStarted && isEnded()) {
             mAnimsStarted = false;
+            setCanRelease(true);
             for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
                 animatorListener.onAnimationEnd(null);
             }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index ebc9f96..7090393 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -121,8 +121,11 @@
                 addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows);
             }
 
-            View qsb = launcher.findViewById(R.id.search_container_all_apps);
-            addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows);
+            if (launcher.getAppsView().getSearchUiManager()
+                    .isQsbVisible(NORMAL.getVisibleElements(launcher))) {
+                addStaggeredAnimationForView(launcher.getAppsView().getSearchView(),
+                        grid.inv.numRows + 2, totalRows);
+            }
         }
 
         if (animateOverviewScrim) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SurfaceTransactionApplier.java
new file mode 100644
index 0000000..0a3e3ec
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SurfaceTransactionApplier.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import static com.android.systemui.shared.system.TransactionCompat.deferTransactionUntil;
+import static com.android.systemui.shared.system.TransactionCompat.setEarlyWakeup;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Message;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.View;
+
+import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+import com.android.systemui.shared.system.ViewRootImplCompat;
+
+import java.util.function.Consumer;
+
+
+/**
+ * Helper class to apply surface transactions in sync with RenderThread similar to
+ *   android.view.SyncRtSurfaceTransactionApplier
+ * with some Launcher specific utility methods
+ */
+@TargetApi(Build.VERSION_CODES.R)
+public class SurfaceTransactionApplier extends ReleaseCheck {
+
+    private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
+
+    private final SurfaceControl mBarrierSurfaceControl;
+    private final ViewRootImplCompat mTargetViewRootImpl;
+    private final Handler mApplyHandler;
+
+    private int mLastSequenceNumber = 0;
+
+    /**
+     * @param targetView The view in the surface that acts as synchronization anchor.
+     */
+    public SurfaceTransactionApplier(View targetView) {
+        mTargetViewRootImpl = new ViewRootImplCompat(targetView);
+        mBarrierSurfaceControl = mTargetViewRootImpl.getRenderSurfaceControl();
+        mApplyHandler = new Handler(this::onApplyMessage);
+    }
+
+    protected boolean onApplyMessage(Message msg) {
+        if (msg.what == MSG_UPDATE_SEQUENCE_NUMBER) {
+            setCanRelease(msg.arg1 == mLastSequenceNumber);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Schedules applying surface parameters on the next frame.
+     *
+     * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
+     *               this method to avoid synchronization issues.
+     */
+    public void scheduleApply(final SurfaceParams... params) {
+        View view = mTargetViewRootImpl.getView();
+        if (view == null) {
+            return;
+        }
+
+        mLastSequenceNumber++;
+        final int toApplySeqNo = mLastSequenceNumber;
+        setCanRelease(false);
+        mTargetViewRootImpl.registerRtFrameCallback(frame -> {
+            if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) {
+                Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
+                        .sendToTarget();
+                return;
+            }
+            Transaction t = new Transaction();
+            for (int i = params.length - 1; i >= 0; i--) {
+                SurfaceParams surfaceParams = params[i];
+                if (surfaceParams.surface.isValid()) {
+                    deferTransactionUntil(t, surfaceParams.surface, mBarrierSurfaceControl, frame);
+                    surfaceParams.applyTo(t);
+                }
+            }
+            setEarlyWakeup(t);
+            t.apply();
+            Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
+                    .sendToTarget();
+        });
+
+        // Make sure a frame gets scheduled.
+        view.invalidate();
+    }
+
+    /**
+     * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
+     * attached if necessary.
+     */
+    public static void create(
+            final View targetView, final Consumer<SurfaceTransactionApplier> callback) {
+        if (targetView == null) {
+            // No target view, no applier
+            callback.accept(null);
+        } else if (new ViewRootImplCompat(targetView).isValid()) {
+            // Already attached, we're good to go
+            callback.accept(new SurfaceTransactionApplier(targetView));
+        } else {
+            // Haven't been attached before we can get the view root
+            targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+                @Override
+                public void onViewAttachedToWindow(View v) {
+                    targetView.removeOnAttachStateChangeListener(this);
+                    callback.accept(new SurfaceTransactionApplier(targetView));
+                }
+
+                @Override
+                public void onViewDetachedFromWindow(View v) {
+                    // Do nothing
+                }
+            });
+        }
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
index 9bb508e..7a62e83 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
@@ -57,7 +57,7 @@
     private float mTargetAlpha;
     private float mCornerRadius;
     private RemoteAnimationTargets mTargetSet;
-    private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
+    private SurfaceTransactionApplier mSyncTransactionApplier;
 
     private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
     private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
@@ -112,7 +112,7 @@
      * are computed based on these TransformParams.
      */
     public TransformParams setSyncTransactionApplier(
-            SyncRtSurfaceTransactionApplierCompat applier) {
+            SurfaceTransactionApplier applier) {
         mSyncTransactionApplier = applier;
         return this;
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
index 83287c4..08c3dc9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
@@ -21,6 +21,7 @@
 import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
@@ -33,6 +34,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
 
@@ -129,6 +131,12 @@
         updateHiddenFlags(HIDDEN_UNSUPPORTED_NAVIGATION, !removeShelfFromOverview(getContext()));
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
+    }
+
     public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) {
         if (enable) {
             mHiddenFlags |= visibilityFlags;
@@ -152,10 +160,13 @@
         return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
     }
 
-    /** Updates vertical margins for different navigation mode. */
-    public void updateVerticalMarginForNavModeChange(Mode mode) {
-        int bottomMargin = 0;
-        if (mode == Mode.THREE_BUTTONS) {
+    /** Updates vertical margins for different navigation mode or configuration changes. */
+    public void updateVerticalMargin(Mode mode) {
+        int bottomMargin;
+        int orientation = getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            bottomMargin = 0;
+        } else if (mode == Mode.THREE_BUTTONS) {
             bottomMargin = getResources()
                     .getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_three_button);
         } else {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index a506b7e..64d90cf 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -127,6 +127,7 @@
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.util.SplitScreenBounds;
+import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.TransformParams;
 import com.android.systemui.plugins.ResourceProvider;
 import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
@@ -135,7 +136,6 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.LauncherEventUtil;
 import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 
 import java.util.ArrayList;
@@ -211,7 +211,7 @@
     protected final BaseActivityInterface mSizeStrategy;
     protected RecentsAnimationController mRecentsAnimationController;
     protected RecentsAnimationTargets mRecentsAnimationTargets;
-    protected SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
+    protected SurfaceTransactionApplier mSyncTransactionApplier;
     protected int mTaskWidth;
     protected int mTaskHeight;
     protected boolean mEnableDrawingLiveTile = false;
@@ -492,6 +492,7 @@
 
     public void init(OverviewActionsView actionsView) {
         mActionsView = actionsView;
+        mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
     }
 
     @Override
@@ -501,7 +502,7 @@
         mModel.getThumbnailCache().getHighResLoadingState().addCallback(this);
         mActivity.addMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
-        mSyncTransactionApplier = new SyncRtSurfaceTransactionApplierCompat(this);
+        mSyncTransactionApplier = new SurfaceTransactionApplier(this);
         RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
         mIdp.addOnChangeListener(this);
         mIPinnedStackAnimationListener.setActivity(mActivity);
@@ -1039,6 +1040,11 @@
     }
 
     private void animateRecentsRotationInPlace(int newRotation) {
+        if (mOrientationState.canLauncherRotate()) {
+            // Update the rotation but let system take care of the rotation animation
+            setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
+            return;
+        }
         AnimatorSet pa = setRecentsChangedOrientation(true);
         pa.addListener(AnimationSuccessListener.forRunnable(() -> {
             setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
@@ -1621,8 +1627,10 @@
                     : View.LAYOUT_DIRECTION_RTL);
             mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
             mActivity.getDragLayer().recreateControllers();
+            boolean isInLandscape = touchRotation != 0
+                    || mOrientationState.getLauncherRotation() != ROTATION_0;
             mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
-                    touchRotation != 0 || mOrientationState.getLauncherRotation() != ROTATION_0);
+                    !mOrientationState.canLauncherRotate() && isInLandscape);
             resetPaddingFromTaskSize();
             requestLayout();
         }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 5d80e6a..429ccf5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -30,6 +30,7 @@
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
 
 import android.animation.Animator;
@@ -222,8 +223,10 @@
         setOutlineProvider(mOutlineProvider);
     }
 
-    /* Builds proto for logging */
-    protected LauncherAtom.ItemInfo buildProto() {
+    /**
+     * Builds proto for logging
+     */
+    public LauncherAtom.ItemInfo buildProto() {
         ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key);
         LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
         itemBuilder.setIsWork(componentKey.user != Process.myUserHandle());
@@ -424,6 +427,7 @@
     private boolean showTaskMenu(int action) {
         getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
         mMenuView = TaskMenuView.showForTask(this);
+        mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, buildProto());
         UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE,
                 LauncherLogProto.ItemType.TASK_ICON);
         if (mMenuView != null) {
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 74197be..459d65f 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -16,7 +16,7 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@color/gesture_tutorial_background_color">
+    android:background="?android:attr/colorBackground">
 
     <View
         android:id="@+id/gesture_tutorial_ripple_view"
@@ -49,6 +49,7 @@
         android:background="@android:color/transparent"
         android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_titles_container"
         android:contentDescription="@string/gesture_tutorial_close_button_content_description"
+        android:tint="?android:attr/textColorPrimary"
         android:src="@drawable/gesture_tutorial_close_button"/>
 
     <LinearLayout
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 6d81b8e..77d9904 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -32,8 +32,6 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"የመተግበሪያ አስተያየቶች"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"ሁሉም መተግበሪያዎች"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"የእርስዎ የሚገመቱ መተግበሪያዎች"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"በብዛት ስራ ላይ የዋሉ መተግበሪያዎችዎን በቀላሉ ይድረሱ"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel እርስዎ ቀጥለው የሚፈልጓቸውን መተግበሪያዎች ይገምታል፣ በዚያው በመነሻ ገጽዎ ላይ። ለማዋቀር መታ ያድርጉ።"</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"በመነሻ ገጽዎ ታችኛው ረድፍ ላይ የመተግበሪያ አስተያየት ጥቆማዎችን ያግኙ"</string>
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"በጣም ስራ ላይ የዋሉ መተግበሪያዎችዎን በቀላሉ ከመነሻ ገጹ ሆነው ይድረሱባቸው። የአስተያየት ጥቆማዎች በእርስዎ ዕለት ተዕለት ተግባራት ላይ በመመስረት ይቀየራሉ። በታችኛው ረድፍ ላይ ያሉ መተግበሪያዎች ወደ መነሻ ገጽዎ ይወሰዳሉ።"</string>
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"በጣም ስራ ላይ የዋሉ መተግበሪያዎችዎን በቀላሉ ከመነሻ ገጹ ሆነው ይድረሱባቸው። የአስተያየት ጥቆማዎች በእርስዎ ዕለት ተዕለት ተግባራት ላይ በመመስረት ይቀየራሉ። በታችኛው ረድፍ ላይ ያሉ መተግበሪያዎች ወደ አዲስ አቃፊ ይወሰዳሉ።"</string>
@@ -43,6 +41,8 @@
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"በብዛት ስራ ላይ የዋሉ መተግበሪያዎች እዚህ ይመጣሉ፣ እና በዕለት ተዕለት ተግባራት ላይ በመመስረት ይቀየራሉ"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"የመተግበሪያ ጥቆማዎችን ለማግኘት መተግበሪያዎችን ከታችኛው ረድፍ ይጎትቱ"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"የመተግበሪያ አስተያየት ጥቆማዎች ወደ ባዶ ቦታ ታክለዋል"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"የተገመተው መተግበሪያ፦ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"አጋራ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ቅጽበታዊ ገጽ እይታ"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 6f07cec..a309331 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -32,8 +32,6 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"App-Vorschläge"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"Alle Apps"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"App-Vorschläge für dich"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Einfacher Zugriff auf deine meistverwendeten Apps"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel prognostiziert, welche Apps du als nächste brauchst, und setzt diese direkt auf den Startbildschirm. Zum Einrichten tippen."</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Lass dir in der unteren Reihe auf deinem Startbildschirm Vorschläge für Apps anzeigen"</string>
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Schneller Zugriff auf deine meistverwendeten Apps direkt über den Startbildschirm. Die Vorschläge richten sich nach deiner gewöhnlichen Nutzung. Apps in der unteren Reihe werden nach oben auf den Startbildschirm verschoben."</string>
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Schneller Zugriff auf deine meistverwendeten Apps direkt über den Startbildschirm. Die Vorschläge richten sich nach deiner gewöhnlichen Nutzung. Apps in der unteren Reihe werden in einen neuen Ordner verschoben."</string>
@@ -43,6 +41,8 @@
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Hier erscheinen die meistverwendeten Apps. Die Angaben können sich je nach deiner gewöhnlichen Nutzung ändern"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Ziehe Apps aus der unteren Reihe heraus, um Vorschläge für Apps zu bekommen"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"App-Vorschläge in freiem Bereich hinzugefügt"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"App-Vorhersage: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"Teilen"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 688426c..7fca75e 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -32,8 +32,6 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"Προτεινόμενες εφαρμογές"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"Όλες οι εφαρμογές"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Προβλέψεις εφαρμογών"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Εύκολη πρόσβαση στις εφαρμογές που χρησιμοποιείτε περισσότερο"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Το Pixel προβλέπει τις εφαρμογές που θα χρειαστείτε μετά, απευθείας στην αρχική οθόνη. Πατήστε για ρύθμιση."</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Δείτε τις προτεινόμενες εφαρμογές στην κάτω σειρά της αρχικής οθόνης"</string>
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Αποκτήστε εύκολα πρόσβαση στις εφαρμογές που χρησιμοποιείτε περισσότερο απευθείας από την αρχική οθόνη. Οι προτάσεις θα αλλάζουν με βάση τις ρουτίνες σας. Οι εφαρμογές στην κάτω σειρά θα μετακινηθούν προς τα επάνω στην αρχική οθόνη."</string>
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Αποκτήστε εύκολα πρόσβαση στις εφαρμογές που χρησιμοποιείτε περισσότερο, απευθείας από την αρχική οθόνη. Οι προτάσεις θα αλλάζουν με βάση τις ρουτίνες σας. Οι εφαρμογές στην κάτω σειρά θα μεταφερθούν σε νέο φάκελο."</string>
@@ -43,6 +41,8 @@
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Οι εφαρμογές που χρησιμοποιείτε περισσότερο εμφανίζονται εδώ και αλλάζουν με βάση τις ρουτίνες"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Σύρετε εφαρμογές μακριά από την κάτω σειρά, για να δείτε τις προτεινόμενες εφαρμογές"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Οι προτεινόμενες εφαρμογές προστέθηκαν στον κενό χώρο"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Εφαρμογή από πρόβλεψη: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"Κοινοποίηση"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Στιγμιότυπο οθόνης"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 70753e2..c166708 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -32,8 +32,6 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‎‎‎App suggestions‎‏‎‎‏‎"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎All apps‎‏‎‎‏‎"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎Your predicted apps‎‏‎‎‏‎"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‎Easily access your most-used apps‎‏‎‎‏‎"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‎‎‏‎Pixel predicts apps youll need next, right on your Home screen. Tap to set up.‎‏‎‎‏‎"</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎Get app suggestions on the bottom row of your Home screen‎‏‎‎‏‎"</string>
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‎‎Easily access your most-used apps right on the Home screen. Suggestions will change based on your routines. Apps on the bottom row will move up to your Home screen.‎‏‎‎‏‎"</string>
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎Easily access your most-used apps, right on the Home screen. Suggestions will change based on your routines. Apps on the bottom row will move to a new folder.‎‏‎‎‏‎"</string>
@@ -43,6 +41,8 @@
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎Most-used apps appear here, and change based on routines‎‏‎‎‏‎"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎Drag apps off the bottom row to get app suggestions‎‏‎‎‏‎"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‎‎App suggestions added to empty space‎‏‎‎‏‎"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‎‏‏‎Predicted app: ‎‏‎‎‏‏‎<xliff:g id="TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="action_share" msgid="2648470652637092375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎Share‎‏‎‎‏‎"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‎Screenshot‎‏‎‎‏‎"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 0ada754..7fa7710 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -32,10 +32,8 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"Sugerencias de aplicaciones"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"Todas las apps"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Predicción de tus apps"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Accede fácilmente a las apps que más usas"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel predice las apps que usarás la próxima vez en la pantalla principal. Presiona para configurar esta opción."</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Obtén sugerencias de aplicaciones en la fila inferior de la pantalla principal"</string>
-    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Accede fácilmente en la pantalla principal a las apps que más usas. Las sugerencias cambiarán según tus rutinas. Las apps de la fila inferior se moverán hacia arriba en la pantalla principal."</string>
+    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Accede fácilmente en la pantalla principal a las apps que más usas. Las sugerencias cambiarán según tus rutinas. Las apps de la fila inferior se desplazarán hacia arriba en la pantalla principal."</string>
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Accede fácilmente a las apps que más usas en la pantalla principal. Las sugerencias cambiarán según tus rutinas. Las apps de la fila inferior se moverán a una nueva carpeta."</string>
     <string name="hotseat_edu_accept" msgid="1611544083278999837">"Obtén sugerencias de aplicaciones"</string>
     <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"No, gracias"</string>
@@ -43,6 +41,8 @@
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Las apps que más se usan se muestran aquí y cambian según las rutinas"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Arrastra apps fuera de la fila inferior para obtener sugerencias"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Se agregaron sugerencias de aplicaciones a un espacio vacío"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predicción de app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"Compartir"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index aa31197..9a3972a 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -32,8 +32,6 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"Applications suggérées"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"Toutes les applications"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Applications prévues pour vous"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Accédez facilement à vos applications les plus utilisées"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel prédit les applications dont vous pourriez avoir besoin par la suite et les affiche sur votre écran d\'accueil. Appuyez ici pour configurer ce paramètre."</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Retrouvez vos applications favorites au bas de votre écran d\'accueil"</string>
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Les suggestions d\'applications permettent d\'afficher vos applications favorites au bas de votre écran d\'accueil. Elles s\'adaptent à vos habitudes d\'utilisation. Les icônes auparavant affichées au bas de l\'écran seront déplacées vers le haut."</string>
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Les suggestions d\'applications permettent d\'afficher vos applications favorites au bas de votre écran d\'accueil. Elles s\'adaptent à vos habitudes d\'utilisation. Les icônes auparavant affichées au bas de l\'écran seront placées dans un nouveau dossier."</string>
@@ -43,6 +41,8 @@
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Les applications dont vous vous servez le plus s\'affichent ici (ces suggestions peuvent varier en fonction de vos habitudes d\'utilisation)"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Faites glisser des applications hors de la rangée du bas pour obtenir des suggestions d\'applications"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Des suggestions d\'applications ont été ajoutées à un emplacement vide"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Application prédite : <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"Partager"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index ecc195f..4c68663 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -32,8 +32,6 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"앱 제안"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"모든 앱"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"추천 앱"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"가장 많이 사용한 앱에 간편하게 액세스"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel에서 다음번에 사용할 앱을 예상하여 홈 화면에 바로 표시해 줍니다. 설정하려면 탭하세요."</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"홈 화면 하단 행에서 앱 제안을 확인하세요."</string>
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"홈 화면에서 가장 많이 사용한 앱에 바로 액세스할 수 있습니다. 제안은 루틴에 따라 달라집니다. 하단 행의 앱이 홈 화면으로 이동합니다."</string>
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"홈 화면에서 가장 많이 사용한 앱에 바로 액세스할 수 있습니다. 제안은 루틴에 따라 달라집니다. 하단 행의 앱이 새로운 폴더로 이동합니다."</string>
@@ -43,6 +41,8 @@
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"가장 많이 사용한 앱이 여기에 표시되며 루틴에 따라 달라짐"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"하단 행에서 앱을 드래그하여 앱 제안 받기"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"빈 공간에 앱 제안 추가됨"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"예상 앱: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"공유"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"스크린샷"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 66402f2..388fee2 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -32,9 +32,7 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"Санал болгож буй аппууд"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"Бүх апп"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Таны таамагласан аппууд"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Хамгийн их ашигладаг аппууддаа хялбархан хандаарай"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel утас танд дараагийн удаа хэрэг болох аппуудыг таамаглаж, таны Үндсэн нүүрэнд харуулна. Тохируулахын тулд товшино уу."</string>
-    <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Үндсэн нүүрнийхээ доод мөр дээр санал болгож буй аппуудыг аваарай"</string>
+    <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Үндсэн нүүрнийхээ доод мөрөнд санал болгож буй аппуудыг аваарай"</string>
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Хамгийн их ашигладаг аппууддаа Үндсэн нүүрээс хялбархан хандаарай. Санал болгож буй аппуудыг таны хэвшлээс хамаарч өөрчилнө. Доод мөр дэх аппуудыг таны Үндсэн нүүр лүү дээш зөөнө."</string>
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Хамгийн их ашигладаг аппууддаа Үндсэн нүүрээс хялбархан хандаарай. Санал болгож буй аппуудыг таны хэвшлээс хамаарч өөрчилнө. Доод мөр дэх аппуудыг шинэ фолдер луу зөөнө."</string>
     <string name="hotseat_edu_accept" msgid="1611544083278999837">"Санал болгож буй аппуудыг авах"</string>
@@ -43,6 +41,8 @@
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Хамгийн их ашигладаг аппуудыг энд харуулах бөгөөд хэвшлээс хамаарч өөрчилдөг"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Санал болгож буй аппуудыг авахын тулд доод мөрөөс аппуудыг чирж гаргаарай"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Санал болгож буй аппуудыг хоосон зайд нэмсэн"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Таамаглаж буй апп: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"Хуваалцах"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Дэлгэцийн агшин дарах"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index d1dacf2..435259e 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -32,17 +32,17 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"Sugestões de apps"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"Todos os apps"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Suas predições de apps"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Acesse os apps mais usados de forma simples"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"O Pixel prevê de quais apps você precisará, diretamente na tela inicial. Toque para configurar."</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Receba sugestões de apps na linha inferior da tela inicial"</string>
-    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Acesse os apps mais usados na tela inicial de forma simples. As sugestões mudarão de acordo com sua rotina. Os apps na linha inferior subirão para a tela inicial."</string>
-    <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Acesse os apps mais usados na tela inicial de forma simples. As sugestões mudarão de acordo com sua rotina. Os apps na linha inferior serão movidos para uma nova pasta."</string>
+    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Acesse diretamente na tela inicial os apps que você mais usa. As sugestões mudarão de acordo com sua rotina. Os apps na linha inferior serão movidos para a tela inicial."</string>
+    <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Acesse diretamente na tela inicial os apps que você mais usa. As sugestões mudarão de acordo com sua rotina. Os apps na linha inferior serão movidos para uma nova pasta."</string>
     <string name="hotseat_edu_accept" msgid="1611544083278999837">"Receber sugestões de apps"</string>
     <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Não"</string>
     <string name="hotseat_turn_off" msgid="7808360330229368470">"Configurações"</string>
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Os apps mais usados aparecem aqui e mudam de acordo com sua rotina"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Arraste apps da linha inferior para receber sugestões de apps"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Sugestões de apps adicionadas a um espaço vazio"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"App previsto: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"Compartilhar"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Capturar tela"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 285d4d2..73b99f4 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -32,17 +32,17 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"Návrhy aplikácií"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"Všetky aplikácie"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Vaše predpovedané aplikácie"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Získajte jednoduchý prístup k najpoužívanejším aplikáciám"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel predpovedá aplikácie, ktoré budete potrebovať, priamo na ploche. Klepnutím prejdete na nastavenie."</string>
-    <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Získajte návrhy aplikácií v spodnom riadku plochy"</string>
-    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Získajte jednoduchý prístup k najpoužívanejším aplikáciám priamo na ploche. Návrhy sa budú meniť podľa vašich postupov. Aplikácie v spodnom riadku sa presunú nahor na plochu."</string>
-    <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Získajte jednoduchý prístup k najpoužívanejším aplikáciám priamo na ploche. Návrhy sa budú meniť podľa vašich postupov. Aplikácie v spodnom riadku sa presunú do nového priečinka."</string>
-    <string name="hotseat_edu_accept" msgid="1611544083278999837">"Získavať návrhy aplikácií"</string>
+    <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Nechajte si v spodnom riadku na ploche zobrazovať návrhy aplikácií"</string>
+    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Získajte jednoduchý prístup k najpoužívanejším aplikáciám priamo na ploche. Návrhy sa budú meniť podľa vašich zvyklostí. Aplikácie v spodnom riadku sa presunú nahor na plochu."</string>
+    <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Získajte jednoduchý prístup k najpoužívanejším aplikáciám priamo na ploche. Návrhy sa budú meniť podľa vašich zvyklostí. Aplikácie v spodnom riadku sa presunú do nového priečinka."</string>
+    <string name="hotseat_edu_accept" msgid="1611544083278999837">"Zobrazovať návrhy aplikácií"</string>
     <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Nie, ďakujem"</string>
     <string name="hotseat_turn_off" msgid="7808360330229368470">"Nastavenia"</string>
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Tu sú zobrazené najpoužívanejšie aplikácie a menia sa podľa postupov"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Ak chcete získať návrhy aplikácií, presuňte aplikácie zo spodného riadka"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Návrhy aplikácie boli pridané na prázdne miesto"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predpovedaná aplikácia: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"Zdieľať"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snímka obrazovky"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 54c8c14..cf9fa5e 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -32,8 +32,6 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"Predlagane aplikacije"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"Vse aplikacije"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Predvidene aplikacije"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Preprost dostop do najpogosteje uporabljenih aplikacij"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel že na začetnem zaslonu predvidi, katere aplikacije boste potrebovali v nadaljevanju. Dotaknite se, če želite nastaviti."</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Oglejte si predlagane aplikacije v spodnji vrstici začetnega zaslona"</string>
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Preprosto dostopajte do najpogosteje uporabljenih aplikacij kar na začetnem zaslonu. Predlogi se spreminjajo na podlagi dejanj, ki jih pogosto izvajate. Aplikacije se iz spodnje vrstice premaknejo na začetni zaslon."</string>
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Preprosto dostopajte do najpogosteje uporabljenih aplikacij kar na začetnem zaslonu. Predlogi se spreminjajo na podlagi dejanj, ki jih pogosto izvajate. Aplikacije se iz spodnje vrstice premaknejo v novo mapo."</string>
@@ -43,6 +41,8 @@
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Tukaj so navedene najpogosteje uporabljene aplikacije in spremembe na podlagi rutin"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Če si želite ogledati predlagane aplikacije, povlecite aplikacije iz spodnje vrstice"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Predlagane aplikacije so bile dodane v prazni prostor"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predvidena aplikacija: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"Deli"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Posnetek zaslona"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 1e1df6a..1986370 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -32,8 +32,6 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"Mapendekezo ya programu"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"Programu zote"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Programu zako zinazopendekezwa"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Fikia kwa urahisi programu unazotumia zaidi"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel hutabiri programu zinazofuata utakazohitaji, moja kwa moja kwenye Skrini yako ya kwanza. Gusa ili uweke mipangilio."</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Pata mapendekezo ya programu kwenye safu mlalo ya chini ya Skrini yako ya kwanza"</string>
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Fikia kwa urahisi programu unazotumia sana moja kwa moja kwenye Skrini ya kwanza. Mapendekezo yatabadilika kulingana na ratiba zako. Programu zilizo kwenye safu mlalo ya chini zitahamishiwa kwenye Skrini yako ya kwanza."</string>
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Fikia kwa urahisi programu unazotumia zaidi, moja kwa moja kwenye Skrini ya kwanza. Mapendekezo yatabadilika kulingana na ratiba zako. Programu zilizo kwenye safu mlalo ya chini zitahamishiwa kwenye folda mpya."</string>
@@ -43,6 +41,8 @@
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Programu zinazotumiwa zaidi huonekana hapa na hubadilika kulingana na ratiba"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Buruta programu kutoka kwenye safu mlalo ya chini ili upate mapendekezo ya programu"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Mapendekezo ya programu yamewekwa kwenye nafasi isiyo na kitu"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Programu iliyotabiriwa: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"Shiriki"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Picha ya skrini"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 0c9c830..28bea34 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -32,17 +32,17 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"คำแนะนำเกี่ยวกับแอป"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"แอปทั้งหมด"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"แอปที่คาดการณ์ไว้"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"เข้าถึงแอปที่ใช้มากที่สุดได้โดยง่าย"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel จะคาดคะเนว่าคุณต้องการใช้แอปใดต่อไป และจะแสดงแอปนั้นในหน้าจอหลัก แตะเพื่อตั้งค่า"</string>
-    <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"ดูคำแนะนำเกี่ยวกับแอปที่แถวล่างของหน้าจอหลัก"</string>
-    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"เข้าถึงแอปที่ใช้มากที่สุดได้โดยง่ายในหน้าจอหลัก คำแนะนำจะเปลี่ยนไปตามการใช้งานประจำ แอปในแถวล่างจะย้ายขึ้นมาอยู่ในหน้าจอหลัก"</string>
-    <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"เข้าถึงแอปที่ใช้มากที่สุดได้โดยง่ายในหน้าจอหลัก คำแนะนำจะเปลี่ยนไปตามการใช้งานประจำ แอปในแถวล่างจะย้ายไปอยู่ในโฟลเดอร์ใหม่"</string>
-    <string name="hotseat_edu_accept" msgid="1611544083278999837">"ดูคำแนะนำเกี่ยวกับแอป"</string>
+    <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"รับคำแนะนำเกี่ยวกับแอปที่แถวล่างของหน้าจอหลัก"</string>
+    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"เข้าถึงแอปที่คุณใช้มากที่สุดได้อย่างง่ายดายจากหน้าจอหลัก คำแนะนำจะเปลี่ยนไปตามแอปที่ใช้งานเป็นประจำ แอปในแถวล่างจะย้ายขึ้นมาอยู่ในหน้าจอหลัก"</string>
+    <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"เข้าถึงแอปที่คุณใช้มากที่สุดได้อย่างง่ายดายจากหน้าจอหลัก คำแนะนำจะเปลี่ยนไปตามแอปที่ใช้งานเป็นประจำ แอปในแถวล่างจะย้ายไปอยู่ในโฟลเดอร์ใหม่"</string>
+    <string name="hotseat_edu_accept" msgid="1611544083278999837">"รับคำแนะนำเกี่ยวกับแอป"</string>
     <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"ไม่เป็นไร"</string>
     <string name="hotseat_turn_off" msgid="7808360330229368470">"การตั้งค่า"</string>
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"แอปที่ใช้มากที่สุดจะปรากฎที่นี่และจะเปลี่ยนไปตามการใช้งานประจำ"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"ลากแอปออกจากแถวล่างเพื่อดูคำแนะนำเกี่ยวกับแอป"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"มีการเพิ่มคำแนะนำเกี่ยวกับแอปในพื้นที่ว่าง"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"แอปที่คาดว่าจะใช้: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"แชร์"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ภาพหน้าจอ"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 7694212..0e3da7f 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -32,17 +32,17 @@
     <string name="title_app_suggestions" msgid="4185902664111965088">"ایپس کی تجاویز"</string>
     <string name="all_apps_label" msgid="8542784161730910663">"تمام ایپس"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"آپ کی پیشن گوئی کردہ ایپس"</string>
-    <string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"آسانی سے اپنی سب سے زیادہ مستعمل ایپس تک رسائی حاصل کریں"</string>
-    <string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"‏Pixel پیش گوئی کرتا ہے کہ آپ کو ہوم اسکرین پر ہی، آپ کے اگلے ایپس کی ضرورت ہوگی۔ سیٹ اپ کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"اپنی ہوم اسکرین کی نچلی قطار پر ایپ کی تجاویز حاصل کریں"</string>
-    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"ہوم اسکرین پر آسانی سے اپنی سب سے زیادہ مستعمل ایپس تک رسائی حاصل کریں۔ آپ کے روٹینز کی بنیاد پر تجاویز تبدیل ہوں گی۔ نچلی قطار میں موجود ایپس آپ کی ہوم اسکرین کے اوپر منتقل ہونگیں۔"</string>
-    <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"ہوم اسکرین پر، آسانی سے اپنی سب سے زیادہ مستعمل ایپس تک رسائی حاصل کریں۔ آپ کے روٹینز کی بنیاد پر تجاویز تبدیل ہوں گی۔ نچلی قطار میں موجود ایپس نئے فولڈر میں منتقل ہونگیں۔"</string>
+    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"ہوم اسکرین پر آسانی سے اپنی سب سے زیادہ مستعمل ایپس تک رسائی حاصل کریں۔ آپ کی روٹینز کی بنیاد پر تجاویز تبدیل ہوں گی۔ نچلی قطار میں موجود ایپس آپ کی ہوم اسکرین کے اوپر منتقل ہوں گی۔"</string>
+    <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"ہوم اسکرین پر، آسانی سے اپنی سب سے زیادہ مستعمل ایپس تک رسائی حاصل کریں۔ آپ کی روٹینز کی بنیاد پر تجاویز تبدیل ہوں گی۔ نچلی قطار میں موجود ایپس نئے فولڈر میں منتقل ہوں گی۔"</string>
     <string name="hotseat_edu_accept" msgid="1611544083278999837">"ایپس کی تجاویز حاصل کریں"</string>
     <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"نہیں شکریہ"</string>
     <string name="hotseat_turn_off" msgid="7808360330229368470">"ترتیبات"</string>
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"سب سے زیادہ مستعمل ایپس یہاں ظاہر ہوتی ہیں، اور روٹینز کی بنیاد پر تبدیل ہوتی ہیں"</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"ایپس کی تجاویز حاصل کرنے کیلئے ایپس کو نچلی قطار سے نیچے گھسیٹیں"</string>
     <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"ایپس کی تجاویز کو خالی اسپیس میں شامل کر دیا گیا"</string>
+    <!-- no translation found for hotsaet_tip_prediction_enabled (4589474727906410667) -->
+    <skip />
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"پیشن گوئی کردہ ایپ: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="action_share" msgid="2648470652637092375">"اشتراک کریں"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"اسکرین شاٹ"</string>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 3583676..40da136 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -14,5 +14,6 @@
      limitations under the License.
 -->
 <resources>
+    <color name="back_arrow_color_light">#FFFFFFFF</color>
     <color name="back_arrow_color_dark">#99000000</color>
 </resources>
\ No newline at end of file
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index be1d47b..a27c127 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -65,8 +65,10 @@
 
     <!-- Hotseat educational strings for users who don't qualify for migration -->
     <string name="hotseat_edu_title_migrate">Get app suggestions on the bottom row of your Home screen</string>
+    <string name="hotseat_edu_title_migrate_landscape">Get app suggestions on favorites row of your Home screen</string>
 
     <string name="hotseat_edu_message_migrate">Easily access your most-used apps right on the Home screen. Suggestions will change based on your routines. Apps on the bottom row will move up to your Home screen. </string>
+    <string name="hotseat_edu_message_migrate_landscape">Easily access your most-used apps right on the Home screen. Suggestions will change based on your routines. Apps in favorites row will move to your Home screen. </string>
     <string name="hotseat_edu_message_migrate_alt">Easily access your most-used apps, right on the Home screen. Suggestions will change based on your routines. Apps on the bottom row will move to a new folder.</string>
 
     <!-- Button text to opt in for fully predicted hotseat -->
@@ -83,11 +85,12 @@
     <string name="hotseat_tip_no_empty_slots">Drag apps off the bottom row to get app suggestions</string>
     <!-- tip shown if user declines migration and has some open spots for prediction -->
     <string name="hotseat_tip_gaps_filled">App suggestions added to empty space</string>
+    <!-- tip shown when user migrates and predictions are enabled in hotseat -->
+    <string name="hotsaet_tip_prediction_enabled">App suggestions Enabled</string>
 
     <!-- content description for hotseat items -->
     <string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
 
-
     <!-- Title shown during interactive part of Back gesture tutorial for right edge. [CHAR LIMIT=30] -->
     <string name="back_gesture_tutorial_playground_title_swipe_inward_right_edge" translatable="false">Try the back gesture</string>
     <!-- Subtitle shown during interactive parts of Back gesture tutorial for right edge. [CHAR LIMIT=60] -->
@@ -111,7 +114,6 @@
     <!-- Subtitle shown on the confirmation screen after successful gesture. [CHAR LIMIT=60] -->
     <string name="back_gesture_tutorial_confirm_subtitle" translatable="false">To change the sensitivity of the back gesture, go to Settings</string>
 
-
     <!-- Title shown during interactive part of Home gesture tutorial. [CHAR LIMIT=30] -->
     <string name="home_gesture_tutorial_playground_title" translatable="false">Tutorial: Go Home</string>
     <!-- Subtitle shown during interactive parts of Home gesture tutorial. [CHAR LIMIT=60] -->
@@ -123,6 +125,28 @@
     <!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
     <string name="home_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up</string>
 
+    <!-- Title shown during interactive part of Overview gesture tutorial. [CHAR LIMIT=30] -->
+    <string name="overview_gesture_tutorial_playground_title" translatable="false">Tutorial: Switch Apps</string>
+    <!-- Subtitle shown during interactive parts of Overview gesture tutorial. [CHAR LIMIT=60] -->
+    <string name="overview_gesture_tutorial_playground_subtitle" translatable="false">Swipe up from the bottom of the screen and hold</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" translatable="false">Make sure you swipe from the bottom edge of the screen</string>
+    <!-- Feedback shown during interactive parts of Overview gesture tutorial when the Home gesture is detected. [CHAR LIMIT=100] -->
+    <string name="overview_gesture_feedback_home_detected" translatable="false">Try holding the window for longer before releasing</string>
+    <!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
+    <string name="overview_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up and pause</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>
+    <!-- Subtitle shown during interactive parts of Assistant gesture tutorial. [CHAR LIMIT=60] -->
+    <string name="assistant_gesture_tutorial_playground_subtitle" translatable="false">Try swiping diagonally from a bottom corner of the screen</string>
+    <!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture is started too far from the corner. [CHAR LIMIT=100] -->
+    <string name="assistant_gesture_feedback_swipe_too_far_from_corner" translatable="false">Make sure you swipe from a bottom corner of the screen</string>
+    <!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture doesn't go diagonally enough. [CHAR LIMIT=100] -->
+    <string name="assistant_gesture_feedback_swipe_not_diagonal" translatable="false">Make sure you swipe diagonally</string>
+    <!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture doesn't go far enough. [CHAR LIMIT=100] -->
+    <string name="assistant_gesture_feedback_swipe_not_long_enough" translatable="false">Try swiping further</string>
+
     <!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
     <string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
     <!-- Button text shown on a button on the confirm screen to leave the tutorial. [CHAR LIMIT=14] -->
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 90957e4..8d054b4 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -35,14 +35,14 @@
     <style name="TextAppearance.GestureTutorial.Title"
         parent="TextAppearance.GestureTutorial">
         <item name="android:gravity">center</item>
-        <item name="android:textColor">@color/gesture_tutorial_title_color</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:textSize">28sp</item>
     </style>
 
     <style name="TextAppearance.GestureTutorial.Subtitle"
         parent="TextAppearance.GestureTutorial">
         <item name="android:gravity">center</item>
-        <item name="android:textColor">@color/gesture_tutorial_subtitle_color</item>
+        <item name="android:textColor">?android:attr/textColorTertiary</item>
         <item name="android:letterSpacing">0.03</item>
         <item name="android:textSize">21sp</item>
     </style>
@@ -50,7 +50,7 @@
     <style name="TextAppearance.GestureTutorial.Feedback"
         parent="TextAppearance.GestureTutorial">
         <item name="android:gravity">center</item>
-        <item name="android:textColor">@color/gesture_tutorial_feedback_color</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:letterSpacing">0.03</item>
         <item name="android:textSize">21sp</item>
     </style>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 0968d8e..4874307 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -93,7 +93,7 @@
     public void onNavigationModeChanged(Mode newMode) {
         getDragLayer().recreateControllers();
         if (mActionsView != null && isOverviewActionsEnabled()) {
-            mActionsView.updateVerticalMarginForNavModeChange(newMode);
+            mActionsView.updateVerticalMargin(newMode);
         }
     }
 
@@ -175,7 +175,7 @@
             // Overview is above all other launcher elements, including qsb, so move it to the top.
             getOverviewPanel().bringToFront();
             mActionsView.bringToFront();
-            mActionsView.updateVerticalMarginForNavModeChange(SysUINavigationMode.getMode(this));
+            mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 25c07f1..fe7b946 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -82,6 +82,7 @@
 import com.android.quickstep.util.MultiValueUpdateListener;
 import com.android.quickstep.util.RemoteAnimationProvider;
 import com.android.quickstep.util.StaggeredWorkspaceAnim;
+import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.systemui.shared.system.ActivityCompat;
 import com.android.systemui.shared.system.ActivityOptionsCompat;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -89,7 +90,6 @@
 import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
@@ -455,9 +455,9 @@
 
         RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets,
                 wallpaperTargets, MODE_OPENING);
-        SyncRtSurfaceTransactionApplierCompat surfaceApplier =
-                new SyncRtSurfaceTransactionApplierCompat(floatingView);
-        openingTargets.addDependentTransactionApplier(surfaceApplier);
+        SurfaceTransactionApplier surfaceApplier =
+                new SurfaceTransactionApplier(floatingView);
+        openingTargets.addReleaseCheck(surfaceApplier);
 
         // Scale the app icon to take up the entire screen. This simplifies the math when
         // animating the app window position / scale.
@@ -712,8 +712,7 @@
      */
     private Animator getUnlockWindowAnimator(RemoteAnimationTargetCompat[] appTargets,
             RemoteAnimationTargetCompat[] wallpaperTargets) {
-        SyncRtSurfaceTransactionApplierCompat surfaceApplier =
-                new SyncRtSurfaceTransactionApplierCompat(mDragLayer);
+        SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
         ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1);
         unlockAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
         float cornerRadius = mDeviceProfile.isMultiWindowMode ? 0 :
@@ -741,8 +740,7 @@
      */
     private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets,
             RemoteAnimationTargetCompat[] wallpaperTargets) {
-        SyncRtSurfaceTransactionApplierCompat surfaceApplier =
-                new SyncRtSurfaceTransactionApplierCompat(mDragLayer);
+        SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
         Matrix matrix = new Matrix();
         Point tmpPos = new Point();
         ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index 2181aa8..f42b124 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -77,6 +77,7 @@
     private static final String EXTRA_ACTION = "action";
     private static final String EXTRA_MAX_NUM_ACTIONS_SHOWN = "max_num_actions_shown";
     private static final String EXTRA_PACKAGES = "packages";
+    private static final String EXTRA_SUCCESS = "success";
 
     public static final MainThreadInitializedObject<WellbeingModel> INSTANCE =
             new MainThreadInitializedObject<>(WellbeingModel::new);
@@ -221,6 +222,7 @@
             params.putInt(EXTRA_MAX_NUM_ACTIONS_SHOWN, 1);
             // Perform wellbeing call .
             remoteActionBundle = client.call(METHOD_GET_ACTIONS, null, params);
+            if (!remoteActionBundle.getBoolean(EXTRA_SUCCESS, true)) return false;
 
             synchronized (mModelLock) {
                 // Remove the entries for requested packages, and then update the fist with what we
@@ -281,9 +283,9 @@
                 // Remove all existing messages
                 mWorkerHandler.removeCallbacksAndMessages(null);
                 final String[] packageNames = mContext.getSystemService(LauncherApps.class)
-                            .getActivityList(null, Process.myUserHandle()).stream()
-                            .map(li -> li.getApplicationInfo().packageName).distinct()
-                            .toArray(String[]::new);
+                        .getActivityList(null, Process.myUserHandle()).stream()
+                        .map(li -> li.getApplicationInfo().packageName).distinct()
+                        .toArray(String[]::new);
                 if (!updateActions(packageNames)) {
                     scheduleRefreshRetry(msg);
                 }
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index fcffaed..ebe9e26 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -17,6 +17,7 @@
 package com.android.launcher3.statehandlers;
 
 import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
 
 import android.os.IBinder;
@@ -191,11 +192,12 @@
 
         float toDepth = toState.getDepth(mLauncher);
         if (Float.compare(mDepth, toDepth) != 0) {
-            animation.setFloat(this, DEPTH, toDepth, LINEAR);
+            animation.setFloat(this, DEPTH, toDepth, config.getInterpolator(ANIM_DEPTH, LINEAR));
         }
     }
 
     private void setDepth(float depth) {
+        depth = Utilities.boundToRange(depth, 0, 1);
         // Round out the depth to dedupe frequent, non-perceptable updates
         int depthI = (int) (depth * 256);
         float depthF = depthI / 256f;
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index a4861dc..ec720d5 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -34,6 +34,7 @@
     int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7;
     int TYPE_RESET_GESTURE = 1 << 8;
     int TYPE_OVERSCROLL = 1 << 9;
+    int TYPE_SYSUI_OVERLAY = 1 << 10;
 
     String[] NAMES = new String[] {
            "TYPE_NO_OP",                    // 0
@@ -46,6 +47,7 @@
             "TYPE_OVERVIEW_WITHOUT_FOCUS",  // 7
             "TYPE_RESET_GESTURE",           // 8
             "TYPE_OVERSCROLL",              // 9
+            "TYPE_SYSUI_OVERLAY"         // 10
     };
 
     InputConsumer NO_OP = () -> TYPE_NO_OP;
@@ -70,6 +72,11 @@
     }
 
     /**
+     * Handle and specific setup necessary based on the orientation of the device
+     */
+    default void notifyOrientationSetup() {}
+
+    /**
      * Returns the active input consumer is in the hierarchy of this input consumer.
      */
     default InputConsumer getActiveConsumerInHierarchy() {
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 4cf7aab..3375c53 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -36,8 +36,8 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.ResourceUtils;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.DefaultDisplay;
-import com.android.quickstep.util.RecentsOrientedState.SurfaceRotation;
 
 import java.io.PrintWriter;
 
@@ -67,6 +67,14 @@
     private boolean mEnableMultipleRegions;
     private Resources mResources;
     private OrientationRectF mLastRectTouched;
+    /**
+     * The rotation of the last touched nav bar. Derived from {@link #mLastRectTouched}, but has a
+     * longer lifetime than the rect. Note this is different than {@link #mQuickStepStartingRotation}
+     * as it always updates its value on every touch whereas mQuickstepStartingRotation only
+     * updates when device rotation matches touch rotation. Maybe this will be only one necessary
+     * after TODO(b/154580671) is in. TBD.
+     */
+    private int mLastRectRotation;
     private SysUINavigationMode.Mode mMode;
     private QuickStepContractInfo mContractInfo;
 
@@ -143,15 +151,18 @@
      * ALSO, you BETTER call this with {@param enableMultipleRegions} set to false once you're done.
      *
      * @param enableMultipleRegions Set to true to start tracking multiple nav bar regions
-     * @param info The current displayInfo
+     * @param info The current displayInfo which will be the start of the quickswitch gesture
      */
     void enableMultipleRegions(boolean enableMultipleRegions, DefaultDisplay.Info info) {
         mEnableMultipleRegions = enableMultipleRegions &&
                 mMode != SysUINavigationMode.Mode.TWO_BUTTONS;
-        if (!enableMultipleRegions) {
+        if (mEnableMultipleRegions) {
+            mQuickStepStartingRotation = info.rotation;
+        } else {
+            mLastRectRotation = 0;
             mQuickStepStartingRotation = QUICKSTEP_ROTATION_UNINITIALIZED;
-            resetSwipeRegions(info);
         }
+        resetSwipeRegions(info);
     }
 
     /**
@@ -236,6 +247,10 @@
     }
 
     boolean touchInValidSwipeRegions(float x, float y) {
+        if (TestProtocol.sDebugTracing) {
+            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "touchInValidSwipeRegions " + x + "," + y + " in "
+                    + mLastRectTouched);
+        }
         if (mLastRectTouched != null) {
             return mLastRectTouched.contains(x, y);
         }
@@ -243,11 +258,7 @@
     }
 
     int getCurrentActiveRotation() {
-        if (mLastRectTouched == null) {
-            return 0;
-        } else {
-            return mLastRectTouched.mRotation;
-        }
+        return mLastRectRotation;
     }
 
     int getQuickStepStartingRotation() {
@@ -281,12 +292,20 @@
 
                 for (int i = 0; i < MAX_ORIENTATIONS; i++) {
                     OrientationRectF rect = mSwipeTouchRegions.get(i);
+                    if (TestProtocol.sDebugTracing) {
+                        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "transform:DOWN, rect=" + rect);
+                    }
                     if (rect == null) {
                         continue;
                     }
                     if (rect.applyTransform(event, false)) {
+                        if (TestProtocol.sDebugTracing) {
+                            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "setting mLastRectTouched");
+                        }
                         mLastRectTouched = rect;
-                        if (mCurrentDisplayRotation == mLastRectTouched.mRotation) {
+                        mLastRectRotation = rect.mRotation;
+                        if (mEnableMultipleRegions && mCurrentDisplayRotation == mLastRectRotation) {
+                            // TODO(b/154580671) might make this block unnecessary
                             // Start a touch session for the default nav region for the display
                             mQuickStepStartingRotation = mLastRectTouched.mRotation;
                             resetSwipeRegions();
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 2d9c56f..70b4f20 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -40,21 +40,20 @@
 /**
  * Manages the recent task list from the system, caching it as necessary.
  */
-@TargetApi(Build.VERSION_CODES.P)
+@TargetApi(Build.VERSION_CODES.R)
 public class RecentTasksList extends TaskStackChangeListener {
 
+    private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0);
+
     private final KeyguardManagerCompat mKeyguardManager;
     private final LooperExecutor mMainThreadExecutor;
     private final ActivityManagerWrapper mActivityManagerWrapper;
 
     // The list change id, increments as the task list changes in the system
     private int mChangeId;
-    // The last change id when the list was last loaded completely, must be <= the list change id
-    private int mLastLoadedId;
-    // The last change id was loaded with keysOnly  = true
-    private boolean mLastLoadHadKeysOnly;
 
-    ArrayList<Task> mTasks = new ArrayList<>();
+    private TaskLoadResult mResultsBg = INVALID_RESULT;
+    private TaskLoadResult mResultsUi = INVALID_RESULT;
 
     public RecentTasksList(LooperExecutor mainThreadExecutor,
             KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) {
@@ -71,7 +70,7 @@
     public void getTaskKeys(int numTasks, Consumer<ArrayList<Task>> callback) {
         // Kick off task loading in the background
         UI_HELPER_EXECUTOR.execute(() -> {
-            ArrayList<Task> tasks = loadTasksInBackground(numTasks, true /* loadKeysOnly */);
+            ArrayList<Task> tasks = loadTasksInBackground(numTasks, -1, true /* loadKeysOnly */);
             mMainThreadExecutor.execute(() -> callback.accept(tasks));
         });
     }
@@ -85,26 +84,30 @@
      */
     public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) {
         final int requestLoadId = mChangeId;
-        Runnable resultCallback = callback == null
-                ? () -> { }
-                : () -> callback.accept(copyOf(mTasks));
-
-        if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) {
+        if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
             // The list is up to date, send the callback on the next frame,
             // so that requestID can be returned first.
-            mMainThreadExecutor.post(resultCallback);
+            if (callback != null) {
+                // Copy synchronously as the changeId might change by next frame
+                ArrayList<Task> result = copyOf(mResultsUi);
+                mMainThreadExecutor.post(() -> callback.accept(result));
+            }
+
             return requestLoadId;
         }
 
         // Kick off task loading in the background
         UI_HELPER_EXECUTOR.execute(() -> {
-            ArrayList<Task> tasks = loadTasksInBackground(Integer.MAX_VALUE, loadKeysOnly);
-
+            if (!mResultsBg.isValidForRequest(requestLoadId, loadKeysOnly)) {
+                mResultsBg = loadTasksInBackground(Integer.MAX_VALUE, requestLoadId, loadKeysOnly);
+            }
+            TaskLoadResult loadResult = mResultsBg;
             mMainThreadExecutor.execute(() -> {
-                mTasks = tasks;
-                mLastLoadedId = requestLoadId;
-                mLastLoadHadKeysOnly = loadKeysOnly;
-                resultCallback.run();
+                mResultsUi = loadResult;
+                if (callback != null) {
+                    ArrayList<Task> result = copyOf(mResultsUi);
+                    callback.accept(result);
+                }
             });
         });
 
@@ -119,8 +122,8 @@
     }
 
     @Override
-    public synchronized void onTaskStackChanged() {
-        mChangeId++;
+    public void onTaskStackChanged() {
+        invalidateLoadedTasks();
     }
 
     @Override
@@ -131,22 +134,28 @@
         // callback (those are for changes to the active tasks), but the task list is still updated,
         // so we should also invalidate the change id to ensure we load a new list instead of 
         // reusing a stale list.
-        mChangeId++;
+        invalidateLoadedTasks();
     }
 
     @Override
     public void onTaskRemoved(int taskId) {
-        mTasks = loadTasksInBackground(Integer.MAX_VALUE, false);
+        invalidateLoadedTasks();
     }
 
+
     @Override
-    public synchronized void onActivityPinned(String packageName, int userId, int taskId,
-            int stackId) {
-        mChangeId++;
+    public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+        invalidateLoadedTasks();
     }
 
     @Override
     public synchronized void onActivityUnpinned() {
+        invalidateLoadedTasks();
+    }
+
+    private synchronized void invalidateLoadedTasks() {
+        UI_HELPER_EXECUTOR.execute(() -> mResultsBg = INVALID_RESULT);
+        mResultsUi = INVALID_RESULT;
         mChangeId++;
     }
 
@@ -154,9 +163,8 @@
      * Loads and creates a list of all the recent tasks.
      */
     @VisibleForTesting
-    ArrayList<Task> loadTasksInBackground(int numTasks, boolean loadKeysOnly) {
+    TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly) {
         int currentUserId = Process.myUserHandle().getIdentifier();
-        ArrayList<Task> allTasks = new ArrayList<>();
         List<ActivityManager.RecentTaskInfo> rawTasks =
                 mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId);
         // The raw tasks are given in most-recent to least-recent order, we need to reverse it
@@ -173,6 +181,7 @@
             }
         };
 
+        TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size());
         for (ActivityManager.RecentTaskInfo rawTask : rawTasks) {
             Task.TaskKey taskKey = new Task.TaskKey(rawTask);
             Task task;
@@ -197,4 +206,22 @@
         }
         return newTasks;
     }
+
+    private static class TaskLoadResult extends ArrayList<Task> {
+
+        final int mId;
+
+        // If the result was loaded with keysOnly  = true
+        final boolean mKeysOnly;
+
+        TaskLoadResult(int id, boolean keysOnly, int size) {
+            super(size);
+            mId = id;
+            mKeysOnly = keysOnly;
+        }
+
+        boolean isValidForRequest(int requestId, boolean loadKeysOnly) {
+            return mId == requestId && (!mKeysOnly || loadKeysOnly);
+        }
+    }
 }
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 6e7c423..66e011d 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -18,6 +18,7 @@
 import static android.content.Intent.ACTION_USER_UNLOCKED;
 
 import static com.android.launcher3.util.DefaultDisplay.CHANGE_ALL;
+import static com.android.launcher3.util.DefaultDisplay.CHANGE_FRAME_DELAY;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
 import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
@@ -44,6 +45,7 @@
 import android.graphics.Region;
 import android.os.Process;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.view.MotionEvent;
 
@@ -52,6 +54,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.SecureSettingsObserver;
 import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
 import com.android.quickstep.util.NavBarPosition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -103,7 +106,8 @@
     private TaskStackChangeListener mFrozenTaskListener = new TaskStackChangeListener() {
         @Override
         public void onRecentTaskListFrozenChanged(boolean frozen) {
-            if (frozen) {
+            mTaskListFrozen = frozen;
+            if (frozen || mInOverview) {
                 return;
             }
             enableMultipleRegions(false);
@@ -124,6 +128,9 @@
      * TODO: (b/156984037) For when user rotates after entering overview
      */
     private boolean mInOverview;
+    private boolean mTaskListFrozen;
+
+    private boolean mIsUserSetupComplete;
 
     public RecentsAnimationDeviceState(Context context) {
         mContext = context;
@@ -175,6 +182,17 @@
                         ComponentName.unflattenFromString(blockingActivity));
             }
         }
+
+        SecureSettingsObserver userSetupObserver = new SecureSettingsObserver(
+                context.getContentResolver(),
+                e -> mIsUserSetupComplete = e,
+                Settings.Secure.USER_SETUP_COMPLETE,
+                0);
+        mIsUserSetupComplete = userSetupObserver.getValue();
+        if (!mIsUserSetupComplete) {
+            userSetupObserver.register();
+            runOnDestroy(userSetupObserver::unregister);
+        }
     }
 
     private void setupOrientationSwipeHandler() {
@@ -243,7 +261,8 @@
 
     @Override
     public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) {
-        if (info.id != getDisplayId()) {
+        if (info.id != getDisplayId() || (flags & CHANGE_FRAME_DELAY) == CHANGE_FRAME_DELAY) {
+            // ignore displays that aren't running launcher and frame refresh rate changes
             return;
         }
 
@@ -314,6 +333,13 @@
         return mIsUserUnlocked;
     }
 
+    /**
+     * @return whether the user has completed setup wizard
+     */
+    public boolean isUserSetupComplete() {
+        return mIsUserSetupComplete;
+    }
+
     private void notifyUserUnlocked() {
         for (Runnable action : mUserUnlockedActions) {
             action.run();
@@ -360,7 +386,6 @@
         return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
                 && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
                 && (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
-                && (mSystemUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) == 0
                 && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
                         || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0);
     }
@@ -381,6 +406,13 @@
     }
 
     /**
+     * @return whether the bubble stack is expanded
+     */
+    public boolean isBubblesExpanded() {
+        return (mSystemUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0;
+    }
+
+    /**
      * @return whether lock-task mode is active
      */
     public boolean isLockToAppActive() {
@@ -493,20 +525,22 @@
 
     /**
      * @param ev An ACTION_DOWN motion event
-     * @return whether the given motion event can trigger the assistant.
+     * @param task Info for the currently running task
+     * @return whether the given motion event can trigger the assistant over the current task.
      */
-    public boolean canTriggerAssistantAction(MotionEvent ev) {
+    public boolean canTriggerAssistantAction(MotionEvent ev, ActivityManager.RunningTaskInfo task) {
         return mAssistantAvailable
                 && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
                 && mOrientationTouchTransformer.touchInAssistantRegion(ev)
-                && !isLockToAppActive();
+                && !isLockToAppActive()
+                && !isGestureBlockedActivity(task);
     }
 
     /**
      * *May* apply a transform on the motion event if it lies in the nav bar region for another
      * orientation that is currently being tracked as a part of quickstep
      */
-    public void setOrientationTransformIfNeeded(MotionEvent event) {
+    void setOrientationTransformIfNeeded(MotionEvent event) {
         // negative coordinates bug b/143901881
         if (event.getX() < 0 || event.getY() < 0) {
             event.setLocation(Math.max(0, event.getX()), Math.max(0, event.getY()));
@@ -514,25 +548,54 @@
         mOrientationTouchTransformer.transform(event);
     }
 
-    void onSwipeUpToOverview(BaseActivityInterface activityInterface) {
-        mInOverview = true;
-        activityInterface.onExitOverview(this, () -> {
-            mInOverview = false;
-            enableMultipleRegions(false);
-        });
+    void enableMultipleRegions(boolean enable) {
+        mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
+        notifySysuiForRotation(mOrientationTouchTransformer.getQuickStepStartingRotation());
     }
 
-    void enableMultipleRegions(boolean enable) {
-        if (mInOverview) {
-            return;
+    private void notifySysuiForRotation(int rotation) {
+        UI_HELPER_EXECUTOR.execute(() ->
+                SystemUiProxy.INSTANCE.get(mContext).onQuickSwitchToNewTask(rotation));
+    }
+
+    public void onStartGesture() {
+        if (mTaskListFrozen) {
+            // Prioritize whatever nav bar user touches once in quickstep
+            // This case is specifically when user changes what nav bar they are using mid
+            // quickswitch session before tasks list is unfrozen
+            notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
         }
-        mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
-        UI_HELPER_EXECUTOR.execute(() -> {
-            int quickStepStartingRotation =
-                    mOrientationTouchTransformer.getQuickStepStartingRotation();
-            SystemUiProxy.INSTANCE.get(mContext)
-                    .onQuickSwitchToNewTask(quickStepStartingRotation);
-        });
+    }
+
+
+    void onEndTargetCalculated(GestureState.GestureEndTarget endTarget,
+            BaseActivityInterface activityInterface) {
+        if (endTarget == GestureState.GestureEndTarget.RECENTS) {
+            mInOverview = true;
+            if (!mTaskListFrozen) {
+                // If we're in landscape w/o ever quickswitching, show the navbar in landscape
+                enableMultipleRegions(true);
+            }
+            activityInterface.onExitOverview(this, () -> {
+                mInOverview = false;
+                enableMultipleRegions(false);
+            });
+        } else if (endTarget == GestureState.GestureEndTarget.HOME) {
+            enableMultipleRegions(false);
+        } else if (endTarget == GestureState.GestureEndTarget.NEW_TASK) {
+            if (mOrientationTouchTransformer.getQuickStepStartingRotation() == -1) {
+                // First gesture to start quickswitch
+                enableMultipleRegions(true);
+            } else {
+                notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
+            }
+        } else if (endTarget == GestureState.GestureEndTarget.LAST_TASK) {
+            if (!mTaskListFrozen) {
+                // touched nav bar but didn't go anywhere and not quickswitching, do nothing
+                return;
+            }
+            notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
+        }
     }
 
     public int getCurrentActiveRotation() {
diff --git a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
index f90df45..ab5e3ba 100644
--- a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
@@ -16,19 +16,16 @@
 package com.android.quickstep;
 
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
 
-import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Queue;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * Holds a collection of RemoteAnimationTargets, filtered by different properties.
  */
 public class RemoteAnimationTargets {
 
-    private final Queue<SyncRtSurfaceTransactionApplierCompat> mDependentTransactionAppliers =
-            new ArrayDeque<>(1);
+    private final CopyOnWriteArrayList<ReleaseCheck> mReleaseChecks = new CopyOnWriteArrayList<>();
 
     public final RemoteAnimationTargetCompat[] unfilteredApps;
     public final RemoteAnimationTargetCompat[] apps;
@@ -36,6 +33,8 @@
     public final int targetMode;
     public final boolean hasRecents;
 
+    private boolean mReleased = false;
+
     public RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps,
             RemoteAnimationTargetCompat[] wallpapers, int targetMode) {
         ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
@@ -76,21 +75,65 @@
         return false;
     }
 
-    public void addDependentTransactionApplier(SyncRtSurfaceTransactionApplierCompat delay) {
-        mDependentTransactionAppliers.add(delay);
+    public void addReleaseCheck(ReleaseCheck check) {
+        mReleaseChecks.add(check);
     }
 
     public void release() {
-        SyncRtSurfaceTransactionApplierCompat applier = mDependentTransactionAppliers.poll();
-        if (applier == null) {
-            for (RemoteAnimationTargetCompat target : unfilteredApps) {
-                target.release();
+        if (mReleased) {
+            return;
+        }
+        for (ReleaseCheck check : mReleaseChecks) {
+            if (!check.mCanRelease) {
+                check.addOnSafeToReleaseCallback(this::release);
+                return;
             }
-            for (RemoteAnimationTargetCompat target : wallpapers) {
-                target.release();
+        }
+        mReleaseChecks.clear();
+        mReleased = true;
+
+        for (RemoteAnimationTargetCompat target : unfilteredApps) {
+            target.release();
+        }
+        for (RemoteAnimationTargetCompat target : wallpapers) {
+            target.release();
+        }
+    }
+
+    /**
+     * Interface for intercepting surface release method
+     */
+    public static class ReleaseCheck {
+
+        boolean mCanRelease = false;
+        private Runnable mAfterApplyCallback;
+
+        protected void setCanRelease(boolean canRelease) {
+            mCanRelease = canRelease;
+            if (mCanRelease && mAfterApplyCallback != null) {
+                Runnable r = mAfterApplyCallback;
+                mAfterApplyCallback = null;
+                r.run();
             }
-        } else {
-            applier.addAfterApplyCallback(this::release);
+        }
+
+        /**
+         * Adds a callback to notify when the surface can safely be released
+         */
+        void addOnSafeToReleaseCallback(Runnable callback) {
+            if (mCanRelease) {
+                callback.run();
+            } else {
+                if (mAfterApplyCallback == null) {
+                    mAfterApplyCallback = callback;
+                } else {
+                    final Runnable oldCallback = mAfterApplyCallback;
+                    mAfterApplyCallback = () -> {
+                        callback.run();
+                        oldCallback.run();
+                    };
+                }
+            }
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java
new file mode 100644
index 0000000..6862f07
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.interaction;
+
+import static com.android.quickstep.interaction.TutorialController.TutorialType.ASSISTANT_COMPLETE;
+
+import android.graphics.PointF;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
+import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
+
+/** A {@link TutorialController} for the Assistant tutorial. */
+final class AssistantGestureTutorialController extends TutorialController {
+
+    AssistantGestureTutorialController(AssistantGestureTutorialFragment fragment,
+                                       TutorialType tutorialType) {
+        super(fragment, tutorialType);
+    }
+
+    @Override
+    Integer getTitleStringId() {
+        switch (mTutorialType) {
+            case ASSISTANT:
+                return R.string.assistant_gesture_tutorial_playground_title;
+            case ASSISTANT_COMPLETE:
+                return R.string.gesture_tutorial_confirm_title;
+        }
+        return null;
+    }
+
+    @Override
+    Integer getSubtitleStringId() {
+        if (mTutorialType == TutorialType.ASSISTANT) {
+            return R.string.assistant_gesture_tutorial_playground_subtitle;
+        }
+        return null;
+    }
+
+    @Override
+    Integer getActionButtonStringId() {
+        if (mTutorialType == ASSISTANT_COMPLETE) {
+            return R.string.gesture_tutorial_action_button_label_done;
+        }
+        return null;
+    }
+
+    @Override
+    void onActionButtonClicked(View button) {
+        mTutorialFragment.closeTutorial();
+    }
+
+    @Override
+    public void onBackGestureAttempted(BackGestureResult result) {
+        switch (mTutorialType) {
+            case ASSISTANT:
+                switch (result) {
+                    case BACK_COMPLETED_FROM_LEFT:
+                    case BACK_COMPLETED_FROM_RIGHT:
+                    case BACK_CANCELLED_FROM_LEFT:
+                    case BACK_CANCELLED_FROM_RIGHT:
+                        showFeedback(R.string.assistant_gesture_feedback_swipe_too_far_from_corner);
+                        break;
+                }
+                break;
+            case ASSISTANT_COMPLETE:
+                if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
+                        || result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT) {
+                    mTutorialFragment.closeTutorial();
+                }
+                break;
+        }
+    }
+
+
+    @Override
+    public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
+        switch (mTutorialType) {
+            case ASSISTANT:
+                switch (result) {
+                    case HOME_GESTURE_COMPLETED:
+                    case OVERVIEW_GESTURE_COMPLETED:
+                    case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
+                    case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
+                    case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
+                    case HOME_OR_OVERVIEW_CANCELLED:
+                        showFeedback(R.string.assistant_gesture_feedback_swipe_too_far_from_corner);
+                        break;
+                    case ASSISTANT_COMPLETED:
+                        hideFeedback();
+                        hideHandCoachingAnimation();
+                        showRippleEffect(
+                                () -> mTutorialFragment.changeController(ASSISTANT_COMPLETE));
+                        break;
+                    case ASSISTANT_NOT_STARTED_BAD_ANGLE:
+                        showFeedback(R.string.assistant_gesture_feedback_swipe_not_diagonal);
+                        break;
+                    case ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT:
+                        showFeedback(R.string.assistant_gesture_feedback_swipe_not_long_enough);
+                        break;
+                }
+                break;
+            case ASSISTANT_COMPLETE:
+                if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) {
+                    mTutorialFragment.closeTutorial();
+                }
+                break;
+        }
+    }
+
+    @Override
+    public void setAssistantProgress(float progress) {
+        // TODO: Create an animation.
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
new file mode 100644
index 0000000..70181fb
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.interaction;
+
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.quickstep.interaction.TutorialController.TutorialType;
+
+/** Shows the Home gesture interactive tutorial. */
+public class AssistantGestureTutorialFragment extends TutorialFragment {
+    @Override
+    int getHandAnimationResId() {
+        return R.drawable.assistant_gesture;
+    }
+
+    @Override
+    TutorialController createController(TutorialType type) {
+        return new AssistantGestureTutorialController(this, type);
+    }
+
+    @Override
+    Class<? extends TutorialController> getControllerClass() {
+        return AssistantGestureTutorialController.class;
+    }
+
+    @Override
+    public boolean onTouch(View view, MotionEvent motionEvent) {
+        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN && mTutorialController != null) {
+            mTutorialController.setRippleHotspot(motionEvent.getX(), motionEvent.getY());
+        }
+        return super.onTouch(view, motionEvent);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 41e86e0..921e568 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -21,8 +21,6 @@
 import android.graphics.PointF;
 import android.view.View;
 
-import androidx.annotation.Nullable;
-
 import com.android.launcher3.R;
 import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
 import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
@@ -35,14 +33,6 @@
     }
 
     @Override
-    void transitToController() {
-        super.transitToController();
-        if (mTutorialType != BACK_NAVIGATION_COMPLETE) {
-            showHandCoachingAnimation();
-        }
-    }
-
-    @Override
     Integer getTitleStringId() {
         switch (mTutorialType) {
             case RIGHT_EDGE_BACK_NAVIGATION:
@@ -164,7 +154,4 @@
             }
         }
     }
-
-    @Override
-    public void setNavBarGestureProgress(@Nullable Float displacement) {}
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java
index 5bf5026..0521db4 100644
--- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java
+++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java
@@ -280,7 +280,11 @@
                 new SpringForce()
                         .setStiffness(SpringForce.STIFFNESS_MEDIUM)
                         .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
-        mPaint.setColor(context.getColor(R.color.back_arrow_color_dark));
+        int currentNightMode =
+                context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        mPaint.setColor(context.getColor(currentNightMode == Configuration.UI_MODE_NIGHT_YES
+                ? R.color.back_arrow_color_light
+                : R.color.back_arrow_color_dark));
         loadDimens();
         updateArrowDirection();
 
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index 1113bc2..0edabd4 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -15,142 +15,23 @@
  */
 package com.android.quickstep.interaction;
 
-import static com.android.launcher3.anim.Interpolators.ACCEL;
-import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
-import static com.android.quickstep.BaseSwipeUpHandlerV2.MAX_SWIPE_DURATION;
 import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Insets;
-import android.graphics.Outline;
 import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.RectF;
 import android.os.Build;
-import android.view.SurfaceControl;
 import android.view.View;
-import android.view.ViewOutlineProvider;
-import android.view.WindowInsets.Type;
-import android.view.WindowManager;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.PendingAnimation;
-import com.android.quickstep.AnimatedFloat;
-import com.android.quickstep.GestureState;
-import com.android.quickstep.OverviewComponentObserver;
-import com.android.quickstep.RecentsAnimationDeviceState;
-import com.android.quickstep.SwipeUpAnimationLogic;
-import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
 import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
 import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
-import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.util.TransformParams;
-import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
 
 /** A {@link TutorialController} for the Home tutorial. */
 @TargetApi(Build.VERSION_CODES.R)
-final class HomeGestureTutorialController extends TutorialController {
-
-    private float mFakeTaskViewRadius;
-    private Rect mFakeTaskViewRect = new Rect();
-
-    private final ViewSwipeUpAnimation mViewSwipeUpAnimation;
-    private RunningWindowAnim mRunningWindowAnim;
+final class HomeGestureTutorialController extends SwipeUpGestureTutorialController {
 
     HomeGestureTutorialController(HomeGestureTutorialFragment fragment, TutorialType tutorialType) {
         super(fragment, tutorialType);
-
-        RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(mContext);
-        OverviewComponentObserver observer = new OverviewComponentObserver(mContext, deviceState);
-        mViewSwipeUpAnimation = new ViewSwipeUpAnimation(mContext, deviceState,
-                new GestureState(observer, -1));
-        observer.onDestroy();
-
-        DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext)
-                .getDeviceProfile(mContext)
-                .copy(mContext);
-        Insets insets = mContext.getSystemService(WindowManager.class)
-                .getCurrentWindowMetrics()
-                .getWindowInsets()
-                .getInsets(Type.systemBars());
-        dp.updateInsets(new Rect(insets.left, insets.top, insets.right, insets.bottom));
-        mViewSwipeUpAnimation.initDp(dp);
-
-        mFakeTaskViewRadius = QuickStepContract.getWindowCornerRadius(mContext.getResources());
-
-        mFakeTaskView.setClipToOutline(true);
-        mFakeTaskView.setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                outline.setRoundRect(mFakeTaskViewRect, mFakeTaskViewRadius);
-            }
-        });
-    }
-
-    private void cancelRunningAnimation() {
-        if (mRunningWindowAnim != null) {
-            mRunningWindowAnim.cancel();
-        }
-        mRunningWindowAnim = null;
-    }
-
-    /** Fades the task view, optionally after animating to a fake Overview. */
-    private void fadeOutFakeTaskView(boolean toOverviewFirst, @Nullable Runnable onEndRunnable) {
-        cancelRunningAnimation();
-        PendingAnimation anim = new PendingAnimation(300);
-        AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation, boolean isReverse) {
-                mFakeTaskView.setVisibility(View.INVISIBLE);
-                mFakeTaskView.setAlpha(1);
-                mRunningWindowAnim = null;
-            }
-        };
-        if (toOverviewFirst) {
-            anim.setFloat(mViewSwipeUpAnimation.getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation, boolean isReverse) {
-                    PendingAnimation fadeAnim = new PendingAnimation(300);
-                    fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
-                    fadeAnim.addListener(resetTaskView);
-                    AnimatorSet animset = fadeAnim.buildAnim();
-                    animset.setStartDelay(100);
-                    animset.start();
-                    mRunningWindowAnim = RunningWindowAnim.wrap(animset);
-                }
-            });
-        } else {
-            anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
-            anim.addListener(resetTaskView);
-        }
-        if (onEndRunnable != null) {
-            anim.addListener(AnimationSuccessListener.forRunnable(onEndRunnable));
-        }
-        AnimatorSet animset = anim.buildAnim();
-        animset.start();
-        mRunningWindowAnim = RunningWindowAnim.wrap(animset);
-    }
-
-    @Override
-    void transitToController() {
-        super.transitToController();
-        if (mTutorialType != HOME_NAVIGATION_COMPLETE) {
-            showHandCoachingAnimation();
-        }
     }
 
     @Override
@@ -189,6 +70,14 @@
     public void onBackGestureAttempted(BackGestureResult result) {
         switch (mTutorialType) {
             case HOME_NAVIGATION:
+                switch (result) {
+                    case BACK_COMPLETED_FROM_LEFT:
+                    case BACK_COMPLETED_FROM_RIGHT:
+                    case BACK_CANCELLED_FROM_LEFT:
+                    case BACK_CANCELLED_FROM_RIGHT:
+                        showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
+                        break;
+                }
                 break;
             case HOME_NAVIGATION_COMPLETE:
                 if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
@@ -205,17 +94,8 @@
             case HOME_NAVIGATION:
                 switch (result) {
                     case HOME_GESTURE_COMPLETED: {
-                        hideFeedback();
-                        cancelRunningAnimation();
-                        hideHandCoachingAnimation();
-                        RectFSpringAnim rectAnim =
-                                mViewSwipeUpAnimation.handleSwipeUpToHome(finalVelocity);
-                        // After home animation finishes, fade out and then move to the next screen.
-                        rectAnim.addAnimatorListener(AnimationSuccessListener.forRunnable(
-                                () -> fadeOutFakeTaskView(false,
-                                        () -> mTutorialFragment.changeController(
-                                                HOME_NAVIGATION_COMPLETE))));
-                        mRunningWindowAnim = RunningWindowAnim.wrap(rectAnim);
+                        animateFakeTaskViewHome(finalVelocity, () ->
+                                mTutorialFragment.changeController(HOME_NAVIGATION_COMPLETE));
                         break;
                     }
                     case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
@@ -241,93 +121,4 @@
         }
     }
 
-    @Override
-    public void setNavBarGestureProgress(@Nullable Float displacement) {
-        if (displacement == null || mTutorialType == HOME_NAVIGATION_COMPLETE) {
-            mFakeTaskView.setVisibility(View.INVISIBLE);
-        } else {
-            mFakeTaskView.setVisibility(View.VISIBLE);
-            if (mRunningWindowAnim == null) {
-                mViewSwipeUpAnimation.updateDisplacement(displacement);
-            }
-        }
-    }
-
-    private class ViewSwipeUpAnimation extends SwipeUpAnimationLogic {
-
-        ViewSwipeUpAnimation(Context context, RecentsAnimationDeviceState deviceState,
-                             GestureState gestureState) {
-            super(context, deviceState, gestureState, new FakeTransformParams());
-        }
-
-        void initDp(DeviceProfile dp) {
-            initTransitionEndpoints(dp);
-            mTaskViewSimulator.setPreviewBounds(
-                    new Rect(0, 0, dp.widthPx, dp.heightPx), dp.getInsets());
-        }
-
-        @Override
-        public void updateFinalShift() {
-            float progress = mCurrentShift.value / mDragLengthFactor;
-            mWindowTransitionController.setPlayFraction(progress);
-            mTaskViewSimulator.apply(mTransformParams);
-        }
-
-        AnimatedFloat getCurrentShift() {
-            return mCurrentShift;
-        }
-
-        RectFSpringAnim handleSwipeUpToHome(PointF velocity) {
-            PointF velocityPxPerMs = new PointF(velocity.x, velocity.y);
-            float currentShift = mCurrentShift.value;
-            final float startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y
-                    * getSingleFrameMs(mContext) / mTransitionDragLength, 0, mDragLengthFactor);
-            float distanceToTravel = (1 - currentShift) * mTransitionDragLength;
-
-            // we want the page's snap velocity to approximately match the velocity at
-            // which the user flings, so we scale the duration by a value near to the
-            // derivative of the scroll interpolator at zero, ie. 2.
-            long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
-            long duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
-            HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory(null) {
-                @Override
-                public AnimatorPlaybackController createActivityAnimationToHome() {
-                    return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
-                }
-
-                @NonNull
-                @Override
-                public RectF getWindowTargetRect() {
-                    int fakeHomeIconSizePx = mDp.allAppsIconSizePx;
-                    int fakeHomeIconLeft = (mDp.widthPx - fakeHomeIconSizePx) / 2;
-                    int fakeHomeIconTop = mDp.heightPx - (mDp.allAppsCellHeightPx * 3);
-                    return new RectF(fakeHomeIconLeft, fakeHomeIconTop,
-                            fakeHomeIconLeft + fakeHomeIconSizePx,
-                            fakeHomeIconTop + fakeHomeIconSizePx);
-                }
-            };
-            RectFSpringAnim windowAnim = createWindowAnimationToHome(startShift, homeAnimFactory);
-            windowAnim.start(mContext, velocityPxPerMs);
-            return windowAnim;
-        }
-    }
-
-    private class FakeTransformParams extends TransformParams {
-
-        @Override
-        public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
-            SurfaceParams.Builder builder = new SurfaceParams.Builder((SurfaceControl) null);
-            proxy.onBuildTargetParams(builder, null, this);
-            return new SurfaceParams[] {builder.build()};
-        }
-
-        @Override
-        public void applySurfaceParams(SurfaceParams[] params) {
-            SurfaceParams p = params[0];
-            mFakeTaskView.setAnimationMatrix(p.matrix);
-            mFakeTaskViewRect.set(p.windowCrop);
-            mFakeTaskViewRadius = p.cornerRadius;
-            mFakeTaskView.invalidateOutline();
-        }
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index 4069c09..0e2312b 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -15,6 +15,10 @@
  */
 package com.android.quickstep.interaction;
 
+import static com.android.launcher3.Utilities.squaredHypot;
+import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_COMPLETED;
+import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_NOT_STARTED_BAD_ANGLE;
+import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT;
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_GESTURE_COMPLETED;
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_NOT_STARTED_TOO_FAR_FROM_EDGE;
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_OR_OVERVIEW_CANCELLED;
@@ -22,38 +26,69 @@
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_GESTURE_COMPLETED;
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.graphics.RectF;
+import android.os.SystemClock;
 import android.view.Display;
+import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
 import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.R;
 import com.android.launcher3.ResourceUtils;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.util.VibratorWrapper;
 import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.util.NavBarPosition;
 import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
+import com.android.systemui.shared.system.QuickStepContract;
 
-/** Utility class to handle home gestures. */
+/** Utility class to handle Home and Assistant gestures. */
 public class NavBarGestureHandler implements OnTouchListener,
         TriggerSwipeUpTouchTracker.OnSwipeUpListener {
 
     private static final String LOG_TAG = "NavBarGestureHandler";
+    private static final long RETRACT_GESTURE_ANIMATION_DURATION_MS = 300;
 
+    private final Context mContext;
     private final Point mDisplaySize = new Point();
     private final TriggerSwipeUpTouchTracker mSwipeUpTouchTracker;
-    private int mBottomGestureHeight;
+    private final int mBottomGestureHeight;
+    private final GestureDetector mAssistantGestureDetector;
+    private final int mAssistantAngleThreshold;
+    private final RectF mAssistantLeftRegion = new RectF();
+    private final RectF mAssistantRightRegion = new RectF();
+    private final float mAssistantDragDistThreshold;
+    private final float mAssistantFlingDistThreshold;
+    private final long mAssistantTimeThreshold;
+    private final float mAssistantSquaredSlop;
+    private final PointF mAssistantStartDragPos = new PointF();
+    private final PointF mDownPos = new PointF();
+    private final PointF mLastPos = new PointF();
+    private boolean mTouchCameFromAssistantCorner;
     private boolean mTouchCameFromNavBar;
-    private float mDownY;
+    private boolean mPassedAssistantSlop;
+    private boolean mAssistantGestureActive;
+    private boolean mLaunchedAssistant;
+    private long mAssistantDragStartTime;
+    private float mAssistantDistance;
+    private float mAssistantTimeFraction;
+    private float mAssistantLastProgress;
+    @Nullable
     private NavBarGestureAttemptCallback mGestureCallback;
 
     NavBarGestureHandler(Context context) {
-        final Display display = context.getDisplay();
+        mContext = context;
+        final Display display = mContext.getDisplay();
         final int displayRotation;
         if (display == null) {
             displayRotation = Surface.ROTATION_0;
@@ -61,7 +96,6 @@
             displayRotation = display.getRotation();
             display.getRealSize(mDisplaySize);
         }
-        mDownY = mDisplaySize.y;
         mSwipeUpTouchTracker =
                 new TriggerSwipeUpTouchTracker(context, true /*disableHorizontalSwipe*/,
                         new NavBarPosition(Mode.NO_BUTTON, displayRotation),
@@ -70,6 +104,27 @@
         final Resources resources = context.getResources();
         mBottomGestureHeight =
                 ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, resources);
+        mAssistantDragDistThreshold =
+                resources.getDimension(R.dimen.gestures_assistant_drag_threshold);
+        mAssistantFlingDistThreshold =
+                resources.getDimension(R.dimen.gestures_assistant_fling_threshold);
+        mAssistantTimeThreshold =
+                resources.getInteger(R.integer.assistant_gesture_min_time_threshold);
+        mAssistantAngleThreshold =
+                resources.getInteger(R.integer.assistant_gesture_corner_deg_threshold);
+
+        mAssistantGestureDetector = new GestureDetector(context, new AssistantGestureListener());
+        int assistantWidth = resources.getDimensionPixelSize(R.dimen.gestures_assistant_width);
+        final float assistantHeight = Math.max(mBottomGestureHeight,
+                QuickStepContract.getWindowCornerRadius(resources));
+        mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mDisplaySize.y;
+        mAssistantLeftRegion.top = mAssistantRightRegion.top = mDisplaySize.y - assistantHeight;
+        mAssistantLeftRegion.left = 0;
+        mAssistantLeftRegion.right = assistantWidth;
+        mAssistantRightRegion.right = mDisplaySize.x;
+        mAssistantRightRegion.left = mDisplaySize.x - assistantWidth;
+        float slop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mAssistantSquaredSlop = slop * slop;
     }
 
     void registerNavBarGestureAttemptCallback(NavBarGestureAttemptCallback callback) {
@@ -82,7 +137,7 @@
 
     @Override
     public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
-        if (mGestureCallback == null) {
+        if (mGestureCallback == null || mAssistantGestureActive) {
             return;
         }
         finalVelocity.set(finalVelocity.x / 1000, finalVelocity.y / 1000);
@@ -98,36 +153,128 @@
 
     @Override
     public void onSwipeUpCancelled() {
-        if (mGestureCallback != null) {
+        if (mGestureCallback != null && !mAssistantGestureActive) {
             mGestureCallback.onNavBarGestureAttempted(HOME_OR_OVERVIEW_CANCELLED, new PointF());
         }
     }
 
     @Override
-    public boolean onTouch(View view, MotionEvent motionEvent) {
-        int action = motionEvent.getAction();
+    public boolean onTouch(View view, MotionEvent event) {
+        int action = event.getAction();
         boolean intercepted = mSwipeUpTouchTracker.interceptedTouch();
-        if (action == MotionEvent.ACTION_DOWN) {
-            mDownY = motionEvent.getY();
-            mTouchCameFromNavBar = mDownY >= mDisplaySize.y - mBottomGestureHeight;
-            if (!mTouchCameFromNavBar) {
-                mGestureCallback.setNavBarGestureProgress(null);
-            }
-            mSwipeUpTouchTracker.init();
-        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
-            if (mGestureCallback != null && !intercepted && mTouchCameFromNavBar) {
-                mGestureCallback.onNavBarGestureAttempted(
-                        HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION, new PointF());
-                intercepted = true;
-            }
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                mDownPos.set(event.getX(), event.getY());
+                mLastPos.set(mDownPos);
+                mTouchCameFromAssistantCorner =
+                        mAssistantLeftRegion.contains(event.getX(), event.getY())
+                                || mAssistantRightRegion.contains(event.getX(), event.getY());
+                mAssistantGestureActive = mTouchCameFromAssistantCorner;
+                mTouchCameFromNavBar = !mTouchCameFromAssistantCorner
+                        && mDownPos.y >= mDisplaySize.y - mBottomGestureHeight;
+                if (!mTouchCameFromNavBar && mGestureCallback != null) {
+                    mGestureCallback.setNavBarGestureProgress(null);
+                }
+                mLaunchedAssistant = false;
+                mSwipeUpTouchTracker.init();
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (!mAssistantGestureActive) {
+                    break;
+                }
+                mLastPos.set(event.getX(), event.getY());
+
+                if (!mPassedAssistantSlop) {
+                    // Normal gesture, ensure we pass the slop before we start tracking the gesture
+                    if (squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y)
+                            > mAssistantSquaredSlop) {
+
+                        mPassedAssistantSlop = true;
+                        mAssistantStartDragPos.set(mLastPos.x, mLastPos.y);
+                        mAssistantDragStartTime = SystemClock.uptimeMillis();
+
+                        mAssistantGestureActive = isValidAssistantGestureAngle(
+                                mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y);
+                        if (!mAssistantGestureActive && mGestureCallback != null) {
+                            mGestureCallback.onNavBarGestureAttempted(
+                                    ASSISTANT_NOT_STARTED_BAD_ANGLE, new PointF());
+                        }
+                    }
+                } else {
+                    // Movement
+                    mAssistantDistance = (float) Math.hypot(mLastPos.x - mAssistantStartDragPos.x,
+                            mLastPos.y - mAssistantStartDragPos.y);
+                    if (mAssistantDistance >= 0) {
+                        final long diff = SystemClock.uptimeMillis() - mAssistantDragStartTime;
+                        mAssistantTimeFraction = Math.min(diff * 1f / mAssistantTimeThreshold, 1);
+                        updateAssistantProgress();
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                if (mGestureCallback != null && !intercepted && mTouchCameFromNavBar) {
+                    mGestureCallback.onNavBarGestureAttempted(
+                            HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION, new PointF());
+                    intercepted = true;
+                    break;
+                }
+                if (mAssistantGestureActive && !mLaunchedAssistant && mGestureCallback != null) {
+                    mGestureCallback.onNavBarGestureAttempted(
+                            ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT, new PointF());
+                    ValueAnimator animator = ValueAnimator.ofFloat(mAssistantLastProgress, 0)
+                            .setDuration(RETRACT_GESTURE_ANIMATION_DURATION_MS);
+                    animator.addUpdateListener(valueAnimator -> {
+                        float progress = (float) valueAnimator.getAnimatedValue();
+                        mGestureCallback.setAssistantProgress(progress);
+                    });
+                    animator.setInterpolator(Interpolators.DEACCEL_2);
+                    animator.start();
+                }
+                mPassedAssistantSlop = false;
+                break;
         }
         if (mTouchCameFromNavBar && mGestureCallback != null) {
-            mGestureCallback.setNavBarGestureProgress(motionEvent.getY() - mDownY);
+            mGestureCallback.setNavBarGestureProgress(event.getY() - mDownPos.y);
         }
-        mSwipeUpTouchTracker.onMotionEvent(motionEvent);
+        mSwipeUpTouchTracker.onMotionEvent(event);
+        mAssistantGestureDetector.onTouchEvent(event);
         return intercepted;
     }
 
+    /**
+     * Determine if angle is larger than threshold for assistant detection
+     */
+    private boolean isValidAssistantGestureAngle(float deltaX, float deltaY) {
+        float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
+
+        // normalize so that angle is measured clockwise from horizontal in the bottom right corner
+        // and counterclockwise from horizontal in the bottom left corner
+        angle = angle > 90 ? 180 - angle : angle;
+        return (angle > mAssistantAngleThreshold && angle < 90);
+    }
+
+    private void updateAssistantProgress() {
+        if (!mLaunchedAssistant) {
+            mAssistantLastProgress =
+                    Math.min(mAssistantDistance * 1f / mAssistantDragDistThreshold, 1)
+                            * mAssistantTimeFraction;
+            if (mAssistantDistance >= mAssistantDragDistThreshold && mAssistantTimeFraction >= 1) {
+                startAssistant(new PointF());
+            } else if (mGestureCallback != null) {
+                mGestureCallback.setAssistantProgress(mAssistantLastProgress);
+            }
+        }
+    }
+
+    private void startAssistant(PointF velocity) {
+        if (mGestureCallback != null) {
+            mGestureCallback.onNavBarGestureAttempted(ASSISTANT_COMPLETED, velocity);
+        }
+        VibratorWrapper.INSTANCE.get(mContext).vibrate(VibratorWrapper.EFFECT_CLICK);
+        mLaunchedAssistant = true;
+    }
+
     enum NavBarGestureResult {
         UNKNOWN,
         HOME_GESTURE_COMPLETED,
@@ -135,7 +282,10 @@
         HOME_NOT_STARTED_TOO_FAR_FROM_EDGE,
         OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE,
         HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION,  // Side swipe on nav bar.
-        HOME_OR_OVERVIEW_CANCELLED
+        HOME_OR_OVERVIEW_CANCELLED,
+        ASSISTANT_COMPLETED,
+        ASSISTANT_NOT_STARTED_BAD_ANGLE,
+        ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT,
     }
 
     /** Callback to let the UI react to attempted nav bar gestures. */
@@ -144,6 +294,28 @@
         void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity);
 
         /** Indicates how far a touch originating in the nav bar has moved from the nav bar. */
-        void setNavBarGestureProgress(@Nullable Float displacement);
+        default void setNavBarGestureProgress(@Nullable Float displacement) {}
+
+        /** Indicates the progress of an Assistant gesture. */
+        default void setAssistantProgress(float progress) {}
+    }
+
+    private class AssistantGestureListener extends GestureDetector.SimpleOnGestureListener {
+        @Override
+        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+            if (!mLaunchedAssistant && mTouchCameFromAssistantCorner) {
+                PointF velocity = new PointF(velocityX, velocityY);
+                if (!isValidAssistantGestureAngle(velocityX, -velocityY)) {
+                    if (mGestureCallback != null) {
+                        mGestureCallback.onNavBarGestureAttempted(ASSISTANT_NOT_STARTED_BAD_ANGLE,
+                                velocity);
+                    }
+                } else if (mAssistantDistance >= mAssistantFlingDistThreshold) {
+                    mAssistantLastProgress = 1;
+                    startAssistant(velocity);
+                }
+            }
+            return true;
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
new file mode 100644
index 0000000..c636eba
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.interaction;
+
+import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
+
+import android.annotation.TargetApi;
+import android.graphics.PointF;
+import android.os.Build;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
+import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
+
+/** A {@link TutorialController} for the Overview tutorial. */
+@TargetApi(Build.VERSION_CODES.R)
+final class OverviewGestureTutorialController extends SwipeUpGestureTutorialController {
+
+    OverviewGestureTutorialController(OverviewGestureTutorialFragment fragment,
+            TutorialType tutorialType) {
+        super(fragment, tutorialType);
+    }
+
+    @Override
+    Integer getTitleStringId() {
+        switch (mTutorialType) {
+            case OVERVIEW_NAVIGATION:
+                return R.string.overview_gesture_tutorial_playground_title;
+            case OVERVIEW_NAVIGATION_COMPLETE:
+                return R.string.gesture_tutorial_confirm_title;
+        }
+        return null;
+    }
+
+    @Override
+    Integer getSubtitleStringId() {
+        if (mTutorialType == TutorialType.OVERVIEW_NAVIGATION) {
+            return R.string.overview_gesture_tutorial_playground_subtitle;
+        }
+        return null;
+    }
+
+    @Override
+    Integer getActionButtonStringId() {
+        if (mTutorialType == OVERVIEW_NAVIGATION_COMPLETE) {
+            return R.string.gesture_tutorial_action_button_label_done;
+        }
+        return null;
+    }
+
+    @Override
+    void onActionButtonClicked(View button) {
+        mTutorialFragment.closeTutorial();
+    }
+
+    @Override
+    public void onBackGestureAttempted(BackGestureResult result) {
+        switch (mTutorialType) {
+            case OVERVIEW_NAVIGATION:
+                switch (result) {
+                    case BACK_COMPLETED_FROM_LEFT:
+                    case BACK_COMPLETED_FROM_RIGHT:
+                    case BACK_CANCELLED_FROM_LEFT:
+                    case BACK_CANCELLED_FROM_RIGHT:
+                        showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
+                        break;
+                }
+                break;
+            case OVERVIEW_NAVIGATION_COMPLETE:
+                if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
+                        || result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT) {
+                    mTutorialFragment.closeTutorial();
+                }
+                break;
+        }
+    }
+
+    @Override
+    public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
+        switch (mTutorialType) {
+            case OVERVIEW_NAVIGATION:
+                switch (result) {
+                    case HOME_GESTURE_COMPLETED: {
+                        animateFakeTaskViewHome(finalVelocity, () ->
+                                showFeedback(R.string.overview_gesture_feedback_home_detected));
+                        break;
+                    }
+                    case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
+                    case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
+                        showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
+                        break;
+                    case OVERVIEW_GESTURE_COMPLETED:
+                        fadeOutFakeTaskView(true, () ->
+                                mTutorialFragment.changeController(OVERVIEW_NAVIGATION_COMPLETE));
+                        break;
+                    case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
+                    case HOME_OR_OVERVIEW_CANCELLED:
+                        fadeOutFakeTaskView(false, null);
+                        showFeedback(R.string.overview_gesture_feedback_wrong_swipe_direction);
+                        break;
+                }
+                break;
+            case OVERVIEW_NAVIGATION_COMPLETE:
+                if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) {
+                    mTutorialFragment.closeTutorial();
+                }
+                break;
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
new file mode 100644
index 0000000..3357b70
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.interaction;
+
+import com.android.launcher3.R;
+import com.android.quickstep.interaction.TutorialController.TutorialType;
+
+/** Shows the Overview gesture interactive tutorial. */
+public class OverviewGestureTutorialFragment extends TutorialFragment {
+    @Override
+    int getHandAnimationResId() {
+        return R.drawable.overview_gesture;
+    }
+
+    @Override
+    TutorialController createController(TutorialType type) {
+        return new OverviewGestureTutorialController(this, type);
+    }
+
+    @Override
+    Class<? extends TutorialController> getControllerClass() {
+        return OverviewGestureTutorialController.class;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
new file mode 100644
index 0000000..14e00dc
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.interaction;
+
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
+import static com.android.quickstep.BaseSwipeUpHandlerV2.MAX_SWIPE_DURATION;
+import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
+import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Insets;
+import android.graphics.Outline;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Build;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.GestureState;
+import com.android.quickstep.OverviewComponentObserver;
+import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.SwipeUpAnimationLogic;
+import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
+import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.TransformParams;
+import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+
+@TargetApi(Build.VERSION_CODES.R)
+abstract class SwipeUpGestureTutorialController extends TutorialController {
+    private final ViewSwipeUpAnimation mViewSwipeUpAnimation;
+    private float mFakeTaskViewRadius;
+    private Rect mFakeTaskViewRect = new Rect();
+    private RunningWindowAnim mRunningWindowAnim;
+
+    SwipeUpGestureTutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
+        super(tutorialFragment, tutorialType);
+        RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(mContext);
+        OverviewComponentObserver observer = new OverviewComponentObserver(mContext, deviceState);
+        mViewSwipeUpAnimation = new ViewSwipeUpAnimation(mContext, deviceState,
+                new GestureState(observer, -1));
+        observer.onDestroy();
+        deviceState.destroy();
+
+        DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext)
+                .getDeviceProfile(mContext)
+                .copy(mContext);
+        Insets insets = mContext.getSystemService(WindowManager.class)
+                .getCurrentWindowMetrics()
+                .getWindowInsets()
+                .getInsets(WindowInsets.Type.systemBars());
+        dp.updateInsets(new Rect(insets.left, insets.top, insets.right, insets.bottom));
+        mViewSwipeUpAnimation.initDp(dp);
+
+        mFakeTaskViewRadius = QuickStepContract.getWindowCornerRadius(mContext.getResources());
+        mFakeTaskView.setClipToOutline(true);
+        mFakeTaskView.setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                outline.setRoundRect(mFakeTaskViewRect, mFakeTaskViewRadius);
+            }
+        });
+    }
+
+    private void cancelRunningAnimation() {
+        if (mRunningWindowAnim != null) {
+            mRunningWindowAnim.cancel();
+        }
+        mRunningWindowAnim = null;
+    }
+
+    /** Fades the task view, optionally after animating to a fake Overview. */
+    void fadeOutFakeTaskView(boolean toOverviewFirst, @Nullable Runnable onEndRunnable) {
+        hideFeedback();
+        hideHandCoachingAnimation();
+        cancelRunningAnimation();
+        PendingAnimation anim = new PendingAnimation(300);
+        AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation, boolean isReverse) {
+                mFakeTaskView.setVisibility(View.INVISIBLE);
+                mFakeTaskView.setAlpha(1);
+                mRunningWindowAnim = null;
+            }
+        };
+        if (toOverviewFirst) {
+            anim.setFloat(mViewSwipeUpAnimation.getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL);
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation, boolean isReverse) {
+                    PendingAnimation fadeAnim = new PendingAnimation(300);
+                    fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
+                    fadeAnim.addListener(resetTaskView);
+                    AnimatorSet animset = fadeAnim.buildAnim();
+                    animset.setStartDelay(100);
+                    animset.start();
+                    mRunningWindowAnim = RunningWindowAnim.wrap(animset);
+                }
+            });
+        } else {
+            anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
+            anim.addListener(resetTaskView);
+        }
+        if (onEndRunnable != null) {
+            anim.addListener(AnimationSuccessListener.forRunnable(onEndRunnable));
+        }
+        AnimatorSet animset = anim.buildAnim();
+        animset.start();
+        mRunningWindowAnim = RunningWindowAnim.wrap(animset);
+    }
+
+    void animateFakeTaskViewHome(PointF finalVelocity, @Nullable Runnable onEndRunnable) {
+        hideFeedback();
+        hideHandCoachingAnimation();
+        cancelRunningAnimation();
+        RectFSpringAnim rectAnim =
+                mViewSwipeUpAnimation.handleSwipeUpToHome(finalVelocity);
+        // After home animation finishes, fade out and run onEndRunnable.
+        rectAnim.addAnimatorListener(AnimationSuccessListener.forRunnable(
+                () -> fadeOutFakeTaskView(false, onEndRunnable)));
+        mRunningWindowAnim = RunningWindowAnim.wrap(rectAnim);
+    }
+
+    @Override
+    public void setNavBarGestureProgress(@Nullable Float displacement) {
+        if (displacement == null || mTutorialType == HOME_NAVIGATION_COMPLETE
+                || mTutorialType == OVERVIEW_NAVIGATION_COMPLETE) {
+            mFakeTaskView.setVisibility(View.INVISIBLE);
+        } else {
+            mFakeTaskView.setVisibility(View.VISIBLE);
+            if (mRunningWindowAnim == null) {
+                mViewSwipeUpAnimation.updateDisplacement(displacement);
+            }
+        }
+    }
+
+    class ViewSwipeUpAnimation extends SwipeUpAnimationLogic {
+
+        ViewSwipeUpAnimation(Context context, RecentsAnimationDeviceState deviceState,
+                             GestureState gestureState) {
+            super(context, deviceState, gestureState, new FakeTransformParams());
+        }
+
+        void initDp(DeviceProfile dp) {
+            initTransitionEndpoints(dp);
+            mTaskViewSimulator.setPreviewBounds(
+                    new Rect(0, 0, dp.widthPx, dp.heightPx), dp.getInsets());
+        }
+
+        @Override
+        public void updateFinalShift() {
+            float progress = mCurrentShift.value / mDragLengthFactor;
+            mWindowTransitionController.setPlayFraction(progress);
+            mTaskViewSimulator.apply(mTransformParams);
+        }
+
+        AnimatedFloat getCurrentShift() {
+            return mCurrentShift;
+        }
+
+        RectFSpringAnim handleSwipeUpToHome(PointF velocity) {
+            PointF velocityPxPerMs = new PointF(velocity.x, velocity.y);
+            float currentShift = mCurrentShift.value;
+            final float startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y
+                    * getSingleFrameMs(mContext) / mTransitionDragLength, 0, mDragLengthFactor);
+            float distanceToTravel = (1 - currentShift) * mTransitionDragLength;
+
+            // we want the page's snap velocity to approximately match the velocity at
+            // which the user flings, so we scale the duration by a value near to the
+            // derivative of the scroll interpolator at zero, ie. 2.
+            long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
+            long duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
+            HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory(null) {
+                @Override
+                public AnimatorPlaybackController createActivityAnimationToHome() {
+                    return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
+                }
+
+                @NonNull
+                @Override
+                public RectF getWindowTargetRect() {
+                    int fakeHomeIconSizePx = mDp.allAppsIconSizePx;
+                    int fakeHomeIconLeft = (mDp.widthPx - fakeHomeIconSizePx) / 2;
+                    int fakeHomeIconTop = mDp.heightPx - (mDp.allAppsCellHeightPx * 3);
+                    return new RectF(fakeHomeIconLeft, fakeHomeIconTop,
+                            fakeHomeIconLeft + fakeHomeIconSizePx,
+                            fakeHomeIconTop + fakeHomeIconSizePx);
+                }
+            };
+            RectFSpringAnim windowAnim = createWindowAnimationToHome(startShift, homeAnimFactory);
+            windowAnim.start(mContext, velocityPxPerMs);
+            return windowAnim;
+        }
+    }
+
+    private class FakeTransformParams extends TransformParams {
+
+        @Override
+        public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
+            SurfaceParams.Builder builder = new SurfaceParams.Builder((SurfaceControl) null);
+            proxy.onBuildTargetParams(builder, null, this);
+            return new SurfaceParams[] {builder.build()};
+        }
+
+        @Override
+        public void applySurfaceParams(SurfaceParams[] params) {
+            SurfaceParams p = params[0];
+            mFakeTaskView.setAnimationMatrix(p.matrix);
+            mFakeTaskViewRect.set(p.windowCrop);
+            mFakeTaskViewRadius = p.cornerRadius;
+            mFakeTaskView.invalidateOutline();
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index f27d500..c1918c2 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -140,6 +140,9 @@
     void onActionTextButtonClicked(View button) {}
 
     void showHandCoachingAnimation() {
+        if (isComplete()) {
+            return;
+        }
         mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
     }
 
@@ -153,6 +156,12 @@
         hideFeedback();
         updateTitles();
         updateActionButtons();
+
+        if (isComplete()) {
+            hideHandCoachingAnimation();
+        } else {
+            showHandCoachingAnimation();
+        }
     }
 
     private void updateTitles() {
@@ -190,12 +199,23 @@
         button.setOnClickListener(listener);
     }
 
+    private boolean isComplete() {
+        return mTutorialType == TutorialType.BACK_NAVIGATION_COMPLETE
+                || mTutorialType == TutorialType.HOME_NAVIGATION_COMPLETE
+                || mTutorialType == TutorialType.OVERVIEW_NAVIGATION_COMPLETE
+                || mTutorialType == TutorialType.ASSISTANT_COMPLETE;
+    }
+
     /** Denotes the type of the tutorial. */
     enum TutorialType {
         RIGHT_EDGE_BACK_NAVIGATION,
         LEFT_EDGE_BACK_NAVIGATION,
         BACK_NAVIGATION_COMPLETE,
         HOME_NAVIGATION,
-        HOME_NAVIGATION_COMPLETE
+        HOME_NAVIGATION_COMPLETE,
+        OVERVIEW_NAVIGATION,
+        OVERVIEW_NAVIGATION_COMPLETE,
+        ASSISTANT,
+        ASSISTANT_COMPLETE
     }
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index a3881cf..9a8264d 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -68,6 +68,12 @@
             case HOME_NAVIGATION:
             case HOME_NAVIGATION_COMPLETE:
                 return new HomeGestureTutorialFragment();
+            case OVERVIEW_NAVIGATION:
+            case OVERVIEW_NAVIGATION_COMPLETE:
+                return new OverviewGestureTutorialFragment();
+            case ASSISTANT:
+            case ASSISTANT_COMPLETE:
+                return new AssistantGestureTutorialFragment();
             default:
                 Log.e(LOG_TAG, "Failed to find an appropriate fragment for " + tutorialType.name());
         }
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index 5745990..498c232 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -208,7 +208,7 @@
         mDisplayRotation = displayRotation;
         mTouchRotation = touchRotation;
 
-        if (mLauncherRotation == mTouchRotation) {
+        if (mLauncherRotation == mTouchRotation || canLauncherRotate()) {
             mOrientationHandler = PagedOrientationHandler.HOME_ROTATED;
             if (DEBUG) {
                 Log.d(TAG, "current RecentsOrientedState: " + this);
@@ -240,7 +240,7 @@
 
     private void setFlag(int mask, boolean enabled) {
         boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation
-                && mFlags == VALUE_ROTATION_WATCHER_ENABLED;
+                && (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED;
         if (enabled) {
             mFlags |= mask;
         } else {
@@ -248,7 +248,7 @@
         }
 
         boolean isRotationEnabled = !TestProtocol.sDisableSensorRotation
-                && mFlags == VALUE_ROTATION_WATCHER_ENABLED;
+                && (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED;
         if (wasRotationEnabled != isRotationEnabled) {
             UI_HELPER_EXECUTOR.execute(() -> {
                 if (isRotationEnabled) {
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
index 34eb7f8..79ddf7a 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -58,9 +58,9 @@
     }
 
     @Test
-    public void onTaskRemoved_reloadsAllTasks() {
+    public void onTaskRemoved_doesNotFetchTasks() {
         mRecentTasksList.onTaskRemoved(0);
-        verify(mockActivityManagerWrapper, times(1))
+        verify(mockActivityManagerWrapper, times(0))
                 .getRecentTasks(anyInt(), anyInt());
     }
 
@@ -77,7 +77,7 @@
         when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
                 .thenReturn(Collections.singletonList(recentTaskInfo));
 
-        List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, true);
+        List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, true);
 
         assertEquals(1, taskList.size());
         assertNull(taskList.get(0).taskDescription.getLabel());
@@ -91,7 +91,7 @@
         when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
                 .thenReturn(Collections.singletonList(recentTaskInfo));
 
-        List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, false);
+        List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, false);
 
         assertEquals(1, taskList.size());
         assertEquals(taskDescription, taskList.get(0).taskDescription.getLabel());
diff --git a/res/drawable/gesture_tutorial_ripple.xml b/res/drawable/gesture_tutorial_ripple.xml
index ca45662..782af33 100644
--- a/res/drawable/gesture_tutorial_ripple.xml
+++ b/res/drawable/gesture_tutorial_ripple.xml
@@ -1,6 +1,3 @@
 <?xml version="1.0" encoding="utf-8"?>
 <ripple android:color="@color/gesture_tutorial_ripple_color"
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@android:id/mask"
-        android:drawable="@color/gesture_tutorial_background_color" />
-</ripple>
\ No newline at end of file
+    xmlns:android="http://schemas.android.com/apk/res/android"/>
\ No newline at end of file
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 5691af2..5ed7712 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -135,7 +135,7 @@
     <string name="accessibility_close" msgid="2277148124685870734">"Zapri"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Obvestilo je bilo opuščeno"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osebno"</string>
-    <string name="all_apps_work_tab" msgid="4884822796154055118">"Služba"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"Delo"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Delovni profil"</string>
     <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Osebni podatki so ločeni in skriti pred delovnimi aplikacijami"</string>
     <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Delovne aplikacije in službeni podatki so vidni skrbniku za IT"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index de8bbd8..35e5678 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -71,9 +71,7 @@
       <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, ina arifa <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g></item>
     </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Ukurasa%1$d wa %2$d"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for workspace_scroll_format (8458889198184077399) -->
-    <skip />
+    <string name="workspace_scroll_format" msgid="8458889198184077399">"Skrini ya mwanzo %1$d ya %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ukurasa mpya wa skrini ya kwanza"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folda imefunguliwa, <xliff:g id="WIDTH">%1$d</xliff:g> kwa <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Gusa ili ufunge folda"</string>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index c4ec7dd..043ad9a 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -38,14 +38,8 @@
     <color name="all_apps_bg_hand_fill">#E5E5E5</color>
     <color name="all_apps_bg_hand_fill_dark">#9AA0A6</color>
 
-    <color name="gesture_tutorial_background_color">#FFFFFFFF</color>
-    <color name="gesture_tutorial_title_color">#FF000000</color>
-    <color name="gesture_tutorial_subtitle_color">#99000000</color> <!-- 60% black -->
-    <color name="gesture_tutorial_feedback_color">#FF000000</color>
     <color name="gesture_tutorial_ripple_color">#A0C2F9</color> <!-- Light Blue -->
     <color name="gesture_tutorial_fake_task_view_color">#6DA1FF</color> <!-- Light Blue -->
     <color name="gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
     <color name="gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
-
-
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 26b7205..e470c42 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -81,7 +81,6 @@
         <item name="folderFillColor">#CDFFFFFF</item>
         <item name="folderIconBorderColor">#FF80868B</item>
         <item name="folderTextColor">?attr/workspaceTextColor</item>
-
     </style>
 
     <style name="LauncherTheme.Dark" parent="@style/LauncherTheme">
diff --git a/robolectric_tests/config/robolectric.properties b/robolectric_tests/config/robolectric.properties
index c162255..b171712 100644
--- a/robolectric_tests/config/robolectric.properties
+++ b/robolectric_tests/config/robolectric.properties
@@ -13,6 +13,6 @@
     com.android.launcher3.shadows.ShadowLooperExecutor \
     com.android.launcher3.shadows.ShadowMainThreadInitializedObject \
     com.android.launcher3.shadows.ShadowOverrides \
-    com.android.launcher3.shadows.ShadowSyncRtSurfaceTransactionApplierCompat \
+    com.android.launcher3.shadows.ShadowSurfaceTransactionApplier \
 
 application=com.android.launcher3.util.LauncherTestApplication
\ No newline at end of file
diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
index 59c9480..cca333c 100644
--- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
+++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
@@ -59,6 +59,17 @@
     private HashSet<String> mValidPackages;
     private InvariantDeviceProfile mIdp;
 
+    private final String testPackage1 = "com.android.launcher3.validpackage1";
+    private final String testPackage2 = "com.android.launcher3.validpackage2";
+    private final String testPackage3 = "com.android.launcher3.validpackage3";
+    private final String testPackage4 = "com.android.launcher3.validpackage4";
+    private final String testPackage5 = "com.android.launcher3.validpackage5";
+    private final String testPackage6 = "com.android.launcher3.validpackage6";
+    private final String testPackage7 = "com.android.launcher3.validpackage7";
+    private final String testPackage8 = "com.android.launcher3.validpackage8";
+    private final String testPackage9 = "com.android.launcher3.validpackage9";
+    private final String testPackage10 = "com.android.launcher3.validpackage10";
+
     @Before
     public void setUp() {
         mModelHelper = new LauncherModelHelper();
@@ -67,6 +78,17 @@
 
         mValidPackages = new HashSet<>();
         mValidPackages.add(TEST_PACKAGE);
+        mValidPackages.add(testPackage1);
+        mValidPackages.add(testPackage2);
+        mValidPackages.add(testPackage3);
+        mValidPackages.add(testPackage4);
+        mValidPackages.add(testPackage5);
+        mValidPackages.add(testPackage6);
+        mValidPackages.add(testPackage7);
+        mValidPackages.add(testPackage8);
+        mValidPackages.add(testPackage9);
+        mValidPackages.add(testPackage10);
+
         mIdp = InvariantDeviceProfile.INSTANCE.get(mContext);
 
         long userSerial = UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
@@ -78,20 +100,6 @@
 
     @Test
     public void testMigration() {
-        final String testPackage1 = "com.android.launcher3.validpackage1";
-        final String testPackage2 = "com.android.launcher3.validpackage2";
-        final String testPackage3 = "com.android.launcher3.validpackage3";
-        final String testPackage4 = "com.android.launcher3.validpackage4";
-        final String testPackage5 = "com.android.launcher3.validpackage5";
-        final String testPackage7 = "com.android.launcher3.validpackage7";
-
-        mValidPackages.add(testPackage1);
-        mValidPackages.add(testPackage2);
-        mValidPackages.add(testPackage3);
-        mValidPackages.add(testPackage4);
-        mValidPackages.add(testPackage5);
-        mValidPackages.add(testPackage7);
-
         int[] srcHotseatItems = {
                 mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
                 mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
@@ -100,6 +108,10 @@
                 mModelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI),
         };
         mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage5, 5, TMP_CONTENT_URI);
+        mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage6, 6, TMP_CONTENT_URI);
+        mModelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 1, testPackage8, 8, TMP_CONTENT_URI);
+        mModelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 2, testPackage9, 9, TMP_CONTENT_URI);
+        mModelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 3, testPackage10, 10, TMP_CONTENT_URI);
 
         int[] destHotseatItems = {
                 -1,
@@ -108,21 +120,24 @@
         };
         mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage7);
 
-        mIdp.numHotseatIcons = 3;
-        mIdp.numColumns = 3;
-        mIdp.numRows = 3;
+        mIdp.numHotseatIcons = 4;
+        mIdp.numColumns = 4;
+        mIdp.numRows = 4;
         GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
-                LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages, 5);
+                LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages,
+                srcHotseatItems.length);
         GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
-                LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages, 3);
+                LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages,
+                mIdp.numHotseatIcons);
         GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
-                destReader, 3, new Point(mIdp.numColumns, mIdp.numRows));
+                destReader, mIdp.numHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
         task.migrate();
 
+        // Check hotseat items
         Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
                 new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT},
                 "container=" + CONTAINER_HOTSEAT, null, null, null);
-        assertEquals(c.getCount(), 3);
+        assertEquals(c.getCount(), mIdp.numHotseatIcons);
         int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN);
         int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
         c.moveToNext();
@@ -134,13 +149,17 @@
         c.moveToNext();
         assertEquals(c.getInt(screenIndex), 2);
         assertTrue(c.getString(intentIndex).contains(testPackage3));
+        c.moveToNext();
+        assertEquals(c.getInt(screenIndex), 3);
+        assertTrue(c.getString(intentIndex).contains(testPackage4));
         c.close();
 
+        // Check workspace items
         c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
                 new String[]{LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
                         LauncherSettings.Favorites.INTENT},
                 "container=" + CONTAINER_DESKTOP, null, null, null);
-        assertEquals(c.getCount(), 2);
+        assertEquals(c.getCount(), 6);
         intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
         int cellXIndex = c.getColumnIndex(LauncherSettings.Favorites.CELLX);
         int cellYIndex = c.getColumnIndex(LauncherSettings.Favorites.CELLY);
@@ -148,7 +167,23 @@
         c.moveToNext();
         assertTrue(c.getString(intentIndex).contains(testPackage7));
         c.moveToNext();
+        assertTrue(c.getString(intentIndex).contains(testPackage6));
+        assertEquals(c.getInt(cellXIndex), 0);
+        assertEquals(c.getInt(cellYIndex), 3);
+        c.moveToNext();
+        assertTrue(c.getString(intentIndex).contains(testPackage10));
+        assertEquals(c.getInt(cellXIndex), 1);
+        assertEquals(c.getInt(cellYIndex), 3);
+        c.moveToNext();
         assertTrue(c.getString(intentIndex).contains(testPackage5));
+        assertEquals(c.getInt(cellXIndex), 2);
+        assertEquals(c.getInt(cellYIndex), 3);
+        c.moveToNext();
+        assertTrue(c.getString(intentIndex).contains(testPackage9));
+        assertEquals(c.getInt(cellXIndex), 3);
+        assertEquals(c.getInt(cellYIndex), 3);
+        c.moveToNext();
+        assertTrue(c.getString(intentIndex).contains(testPackage8));
         assertEquals(c.getInt(cellXIndex), 0);
         assertEquals(c.getInt(cellYIndex), 2);
     }
diff --git a/robolectric_tests/src/com/android/launcher3/shadows/ShadowSyncRtSurfaceTransactionApplierCompat.java b/robolectric_tests/src/com/android/launcher3/shadows/ShadowSurfaceTransactionApplier.java
similarity index 83%
rename from robolectric_tests/src/com/android/launcher3/shadows/ShadowSyncRtSurfaceTransactionApplierCompat.java
rename to robolectric_tests/src/com/android/launcher3/shadows/ShadowSurfaceTransactionApplier.java
index 238926c..a9f2f27 100644
--- a/robolectric_tests/src/com/android/launcher3/shadows/ShadowSyncRtSurfaceTransactionApplierCompat.java
+++ b/robolectric_tests/src/com/android/launcher3/shadows/ShadowSurfaceTransactionApplier.java
@@ -26,11 +26,11 @@
 import org.robolectric.annotation.RealObject;
 
 /**
- * Shadow for SyncRtSurfaceTransactionApplierCompat to override default functionality
+ * Shadow for SurfaceTransactionApplier to override default functionality
  */
-@Implements(className = "com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat",
+@Implements(className = "com.android.quickstep.util.SurfaceTransactionApplier",
         isInAndroidSdk = false)
-public class ShadowSyncRtSurfaceTransactionApplierCompat {
+public class ShadowSurfaceTransactionApplier {
 
     @RealObject
     private Object mRealObject;
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 8951674..60abc66 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -200,7 +200,7 @@
                 DefaultDisplay.INSTANCE.get(context).getInfo(),
                 getPredefinedDeviceProfiles(context, gridName));
 
-        Info myInfo = new Info(display);
+        Info myInfo = new Info(context, display);
         DisplayOption myDisplayOption = invDistWeightedInterpolate(
                 myInfo, getPredefinedDeviceProfiles(context, gridName));
 
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 48b97fa..e8b5568 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -411,6 +411,11 @@
                         Favorites.BACKUP_TABLE_NAME);
                 return null;
             }
+            case LauncherSettings.Settings.METHOD_REFRESH_HOTSEAT_RESTORE_TABLE: {
+                mOpenHelper.mHotseatRestoreTableExists = tableExists(
+                        mOpenHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
+                return null;
+            }
             case LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE: {
                 final long ts = System.currentTimeMillis();
                 if (ts - mLastRestoreTimestamp > RESTORE_BACKUP_TABLE_DELAY) {
@@ -609,6 +614,7 @@
         private int mMaxItemId = -1;
         private int mMaxScreenId = -1;
         private boolean mBackupTableExists;
+        private boolean mHotseatRestoreTableExists;
 
         static DatabaseHelper createDatabaseHelper(Context context, boolean forMigration) {
             return createDatabaseHelper(context, null, forMigration);
@@ -633,6 +639,8 @@
                 databaseHelper.mBackupTableExists = tableExists(
                         databaseHelper.getReadableDatabase(), Favorites.BACKUP_TABLE_NAME);
             }
+            databaseHelper.mHotseatRestoreTableExists = tableExists(
+                    databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
 
             databaseHelper.initIds();
             return databaseHelper;
@@ -679,6 +687,10 @@
                 dropTable(db, Favorites.BACKUP_TABLE_NAME);
                 mBackupTableExists = false;
             }
+            if (mHotseatRestoreTableExists) {
+                dropTable(db, Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
+                mHotseatRestoreTableExists = false;
+            }
         }
 
         /**
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 6789072..2a5ee00 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -100,6 +100,11 @@
         public static final String BACKUP_TABLE_NAME = "favorites_bakup";
 
         /**
+         * Backup table created when user hotseat is moved to workspace for hybrid hotseat
+         */
+        public static final String HYBRID_HOTSEAT_BACKUP_TABLE = "hotseat_restore_backup";
+
+        /**
          * Temporary table used specifically for grid migrations during wallpaper preview
          */
         public static final String PREVIEW_TABLE_NAME = "favorites_preview";
@@ -154,9 +159,9 @@
         public static final int CONTAINER_HOTSEAT_PREDICTION = -103;
         public static final int CONTAINER_ALL_APPS = -104;
         public static final int CONTAINER_WIDGETS_TRAY = -105;
-
         // Represents search results view.
         public static final int CONTAINER_SEARCH_RESULTS = -106;
+        public static final int CONTAINER_SHORTCUTS = -107;
 
         public static final String containerToString(int container) {
             switch (container) {
@@ -166,6 +171,7 @@
                 case CONTAINER_ALL_APPS: return "all_apps";
                 case CONTAINER_WIDGETS_TRAY: return "widgets_tray";
                 case CONTAINER_SEARCH_RESULTS: return "search_result";
+                case CONTAINER_SHORTCUTS: return "shortcuts";
                 default: return String.valueOf(container);
             }
         }
@@ -332,6 +338,8 @@
 
         public static final String METHOD_REFRESH_BACKUP_TABLE = "refresh_backup_table";
 
+        public static final String METHOD_REFRESH_HOTSEAT_RESTORE_TABLE = "restore_hotseat_table";
+
         public static final String METHOD_RESTORE_BACKUP_TABLE = "restore_backup_table";
 
         public static final String METHOD_UPDATE_CURRENT_OPEN_HELPER = "update_current_open_helper";
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index 34bf636..7d5363f 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.allapps;
 
+import static com.android.launcher3.LauncherState.ALL_APPS_HEADER;
+
 import android.graphics.Rect;
 import android.view.KeyEvent;
 import android.view.animation.Interpolator;
@@ -57,6 +59,13 @@
             Interpolator interpolator);
 
     /**
+     * Returns true if the QSB should be visible for the given set of visible elements
+     */
+    default boolean isQsbVisible(int visibleElements) {
+        return (visibleElements & ALL_APPS_HEADER) != 0;
+    }
+
+    /**
      * Called to control how the search UI result should be handled.
      *
      * @param isEnabled when {@code true}, the search is all handled inside AOSP
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index e72e1a8..356c52c 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -19,7 +19,6 @@
 import static android.view.View.MeasureSpec.getSize;
 import static android.view.View.MeasureSpec.makeMeasureSpec;
 
-import static com.android.launcher3.LauncherState.ALL_APPS_HEADER;
 import static com.android.launcher3.Utilities.prefixTextWithIcon;
 import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
 
@@ -213,7 +212,7 @@
     @Override
     public void setContentVisibility(int visibleElements, PropertySetter setter,
             Interpolator interpolator) {
-        setter.setViewAlpha(this, (visibleElements & ALL_APPS_HEADER) != 0 ? 1 : 0, interpolator);
+        setter.setViewAlpha(this, isQsbVisible(visibleElements) ? 1 : 0, interpolator);
     }
 
     @Override
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 978dd52..118ce0c 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -103,7 +103,7 @@
             "Adds localized title and keyword search and ranking");
 
     public static final BooleanFlag ENABLE_PREDICTION_DISMISS = getDebugFlag(
-            "ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
+            "ENABLE_PREDICTION_DISMISS", true, "Allow option to dimiss apps from predicted list");
 
     public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag(
             "ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index e11d21f..bc560fa 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -94,7 +94,27 @@
 
         @UiEvent(doc = "User cancelled uninstalling the package after dropping on "
                 + "the icon onto 'Uninstall' button in the target bar")
-        LAUNCHER_ITEM_UNINSTALL_CANCELLED(470);
+        LAUNCHER_ITEM_UNINSTALL_CANCELLED(470),
+
+        @UiEvent(doc = "User tapped or long pressed on the task icon(aka package icon) "
+                + "from overview to open task menu.")
+        LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS(517),
+
+        @UiEvent(doc = "User opened package specific widgets list by tapping on widgets system "
+                + "shortcut within longpress popup window.")
+        LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP(514),
+
+        @UiEvent(doc = "User tapped on app info system shortcut.")
+        LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP(515),
+
+        @UiEvent(doc = "User tapped on split screen icon on a task menu.")
+        LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP(518),
+
+        @UiEvent(doc = "User tapped on free form icon on a task menu.")
+        LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP(519),
+
+        @UiEvent(doc = "User tapped on pause app system shortcut.")
+        LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP(519);
         // ADD MORE
 
         private final int mId;
diff --git a/src/com/android/launcher3/model/GridBackupTable.java b/src/com/android/launcher3/model/GridBackupTable.java
index 4a1bc4d..acfc339 100644
--- a/src/com/android/launcher3/model/GridBackupTable.java
+++ b/src/com/android/launcher3/model/GridBackupTable.java
@@ -128,6 +128,32 @@
     }
 
     /**
+     * Creates a new table and populates with copy of Favorites.TABLE_NAME
+     */
+    public void createCustomBackupTable(String tableName) {
+        long profileId = UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
+                Process.myUserHandle());
+        copyTable(mDb, Favorites.TABLE_NAME, tableName, profileId);
+        encodeDBProperties(0);
+    }
+
+    /**
+     *
+     * Restores the contents of a custom table to Favorites.TABLE_NAME
+     */
+
+    public void restoreFromCustomBackupTable(String tableName, boolean dropAfterUse) {
+        if (!tableExists(mDb, tableName)) {
+            return;
+        }
+        long userSerial = UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
+                Process.myUserHandle());
+        copyTable(mDb, tableName, Favorites.TABLE_NAME, userSerial);
+        if (dropAfterUse) {
+            dropTable(mDb, tableName);
+        }
+    }
+    /**
      * Copy valid grid entries from one table to another.
      */
     private static void copyTable(SQLiteDatabase db, String from, String to, long userSerial) {
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
index 4a28218..4bfabb0 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
@@ -33,6 +33,7 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Point;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
@@ -55,6 +56,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -226,9 +228,8 @@
             if (DEBUG) {
                 Log.d(TAG, "Migrating " + screenId);
             }
-            List<DbEntry> entries = mDestReader.loadWorkspaceEntries(screenId);
             GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
-                    mDestReader, mContext, entries, screenId, mTrgX, mTrgY, mWorkspaceDiff);
+                    mDestReader, mContext, screenId, mTrgX, mTrgY, mWorkspaceDiff);
             workspaceSolution.find();
             if (mWorkspaceDiff.isEmpty()) {
                 break;
@@ -238,8 +239,7 @@
         int screenId = mDestReader.mLastScreenId + 1;
         while (!mWorkspaceDiff.isEmpty()) {
             GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
-                    mDestReader, mContext, new ArrayList<>(), screenId, mTrgX, mTrgY,
-                    mWorkspaceDiff);
+                    mDestReader, mContext, screenId, mTrgX, mTrgY, mWorkspaceDiff);
             workspaceSolution.find();
             screenId++;
         }
@@ -352,8 +352,7 @@
         private int mNextStartY;
 
         GridPlacementSolution(SQLiteDatabase db, DbReader srcReader, DbReader destReader,
-                Context context, List<DbEntry> placedWorkspaceItems, int screenId, int trgX,
-                int trgY, List<DbEntry> itemsToPlace) {
+                Context context, int screenId, int trgX, int trgY, List<DbEntry> itemsToPlace) {
             mDb = db;
             mSrcReader = srcReader;
             mDestReader = destReader;
@@ -364,8 +363,11 @@
             mTrgY = trgY;
             mNextStartX = 0;
             mNextStartY = mTrgY - 1;
-            for (DbEntry entry : placedWorkspaceItems) {
-                mOccupied.markCells(entry, true);
+            List<DbEntry> existedEntries = mDestReader.mWorkspaceEntriesByScreenId.get(screenId);
+            if (existedEntries != null) {
+                for (DbEntry entry : existedEntries) {
+                    mOccupied.markCells(entry, true);
+                }
             }
             mItemsToPlace = itemsToPlace;
         }
@@ -386,6 +388,11 @@
             }
         }
 
+        /**
+         * Search for the next possible placement of an icon. (mNextStartX, mNextStartY) serves as
+         * a memoization of last placement, we can start our search for next placement from there
+         * to speed up the search.
+         */
         private boolean findPlacement(DbEntry entry) {
             for (int y = mNextStartY; y >= 0; y--) {
                 for (int x = mNextStartX; x < mTrgX; x++) {
@@ -406,6 +413,7 @@
                         return true;
                     }
                 }
+                mNextStartX = 0;
             }
             return false;
         }
@@ -475,6 +483,8 @@
 
         private final ArrayList<DbEntry> mHotseatEntries = new ArrayList<>();
         private final ArrayList<DbEntry> mWorkspaceEntries = new ArrayList<>();
+        private final Map<Integer, ArrayList<DbEntry>> mWorkspaceEntriesByScreenId =
+                new ArrayMap<>();
 
         DbReader(SQLiteDatabase db, String tableName, Context context,
                 HashSet<String> validPackages, int hotseatSize) {
@@ -564,25 +574,6 @@
             return loadWorkspaceEntries(c);
         }
 
-        protected ArrayList<DbEntry> loadWorkspaceEntries(int screen) {
-            Cursor c = queryWorkspace(
-                    new String[]{
-                            LauncherSettings.Favorites._ID,                  // 0
-                            LauncherSettings.Favorites.ITEM_TYPE,            // 1
-                            LauncherSettings.Favorites.SCREEN,               // 2
-                            LauncherSettings.Favorites.CELLX,                // 3
-                            LauncherSettings.Favorites.CELLY,                // 4
-                            LauncherSettings.Favorites.SPANX,                // 5
-                            LauncherSettings.Favorites.SPANY,                // 6
-                            LauncherSettings.Favorites.INTENT,               // 7
-                            LauncherSettings.Favorites.APPWIDGET_PROVIDER,   // 8
-                            LauncherSettings.Favorites.APPWIDGET_ID},        // 9
-                    LauncherSettings.Favorites.CONTAINER + " = "
-                            + LauncherSettings.Favorites.CONTAINER_DESKTOP
-                            + " AND " + LauncherSettings.Favorites.SCREEN + " = " + screen);
-            return loadWorkspaceEntries(c);
-        }
-
         private ArrayList<DbEntry> loadWorkspaceEntries(Cursor c) {
             final int indexId = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
             final int indexItemType = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
@@ -660,6 +651,10 @@
                     continue;
                 }
                 mWorkspaceEntries.add(entry);
+                if (!mWorkspaceEntriesByScreenId.containsKey(entry.screenId)) {
+                    mWorkspaceEntriesByScreenId.put(entry.screenId, new ArrayList<>());
+                }
+                mWorkspaceEntriesByScreenId.get(entry.screenId).add(entry);
             }
             removeEntryFromDb(mDb, mTableName, entriesToRemove);
             c.close();
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 3a89236..0c815d1 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SEARCH_RESULTS;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
@@ -45,6 +46,7 @@
 import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
 import com.android.launcher3.logger.LauncherAtom.PredictionContainer;
 import com.android.launcher3.logger.LauncherAtom.SearchResultContainer;
+import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
 import com.android.launcher3.util.ContentWriter;
 
 import java.util.Optional;
@@ -363,6 +365,10 @@
                 return ContainerInfo.newBuilder()
                         .setSearchResultContainer(SearchResultContainer.getDefaultInstance())
                         .build();
+            case CONTAINER_SHORTCUTS:
+                return ContainerInfo.newBuilder()
+                        .setShortcutsContainer(ShortcutsContainer.getDefaultInstance())
+                        .build();
         }
         return ContainerInfo.getDefaultInstance();
     }
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 331298f..614cf14 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.popup;
 
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.Utilities.squaredTouchSlop;
 import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
@@ -61,6 +62,7 @@
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.notification.NotificationInfo;
 import com.android.launcher3.notification.NotificationItemView;
 import com.android.launcher3.notification.NotificationKeyData;
@@ -675,8 +677,10 @@
             iconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx;
 
             DraggableView draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON);
+            WorkspaceItemInfo itemInfo = sv.getFinalInfo();
+            itemInfo.container = CONTAINER_SHORTCUTS;
             DragView dv = mLauncher.getWorkspace().beginDragShared(sv.getIconView(), draggableView,
-                    mContainer, sv.getFinalInfo(),
+                    mContainer, itemInfo,
                     new ShortcutDragPreviewProvider(sv.getIconView(), iconShift),
                     new DragOptions());
             dv.animateShift(-iconShift.x, -iconShift.y);
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index 7da86cc..6d3bc14 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.popup;
 
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
+
 import android.content.ComponentName;
 import android.content.pm.ShortcutInfo;
 import android.os.Handler;
@@ -160,6 +162,7 @@
                 final WorkspaceItemInfo si = new WorkspaceItemInfo(shortcut, launcher);
                 cache.getUnbadgedShortcutIcon(si, shortcut);
                 si.rank = i;
+                si.container = CONTAINER_SHORTCUTS;
 
                 final DeepShortcutView view = shortcutViews.get(i);
                 uiHandler.post(() -> view.applyShortcutInfo(si, shortcut, container));
diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java
index 3875d2e..58251e8 100644
--- a/src/com/android/launcher3/popup/RemoteActionShortcut.java
+++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.popup;
 
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.annotation.TargetApi;
@@ -76,6 +77,8 @@
     @Override
     public void onClick(View view) {
         AbstractFloatingView.closeAllOpenViews(mTarget);
+        mTarget.getStatsLogManager()
+                .log(LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP, mItemInfo.buildProto());
 
         final String actionIdentity = mAction.getTitle() + ", "
                 + mItemInfo.getTargetComponent().getPackageName();
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index ae35d4c..ea8caf5 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -1,5 +1,7 @@
 package com.android.launcher3.popup;
 
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP;
 
 import android.app.ActivityOptions;
 import android.content.Context;
@@ -27,6 +29,7 @@
 import com.android.launcher3.widget.WidgetsBottomSheet;
 
 import java.util.List;
+
 /**
  * Represents a system shortcut for a given app. The shortcut should have a label and icon, and an
  * onClickListener that depends on the item that the shortcut services.
@@ -103,7 +106,6 @@
     };
 
     public static class Widgets extends SystemShortcut<Launcher> {
-
         public Widgets(Launcher target, ItemInfo itemInfo) {
             super(R.drawable.ic_widget, R.string.widget_button_text, target, itemInfo);
         }
@@ -117,6 +119,9 @@
             widgetsBottomSheet.populateAndShow(mItemInfo);
             mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
                     ControlType.WIDGETS_BUTTON, view);
+            // TODO(thiruram): Fix missing container info when item is inside folder.
+            mTarget.getStatsLogManager().log(LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP,
+                    mItemInfo.buildProto());
         }
     }
 
@@ -137,6 +142,9 @@
                     mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle());
             mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
                     ControlType.APPINFO_TARGET, view);
+            // TODO(thiruram): Fix missing container info when item is inside folder.
+            mTarget.getStatsLogManager()
+                    .log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP, mItemInfo.buildProto());
         }
     }
 
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
index 5bf9173..b12d04f 100644
--- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
+++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
@@ -237,6 +237,24 @@
             return true;
         });
         sandboxCategory.addPreference(launchHomeTutorialPreference);
+        Preference launchOverviewTutorialPreference = new Preference(context);
+        launchOverviewTutorialPreference.setKey("launchOverviewTutorial");
+        launchOverviewTutorialPreference.setTitle("Launch Overview Tutorial");
+        launchOverviewTutorialPreference.setSummary("Learn how to use the Overview gesture");
+        launchOverviewTutorialPreference.setOnPreferenceClickListener(preference -> {
+            startActivity(launchSandboxIntent.putExtra("tutorial_type", "OVERVIEW_NAVIGATION"));
+            return true;
+        });
+        sandboxCategory.addPreference(launchOverviewTutorialPreference);
+        Preference launchAssistantTutorialPreference = new Preference(context);
+        launchAssistantTutorialPreference.setKey("launchAssistantTutorial");
+        launchAssistantTutorialPreference.setTitle("Launch Assistant Tutorial");
+        launchAssistantTutorialPreference.setSummary("Learn how to use the Assistant gesture");
+        launchAssistantTutorialPreference.setOnPreferenceClickListener(preference -> {
+            startActivity(launchSandboxIntent.putExtra("tutorial_type", "ASSISTANT"));
+            return true;
+        });
+        sandboxCategory.addPreference(launchAssistantTutorialPreference);
     }
 
     private String toName(String action) {
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index 1c49867..f90ad3c 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -69,7 +69,8 @@
             ANIM_ALL_APPS_FADE,
             ANIM_OVERVIEW_SCRIM_FADE,
             ANIM_ALL_APPS_HEADER_FADE,
-            ANIM_OVERVIEW_MODAL
+            ANIM_OVERVIEW_MODAL,
+            ANIM_DEPTH,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AnimType {}
@@ -87,8 +88,9 @@
     public static final int ANIM_OVERVIEW_SCRIM_FADE = 11;
     public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
     public static final int ANIM_OVERVIEW_MODAL = 13;
+    public static final int ANIM_DEPTH = 14;
 
-    private static final int ANIM_TYPES_COUNT = 14;
+    private static final int ANIM_TYPES_COUNT = 15;
 
     private final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
 
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 44eae56..519b1b9 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -101,4 +101,5 @@
     public static final String PERMANENT_DIAG_TAG = "TaplTarget";
     public static final String PAUSE_NOT_DETECTED = "b/139891609";
     public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
+    public static final String NO_SWIPE_TO_HOME = "b/158017601";
 }
diff --git a/src/com/android/launcher3/util/DefaultDisplay.java b/src/com/android/launcher3/util/DefaultDisplay.java
index fabdb4e..150fb5b 100644
--- a/src/com/android/launcher3/util/DefaultDisplay.java
+++ b/src/com/android/launcher3/util/DefaultDisplay.java
@@ -145,10 +145,11 @@
         }
 
         private Info(Context context) {
-            this(context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
+            this(context, context.getSystemService(DisplayManager.class)
+                    .getDisplay(DEFAULT_DISPLAY));
         }
 
-        public Info(Display display) {
+        public Info(Context context, Display display) {
             id = display.getDisplayId();
             rotation = display.getRotation();
 
@@ -161,8 +162,8 @@
             display.getRealSize(realSize);
             display.getCurrentSizeRange(smallestSize, largestSize);
 
-            metrics = new DisplayMetrics();
-            display.getMetrics(metrics);
+            Context defaultDisplayContext = context.createDisplayContext(display);
+            metrics = defaultDisplayContext.getResources().getDisplayMetrics();
         }
 
         private boolean hasDifferentSize(Info info) {