Merge "Removing static state management from the install shortcut queue" into ub-launcher3-master
diff --git a/Android.mk b/Android.mk
index 91ecccb..752b530 100644
--- a/Android.mk
+++ b/Android.mk
@@ -149,12 +149,9 @@
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src) \
     $(call all-java-files-under, quickstep/src) \
-    $(call all-java-files-under, quickstep/recents_ui_overrides/src) \
     $(call all-java-files-under, src_shortcuts_overrides)
 
-LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/quickstep/res \
-    $(LOCAL_PATH)/quickstep/recents_ui_overrides/res
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
 LOCAL_PROGUARD_ENABLED := disabled
 
 
@@ -183,9 +180,7 @@
 LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
 LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.launcher3
 
-LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/quickstep/res \
-    $(LOCAL_PATH)/quickstep/recents_ui_overrides/res
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
 
 LOCAL_FULL_LIBS_MANIFEST_FILES := \
     $(LOCAL_PATH)/quickstep/AndroidManifest-launcher.xml \
@@ -220,12 +215,10 @@
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src) \
     $(call all-java-files-under, quickstep/src) \
-    $(call all-java-files-under, quickstep/recents_ui_overrides/src) \
     $(call all-java-files-under, go/src)
 
 LOCAL_RESOURCE_DIR := \
     $(LOCAL_PATH)/quickstep/res \
-    $(LOCAL_PATH)/quickstep/recents_ui_overrides/res \
     $(LOCAL_PATH)/go/res
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/go/res/values-v26/bools.xml b/go/res/values-v26/bools.xml
deleted file mode 100644
index cc4a7ba..0000000
--- a/go/res/values-v26/bools.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources>
-    <bool name="notification_badging_enabled">false</bool>
-</resources>
\ No newline at end of file
diff --git a/go/res/values/dimens.xml b/go/res/values/dimens.xml
deleted file mode 100644
index f1b1053..0000000
--- a/go/res/values/dimens.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <!-- Dynamic Grid -->
-    <dimen name="dynamic_grid_hotseat_size">60dp</dimen>
-</resources>
\ No newline at end of file
diff --git a/go/src/com/android/launcher3/model/LoaderResults.java b/go/src/com/android/launcher3/model/LoaderResults.java
index 7130531..5f71061 100644
--- a/go/src/com/android/launcher3/model/LoaderResults.java
+++ b/go/src/com/android/launcher3/model/LoaderResults.java
@@ -20,7 +20,6 @@
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.util.LooperExecutor;
 
 /**
  * Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
@@ -29,12 +28,7 @@
 
     public LoaderResults(LauncherAppState app, BgDataModel dataModel,
             AllAppsList allAppsList, Callbacks[] callbacks) {
-        this(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
-    }
-
-    public LoaderResults(LauncherAppState app, BgDataModel dataModel,
-            AllAppsList allAppsList, Callbacks[] callbacks, LooperExecutor executor) {
-        super(app, dataModel, allAppsList, callbacks, executor);
+        super(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
     }
 
     @Override
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java
deleted file mode 100644
index 7b8070a..0000000
--- a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java
+++ /dev/null
@@ -1,317 +0,0 @@
-<<<<<<< HEAD   (cc6caf Merge "Let launcher to provide its own OverscrollPlugin" int)
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.icons.cache;
-
-import android.content.ComponentName;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseBooleanArray;
-
-import com.android.launcher3.icons.cache.BaseIconCache.IconDB;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.Stack;
-
-/**
- * Utility class to handle updating the Icon cache
- */
-public class IconCacheUpdateHandler {
-
-    private static final String TAG = "IconCacheUpdateHandler";
-
-    /**
-     * In this mode, all invalid icons are marked as to-be-deleted in {@link #mItemsToDelete}.
-     * This mode is used for the first run.
-     */
-    private static final boolean MODE_SET_INVALID_ITEMS = true;
-
-    /**
-     * In this mode, any valid icon is removed from {@link #mItemsToDelete}. This is used for all
-     * subsequent runs, which essentially acts as set-union of all valid items.
-     */
-    private static final boolean MODE_CLEAR_VALID_ITEMS = false;
-
-    private static final Object ICON_UPDATE_TOKEN = new Object();
-
-    private final HashMap<String, PackageInfo> mPkgInfoMap;
-    private final BaseIconCache mIconCache;
-
-    private final ArrayMap<UserHandle, Set<String>> mPackagesToIgnore = new ArrayMap<>();
-
-    private final SparseBooleanArray mItemsToDelete = new SparseBooleanArray();
-    private boolean mFilterMode = MODE_SET_INVALID_ITEMS;
-
-    IconCacheUpdateHandler(BaseIconCache cache) {
-        mIconCache = cache;
-
-        mPkgInfoMap = new HashMap<>();
-
-        // Remove all active icon update tasks.
-        mIconCache.mWorkerHandler.removeCallbacksAndMessages(ICON_UPDATE_TOKEN);
-
-        createPackageInfoMap();
-    }
-
-    /**
-     * Sets a package to ignore for processing
-     */
-    public void addPackagesToIgnore(UserHandle userHandle, String packageName) {
-        Set<String> packages = mPackagesToIgnore.get(userHandle);
-        if (packages == null) {
-            packages = new HashSet<>();
-            mPackagesToIgnore.put(userHandle, packages);
-        }
-        packages.add(packageName);
-    }
-
-    private void createPackageInfoMap() {
-        PackageManager pm = mIconCache.mPackageManager;
-        for (PackageInfo info :
-                pm.getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES)) {
-            mPkgInfoMap.put(info.packageName, info);
-        }
-    }
-
-    /**
-     * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in
-     * the DB and are updated.
-     * @return The set of packages for which icons have updated.
-     */
-    public <T> void updateIcons(List<T> apps, CachingLogic<T> cachingLogic,
-            OnUpdateCallback onUpdateCallback) {
-        // Filter the list per user
-        HashMap<UserHandle, HashMap<ComponentName, T>> userComponentMap = new HashMap<>();
-        int count = apps.size();
-        for (int i = 0; i < count; i++) {
-            T app = apps.get(i);
-            UserHandle userHandle = cachingLogic.getUser(app);
-            HashMap<ComponentName, T> componentMap = userComponentMap.get(userHandle);
-            if (componentMap == null) {
-                componentMap = new HashMap<>();
-                userComponentMap.put(userHandle, componentMap);
-            }
-            componentMap.put(cachingLogic.getComponent(app), app);
-        }
-
-        for (Entry<UserHandle, HashMap<ComponentName, T>> entry : userComponentMap.entrySet()) {
-            updateIconsPerUser(entry.getKey(), entry.getValue(), cachingLogic, onUpdateCallback);
-        }
-
-        // From now on, clear every valid item from the global valid map.
-        mFilterMode = MODE_CLEAR_VALID_ITEMS;
-    }
-
-    /**
-     * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in
-     * the DB and are updated.
-     * @return The set of packages for which icons have updated.
-     */
-    @SuppressWarnings("unchecked")
-    private <T> void updateIconsPerUser(UserHandle user, HashMap<ComponentName, T> componentMap,
-            CachingLogic<T> cachingLogic, OnUpdateCallback onUpdateCallback) {
-        Set<String> ignorePackages = mPackagesToIgnore.get(user);
-        if (ignorePackages == null) {
-            ignorePackages = Collections.emptySet();
-        }
-        long userSerial = mIconCache.getSerialNumberForUser(user);
-
-        Stack<T> appsToUpdate = new Stack<>();
-
-        try (Cursor c = mIconCache.mIconDb.query(
-                new String[]{IconDB.COLUMN_ROWID, IconDB.COLUMN_COMPONENT,
-                        IconDB.COLUMN_LAST_UPDATED, IconDB.COLUMN_VERSION,
-                        IconDB.COLUMN_SYSTEM_STATE},
-                IconDB.COLUMN_USER + " = ? ",
-                new String[]{Long.toString(userSerial)})) {
-
-            final int indexComponent = c.getColumnIndex(IconDB.COLUMN_COMPONENT);
-            final int indexLastUpdate = c.getColumnIndex(IconDB.COLUMN_LAST_UPDATED);
-            final int indexVersion = c.getColumnIndex(IconDB.COLUMN_VERSION);
-            final int rowIndex = c.getColumnIndex(IconDB.COLUMN_ROWID);
-            final int systemStateIndex = c.getColumnIndex(IconDB.COLUMN_SYSTEM_STATE);
-
-            while (c.moveToNext()) {
-                String cn = c.getString(indexComponent);
-                ComponentName component = ComponentName.unflattenFromString(cn);
-                PackageInfo info = mPkgInfoMap.get(component.getPackageName());
-
-                int rowId = c.getInt(rowIndex);
-                if (info == null) {
-                    if (!ignorePackages.contains(component.getPackageName())) {
-
-                        if (mFilterMode == MODE_SET_INVALID_ITEMS) {
-                            mIconCache.remove(component, user);
-                            mItemsToDelete.put(rowId, true);
-                        }
-                    }
-                    continue;
-                }
-                if ((info.applicationInfo.flags & ApplicationInfo.FLAG_IS_DATA_ONLY) != 0) {
-                    // Application is not present
-                    continue;
-                }
-
-                long updateTime = c.getLong(indexLastUpdate);
-                int version = c.getInt(indexVersion);
-                T app = componentMap.remove(component);
-                if (version == info.versionCode
-                        && updateTime == cachingLogic.getLastUpdatedTime(app, info)
-                        && TextUtils.equals(c.getString(systemStateIndex),
-                                mIconCache.getIconSystemState(info.packageName))) {
-
-                    if (mFilterMode == MODE_CLEAR_VALID_ITEMS) {
-                        mItemsToDelete.put(rowId, false);
-                    }
-                    continue;
-                }
-
-                if (app == null) {
-                    if (mFilterMode == MODE_SET_INVALID_ITEMS) {
-                        mIconCache.remove(component, user);
-                        mItemsToDelete.put(rowId, true);
-                    }
-                } else {
-                    appsToUpdate.add(app);
-                }
-            }
-        } catch (SQLiteException e) {
-            Log.d(TAG, "Error reading icon cache", e);
-            // Continue updating whatever we have read so far
-        }
-
-        // Insert remaining apps.
-        if (!componentMap.isEmpty() || !appsToUpdate.isEmpty()) {
-            Stack<T> appsToAdd = new Stack<>();
-            appsToAdd.addAll(componentMap.values());
-            new SerializedIconUpdateTask(userSerial, user, appsToAdd, appsToUpdate, cachingLogic,
-                    onUpdateCallback).scheduleNext();
-        }
-    }
-
-    /**
-     * Commits all updates as part of the update handler to disk. Not more calls should be made
-     * to this class after this.
-     */
-    public void finish() {
-        // Commit all deletes
-        int deleteCount = 0;
-        StringBuilder queryBuilder = new StringBuilder()
-                .append(IconDB.COLUMN_ROWID)
-                .append(" IN (");
-
-        int count = mItemsToDelete.size();
-        for (int i = 0;  i < count; i++) {
-            if (mItemsToDelete.valueAt(i)) {
-                if (deleteCount > 0) {
-                    queryBuilder.append(", ");
-                }
-                queryBuilder.append(mItemsToDelete.keyAt(i));
-                deleteCount++;
-            }
-        }
-        queryBuilder.append(')');
-
-        if (deleteCount > 0) {
-            mIconCache.mIconDb.delete(queryBuilder.toString(), null);
-        }
-    }
-
-    /**
-     * A runnable that updates invalid icons and adds missing icons in the DB for the provided
-     * LauncherActivityInfo list. Items are updated/added one at a time, so that the
-     * worker thread doesn't get blocked.
-     */
-    private class SerializedIconUpdateTask<T> implements Runnable {
-        private final long mUserSerial;
-        private final UserHandle mUserHandle;
-        private final Stack<T> mAppsToAdd;
-        private final Stack<T> mAppsToUpdate;
-        private final CachingLogic<T> mCachingLogic;
-        private final HashSet<String> mUpdatedPackages = new HashSet<>();
-        private final OnUpdateCallback mOnUpdateCallback;
-
-        SerializedIconUpdateTask(long userSerial, UserHandle userHandle,
-                Stack<T> appsToAdd, Stack<T> appsToUpdate, CachingLogic<T> cachingLogic,
-                OnUpdateCallback onUpdateCallback) {
-            mUserHandle = userHandle;
-            mUserSerial = userSerial;
-            mAppsToAdd = appsToAdd;
-            mAppsToUpdate = appsToUpdate;
-            mCachingLogic = cachingLogic;
-            mOnUpdateCallback = onUpdateCallback;
-        }
-
-        @Override
-        public void run() {
-            if (!mAppsToUpdate.isEmpty()) {
-                T app = mAppsToUpdate.pop();
-                String pkg = mCachingLogic.getComponent(app).getPackageName();
-                PackageInfo info = mPkgInfoMap.get(pkg);
-
-                mIconCache.addIconToDBAndMemCache(
-                        app, mCachingLogic, info, mUserSerial, true /*replace existing*/);
-                mUpdatedPackages.add(pkg);
-
-                if (mAppsToUpdate.isEmpty() && !mUpdatedPackages.isEmpty()) {
-                    // No more app to update. Notify callback.
-                    mOnUpdateCallback.onPackageIconsUpdated(mUpdatedPackages, mUserHandle);
-                }
-
-                // Let it run one more time.
-                scheduleNext();
-            } else if (!mAppsToAdd.isEmpty()) {
-                T app = mAppsToAdd.pop();
-                PackageInfo info = mPkgInfoMap.get(mCachingLogic.getComponent(app).getPackageName());
-                // We do not check the mPkgInfoMap when generating the mAppsToAdd. Although every
-                // app should have package info, this is not guaranteed by the api
-                if (info != null) {
-                    mIconCache.addIconToDBAndMemCache(app, mCachingLogic, info,
-                            mUserSerial, false /*replace existing*/);
-                }
-
-                if (!mAppsToAdd.isEmpty()) {
-                    scheduleNext();
-                }
-            }
-        }
-
-        public void scheduleNext() {
-            mIconCache.mWorkerHandler.postAtTime(this, ICON_UPDATE_TOKEN,
-                    SystemClock.uptimeMillis() + 1);
-        }
-    }
-
-    public interface OnUpdateCallback {
-
-        void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandle user);
-    }
-}
-=======
->>>>>>> CHANGE (805b52 Removes iconloaderlib from Launcher3.)
diff --git a/quickstep/recents_ui_overrides/res/values/colors.xml b/quickstep/recents_ui_overrides/res/values/colors.xml
deleted file mode 100644
index f03f118..0000000
--- a/quickstep/recents_ui_overrides/res/values/colors.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<resources>
-    <color name="chip_hint_foreground_color">#fff</color>
-    <color name="chip_scrim_start_color">#39000000</color>
-
-    <color name="all_apps_label_text">#61000000</color>
-    <color name="all_apps_label_text_dark">#61FFFFFF</color>
-    <color name="all_apps_prediction_row_separator">#3c000000</color>
-    <color name="all_apps_prediction_row_separator_dark">#3cffffff</color>
-</resources>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/res/values/config.xml b/quickstep/recents_ui_overrides/res/values/config.xml
deleted file mode 100644
index 120e034..0000000
--- a/quickstep/recents_ui_overrides/res/values/config.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<resources>
-    <integer name="max_depth_blur_radius">150</integer>
-</resources>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/res/values/dimens.xml b/quickstep/recents_ui_overrides/res/values/dimens.xml
deleted file mode 100644
index 9266b06..0000000
--- a/quickstep/recents_ui_overrides/res/values/dimens.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<resources>
-    <dimen name="chip_hint_border_width">1dp</dimen>
-    <dimen name="chip_hint_corner_radius">20dp</dimen>
-    <dimen name="chip_hint_outer_padding">20dp</dimen>
-    <dimen name="chip_hint_start_padding">10dp</dimen>
-    <dimen name="chip_hint_end_padding">12dp</dimen>
-    <dimen name="chip_hint_horizontal_margin">20dp</dimen>
-    <dimen name="chip_hint_vertical_offset">16dp</dimen>
-    <dimen name="chip_hint_elevation">2dp</dimen>
-    <dimen name="chip_icon_size">16dp</dimen>
-    <dimen name="chip_text_height">26dp</dimen>
-    <dimen name="chip_text_top_padding">4dp</dimen>
-    <dimen name="chip_text_start_padding">10dp</dimen>
-    <dimen name="chip_text_size">14sp</dimen>
-
-    <dimen name="all_apps_prediction_row_divider_height">17dp</dimen>
-    <dimen name="all_apps_label_top_padding">16dp</dimen>
-    <dimen name="all_apps_label_bottom_padding">8dp</dimen>
-    <dimen name="all_apps_label_text_size">14sp</dimen>
-
-    <!-- Minimum distance to swipe to trigger accessibility gesture -->
-    <dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
-</resources>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/REMOVED.txt b/quickstep/recents_ui_overrides/src/REMOVED.txt
new file mode 100644
index 0000000..c3a3eaf
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/REMOVED.txt
@@ -0,0 +1,2 @@
+Temp file to prevent build breakage.
+Will be removed in followup cl.
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
deleted file mode 100644
index fc9a11b..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides.states;
-
-import com.android.launcher3.Launcher;
-
-public class OverviewPeekState extends OverviewState {
-    private static final float OVERVIEW_OFFSET = 0.7f;
-
-    public OverviewPeekState(int id) {
-        super(id);
-    }
-
-    @Override
-    public float[] getOverviewScaleAndOffset(Launcher launcher) {
-        return new float[] {NO_SCALE, OVERVIEW_OFFSET};
-    }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
deleted file mode 100644
index fac478e..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides.touchcontrollers;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
-import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
-import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
-import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_PAUSE_TO_OVERVIEW_ANIM;
-import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
-import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.launcher3.util.VibratorWrapper;
-import com.android.quickstep.SystemUiProxy;
-import com.android.quickstep.util.MotionPauseDetector;
-import com.android.quickstep.views.RecentsView;
-
-/**
- * Touch controller which handles swipe and hold to go to Overview
- */
-public class FlingAndHoldTouchController extends PortraitStatesTouchController {
-
-    private static final long PEEK_IN_ANIM_DURATION = 240;
-    private static final long PEEK_OUT_ANIM_DURATION = 100;
-    private static final float MAX_DISPLACEMENT_PERCENT = 0.75f;
-
-    protected final MotionPauseDetector mMotionPauseDetector;
-    private final float mMotionPauseMinDisplacement;
-    private final float mMotionPauseMaxDisplacement;
-
-    private AnimatorSet mPeekAnim;
-
-    public FlingAndHoldTouchController(Launcher l) {
-        super(l, false /* allowDragToOverview */);
-        mMotionPauseDetector = new MotionPauseDetector(l);
-        mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
-        mMotionPauseMaxDisplacement = getMotionPauseMaxDisplacement();
-    }
-
-    protected float getMotionPauseMaxDisplacement() {
-        return getShiftRange() * MAX_DISPLACEMENT_PERCENT;
-    }
-
-    @Override
-    protected long getAtomicDuration() {
-        return QuickstepAtomicAnimationFactory.ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
-    }
-
-    @Override
-    public void onDragStart(boolean start, float startDisplacement) {
-        mMotionPauseDetector.clear();
-
-        super.onDragStart(start, startDisplacement);
-
-        if (handlingOverviewAnim()) {
-            mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseChanged);
-        }
-
-        if (mAtomicAnim != null) {
-            mAtomicAnim.cancel();
-        }
-    }
-
-    protected void onMotionPauseChanged(boolean isPaused) {
-        RecentsView recentsView = mLauncher.getOverviewPanel();
-        recentsView.setOverviewStateEnabled(isPaused);
-        if (mPeekAnim != null) {
-            mPeekAnim.cancel();
-        }
-        LauncherState fromState = isPaused ? NORMAL : OVERVIEW_PEEK;
-        LauncherState toState = isPaused ? OVERVIEW_PEEK : NORMAL;
-        long peekDuration = isPaused ? PEEK_IN_ANIM_DURATION : PEEK_OUT_ANIM_DURATION;
-
-        StateAnimationConfig config = new StateAnimationConfig();
-        config.duration = peekDuration;
-        config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK;
-        mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(
-                fromState, toState, config);
-        mPeekAnim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mPeekAnim = null;
-            }
-        });
-        mPeekAnim.start();
-        VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
-
-        mLauncher.getDragLayer().getScrim().createSysuiMultiplierAnim(isPaused ? 0 : 1)
-                .setDuration(peekDuration).start();
-    }
-
-    /**
-     * @return Whether we are handling the overview animation, rather than
-     * having it as part of the existing animation to the target state.
-     */
-    protected boolean handlingOverviewAnim() {
-        int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
-        return mStartState == NORMAL && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0;
-    }
-
-    @Override
-    protected StateAnimationConfig getConfigForStates(
-            LauncherState fromState, LauncherState toState) {
-        if (fromState == NORMAL && toState == ALL_APPS) {
-            StateAnimationConfig builder = new StateAnimationConfig();
-            // Fade in prediction icons quickly, then rest of all apps after reaching overview.
-            float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher)
-                    - OVERVIEW.getVerticalProgress(mLauncher);
-            builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
-                    ACCEL,
-                    0,
-                    ALL_APPS_CONTENT_FADE_THRESHOLD));
-            builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
-                    ACCEL,
-                    progressToReachOverview,
-                    progressToReachOverview + ALL_APPS_CONTENT_FADE_THRESHOLD));
-
-            // Get workspace out of the way quickly, to prepare for potential pause.
-            builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3);
-            builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, DEACCEL_3);
-            builder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_3);
-            return builder;
-        } else if (fromState == ALL_APPS && toState == NORMAL) {
-            StateAnimationConfig builder = new StateAnimationConfig();
-            // Keep all apps/predictions opaque until the very end of the transition.
-            float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher);
-            builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
-                    DEACCEL,
-                    progressToReachOverview - ALL_APPS_CONTENT_FADE_THRESHOLD,
-                    progressToReachOverview));
-            builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
-                    DEACCEL,
-                    1 - ALL_APPS_CONTENT_FADE_THRESHOLD,
-                    1));
-            return builder;
-        }
-        return super.getConfigForStates(fromState, toState);
-    }
-
-    @Override
-    public boolean onDrag(float displacement, MotionEvent event) {
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.PAUSE_NOT_DETECTED, "FlingAndHoldTouchController");
-        }
-        float upDisplacement = -displacement;
-        mMotionPauseDetector.setDisallowPause(!handlingOverviewAnim()
-                || upDisplacement < mMotionPauseMinDisplacement
-                || upDisplacement > mMotionPauseMaxDisplacement);
-        mMotionPauseDetector.addPosition(event);
-        return super.onDrag(displacement, event);
-    }
-
-    @Override
-    public void onDragEnd(float velocity) {
-        if (mMotionPauseDetector.isPaused() && handlingOverviewAnim()) {
-            goToOverviewOnDragEnd(velocity);
-        } else {
-            super.onDragEnd(velocity);
-        }
-
-        View searchView = mLauncher.getAppsView().getSearchView();
-        if (searchView instanceof FeedbackHandler) {
-            ((FeedbackHandler) searchView).resetFeedback();
-        }
-        mMotionPauseDetector.clear();
-    }
-
-    protected void goToOverviewOnDragEnd(float velocity) {
-        if (mPeekAnim != null) {
-            mPeekAnim.cancel();
-        }
-
-        Animator overviewAnim = mLauncher.createAtomicAnimationFactory()
-                .createStateElementAnimation(INDEX_PAUSE_TO_OVERVIEW_ANIM);
-        mAtomicAnim = new AnimatorSet();
-        mAtomicAnim.addListener(new AnimationSuccessListener() {
-            @Override
-            public void onAnimationSuccess(Animator animator) {
-                onSwipeInteractionCompleted(OVERVIEW, Touch.SWIPE);
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                if (mCancelled) {
-                    StateAnimationConfig config = new StateAnimationConfig();
-                    config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK;
-                    config.duration = PEEK_OUT_ANIM_DURATION;
-                    mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(
-                            mFromState, mToState, config);
-                    mPeekAnim.start();
-                }
-                mAtomicAnim = null;
-            }
-        });
-        mAtomicAnim.play(overviewAnim);
-        mAtomicAnim.start();
-    }
-
-    @Override
-    protected void goToTargetState(LauncherState targetState, int logAction) {
-        if (mPeekAnim != null && mPeekAnim.isStarted()) {
-            // Don't jump to the target state until overview is no longer peeking.
-            mPeekAnim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    FlingAndHoldTouchController.super.goToTargetState(targetState, logAction);
-                }
-            });
-        } else {
-            super.goToTargetState(targetState, logAction);
-        }
-    }
-
-    @Override
-    @AnimationFlags
-    protected int updateAnimComponentsOnReinit(@AnimationFlags int animComponents) {
-        if (handlingOverviewAnim()) {
-            // We don't want the state transition to all apps to animate overview,
-            // as that will cause a jump after our atomic animation.
-            return animComponents | SKIP_OVERVIEW;
-        } else {
-            return animComponents;
-        }
-    }
-
-    /**
-     * Interface for views with feedback animation requiring reset
-     */
-    public interface FeedbackHandler {
-
-        /**
-         * reset searchWidget feedback
-         */
-        void resetFeedback();
-    }
-
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ShelfPeekAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ShelfPeekAnim.java
deleted file mode 100644
index 85006da..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ShelfPeekAnim.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.util;
-
-import static com.android.launcher3.LauncherState.BACKGROUND_APP;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
-import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_SHELF_ANIM;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.view.animation.Interpolator;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.uioverrides.states.OverviewState;
-
-/**
- * Animates the shelf between states HIDE, PEEK, and OVERVIEW.
- */
-public class ShelfPeekAnim {
-
-    public static final Interpolator INTERPOLATOR = OVERSHOOT_1_2;
-    public static final long DURATION = 240;
-
-    private final Launcher mLauncher;
-
-    private ShelfAnimState mShelfState;
-    private boolean mIsPeeking;
-
-    public ShelfPeekAnim(Launcher launcher) {
-        mLauncher = launcher;
-    }
-
-    /**
-     * Animates to the given state, canceling the previous animation if it was still running.
-     */
-    public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator, long duration) {
-        if (mShelfState == shelfState || FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
-            return;
-        }
-        mLauncher.getStateManager().cancelStateElementAnimation(INDEX_SHELF_ANIM);
-        mShelfState = shelfState;
-        mIsPeeking = mShelfState == ShelfAnimState.PEEK || mShelfState == ShelfAnimState.HIDE;
-        if (mShelfState == ShelfAnimState.CANCEL) {
-            return;
-        }
-        float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(mLauncher);
-        float shelfOverviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
-        // Peek based on default overview progress so we can see hotseat if we're showing
-        // that instead of predictions in overview.
-        float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(mLauncher);
-        float shelfPeekingProgress = shelfHiddenProgress
-                - (shelfHiddenProgress - defaultOverviewProgress) * 0.25f;
-        float toProgress = mShelfState == ShelfAnimState.HIDE
-                ? shelfHiddenProgress
-                : mShelfState == ShelfAnimState.PEEK
-                        ? shelfPeekingProgress
-                        : shelfOverviewProgress;
-        Animator shelfAnim = mLauncher.getStateManager()
-                .createStateElementAnimation(INDEX_SHELF_ANIM, toProgress);
-        shelfAnim.setInterpolator(interpolator);
-        shelfAnim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mShelfState = ShelfAnimState.CANCEL;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animator) {
-                mIsPeeking = mShelfState == ShelfAnimState.PEEK;
-            }
-        });
-        shelfAnim.setDuration(duration).start();
-    }
-
-    /** @return Whether the shelf is currently peeking or animating to or from peeking. */
-    public boolean isPeeking() {
-        return mIsPeeking;
-    }
-
-    /** The various shelf states we can animate to. */
-    public enum ShelfAnimState {
-        HIDE(true), PEEK(true), OVERVIEW(false), CANCEL(false);
-
-        ShelfAnimState(boolean shouldPreformHaptic) {
-            this.shouldPreformHaptic = shouldPreformHaptic;
-        }
-
-        public final boolean shouldPreformHaptic;
-    }
-}
diff --git a/quickstep/recents_ui_overrides/res/drawable/all_apps_edu_circle.xml b/quickstep/res/drawable/all_apps_edu_circle.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/drawable/all_apps_edu_circle.xml
rename to quickstep/res/drawable/all_apps_edu_circle.xml
diff --git a/quickstep/recents_ui_overrides/res/drawable/chip_hint_background_light.xml b/quickstep/res/drawable/chip_hint_background_light.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/drawable/chip_hint_background_light.xml
rename to quickstep/res/drawable/chip_hint_background_light.xml
diff --git a/quickstep/recents_ui_overrides/res/drawable/chip_scrim_gradient.xml b/quickstep/res/drawable/chip_scrim_gradient.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/drawable/chip_scrim_gradient.xml
rename to quickstep/res/drawable/chip_scrim_gradient.xml
diff --git a/quickstep/recents_ui_overrides/res/drawable/hotseat_edu_notification_icon.xml b/quickstep/res/drawable/hotseat_edu_notification_icon.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/drawable/hotseat_edu_notification_icon.xml
rename to quickstep/res/drawable/hotseat_edu_notification_icon.xml
diff --git a/quickstep/recents_ui_overrides/res/layout/all_apps_edu_view.xml b/quickstep/res/layout/all_apps_edu_view.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/layout/all_apps_edu_view.xml
rename to quickstep/res/layout/all_apps_edu_view.xml
diff --git a/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml b/quickstep/res/layout/fallback_recents_activity.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml
rename to quickstep/res/layout/fallback_recents_activity.xml
diff --git a/quickstep/recents_ui_overrides/res/layout/floating_header_content.xml b/quickstep/res/layout/floating_header_content.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/layout/floating_header_content.xml
rename to quickstep/res/layout/floating_header_content.xml
diff --git a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/layout/overview_panel.xml
rename to quickstep/res/layout/overview_panel.xml
diff --git a/quickstep/recents_ui_overrides/res/layout/predicted_app_icon.xml b/quickstep/res/layout/predicted_app_icon.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/layout/predicted_app_icon.xml
rename to quickstep/res/layout/predicted_app_icon.xml
diff --git a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml b/quickstep/res/layout/predicted_hotseat_edu.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
rename to quickstep/res/layout/predicted_hotseat_edu.xml
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 40da136..449fe10 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -16,4 +16,12 @@
 <resources>
     <color name="back_arrow_color_light">#FFFFFFFF</color>
     <color name="back_arrow_color_dark">#99000000</color>
+
+    <color name="chip_hint_foreground_color">#fff</color>
+    <color name="chip_scrim_start_color">#39000000</color>
+
+    <color name="all_apps_label_text">#61000000</color>
+    <color name="all_apps_label_text_dark">#61FFFFFF</color>
+    <color name="all_apps_prediction_row_separator">#3c000000</color>
+    <color name="all_apps_prediction_row_separator_dark">#3cffffff</color>
 </resources>
\ No newline at end of file
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 0f2955b..9ec303a 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -16,6 +16,8 @@
 <resources>
     <string name="task_overlay_factory_class" translatable="false"/>
 
+    <string name="overscroll_plugin_factory_class" translatable="false" />
+
     <!-- Activities which block home gesture -->
     <string-array name="gesture_blocking_activities" translatable="false">
         <item>com.android.launcher3/com.android.quickstep.interaction.GestureSandboxActivity</item>
@@ -35,4 +37,6 @@
     <integer name="assistant_gesture_corner_deg_threshold">20</integer>
 
     <string name="wellbeing_provider_pkg" translatable="false"/>
+
+    <integer name="max_depth_blur_radius">150</integer>
 </resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 6737c5f..313db8c 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -30,7 +30,6 @@
 
     <dimen name="recents_page_spacing">10dp</dimen>
     <dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
-    <dimen name="overview_peek_distance">96dp</dimen>
 
     <!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
              loading full resolution screenshots. -->
@@ -102,4 +101,26 @@
     <dimen name="swipe_edu_circle_size">64dp</dimen>
     <dimen name="swipe_edu_width">80dp</dimen>
     <dimen name="swipe_edu_max_height">184dp</dimen>
+
+    <dimen name="chip_hint_border_width">1dp</dimen>
+    <dimen name="chip_hint_corner_radius">20dp</dimen>
+    <dimen name="chip_hint_outer_padding">20dp</dimen>
+    <dimen name="chip_hint_start_padding">10dp</dimen>
+    <dimen name="chip_hint_end_padding">12dp</dimen>
+    <dimen name="chip_hint_horizontal_margin">20dp</dimen>
+    <dimen name="chip_hint_vertical_offset">16dp</dimen>
+    <dimen name="chip_hint_elevation">2dp</dimen>
+    <dimen name="chip_icon_size">16dp</dimen>
+    <dimen name="chip_text_height">26dp</dimen>
+    <dimen name="chip_text_top_padding">4dp</dimen>
+    <dimen name="chip_text_start_padding">10dp</dimen>
+    <dimen name="chip_text_size">14sp</dimen>
+
+    <dimen name="all_apps_prediction_row_divider_height">17dp</dimen>
+    <dimen name="all_apps_label_top_padding">16dp</dimen>
+    <dimen name="all_apps_label_bottom_padding">8dp</dimen>
+    <dimen name="all_apps_label_text_size">14sp</dimen>
+
+    <!-- Minimum distance to swipe to trigger accessibility gesture -->
+    <dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
 </resources>
diff --git a/quickstep/recents_ui_overrides/res/values/override.xml b/quickstep/res/values/override.xml
similarity index 99%
rename from quickstep/recents_ui_overrides/res/values/override.xml
rename to quickstep/res/values/override.xml
index 1937164..397ea82 100644
--- a/quickstep/recents_ui_overrides/res/values/override.xml
+++ b/quickstep/res/values/override.xml
@@ -32,4 +32,3 @@
   <string name="model_delegate_class" translatable="false">com.android.launcher3.model.QuickstepModelDelegate</string>
 
 </resources>
-
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
index 22d205a..5cb55ec 100644
--- a/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
@@ -32,7 +32,7 @@
 import android.view.Surface;
 
 import com.android.launcher3.ResourceUtils;
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -50,7 +50,7 @@
     private OrientationTouchTransformer mTouchTransformer;
 
     Resources mResources;
-    private DefaultDisplay.Info mInfo;
+    private DisplayController.Info mInfo;
 
 
     @Before
@@ -231,12 +231,12 @@
         assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
     }
 
-    private DefaultDisplay.Info createDisplayInfo(int rotation) {
+    private DisplayController.Info createDisplayInfo(int rotation) {
         Point p = new Point(SIZE_WIDTH, SIZE_HEIGHT);
         if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
             p = new Point(SIZE_HEIGHT, SIZE_WIDTH);
         }
-        return new DefaultDisplay.Info(0, rotation, 0, p, p, p, null);
+        return new DisplayController.Info(0, rotation, 0, p, p, p, null);
     }
 
     private float generateTouchRegionHeight(int rotation) {
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index a31ba21..5491daa 100644
--- a/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -27,7 +27,7 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.shadows.LShadowDisplay;
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.LauncherActivityInterface;
 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
 
@@ -144,7 +144,7 @@
                     LauncherActivityInterface.INSTANCE);
             tvs.setDp(mDeviceProfile);
 
-            int launcherRotation = DefaultDisplay.INSTANCE.get(mContext).getInfo().rotation;
+            int launcherRotation = DisplayController.INSTANCE.get(mContext).getInfo().rotation;
             if (mAppRotation < 0) {
                 mAppRotation = launcherRotation;
             }
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 235df42..a0016cb 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -50,7 +50,6 @@
 import com.android.quickstep.util.QuickstepOnboardingPrefs;
 import com.android.quickstep.util.RemoteAnimationProvider;
 import com.android.quickstep.util.RemoteFadeOutAnimationListener;
-import com.android.quickstep.util.ShelfPeekAnim;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -73,8 +72,6 @@
             (context, arg1, arg2) -> SystemUiProxy.INSTANCE.get(context).setBackButtonAlpha(
                     Float.intBitsToFloat(arg1), arg2 != 0);
 
-    private final ShelfPeekAnim mShelfPeekAnim = new ShelfPeekAnim(this);
-
     private OverviewActionsView mActionsView;
     protected HotseatPredictionController mHotseatPredictionController;
 
@@ -196,7 +193,7 @@
     }
 
     private boolean isOverviewActionsEnabled() {
-        return FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this);
+        return removeShelfFromOverview(this);
     }
 
     public <T extends OverviewActionsView> T getActionsView() {
@@ -317,10 +314,6 @@
                 Stream.of(WellbeingModel.SHORTCUT_FACTORY));
     }
 
-    public ShelfPeekAnim getShelfPeekAnim() {
-        return mShelfPeekAnim;
-    }
-
     /**
      * Returns Prediction controller for hybrid hotseat
      */
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 5ad0bca..199cf63 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -16,7 +16,7 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.Utilities.postAsyncCallback;
-import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
+import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
 
 import android.animation.Animator;
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
rename to quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java b/quickstep/src/com/android/launcher3/appprediction/AllAppsTipView.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
rename to quickstep/src/com/android/launcher3/appprediction/AllAppsTipView.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
rename to quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/ComponentKeyMapper.java b/quickstep/src/com/android/launcher3/appprediction/ComponentKeyMapper.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/ComponentKeyMapper.java
rename to quickstep/src/com/android/launcher3/appprediction/ComponentKeyMapper.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java b/quickstep/src/com/android/launcher3/appprediction/DynamicItemCache.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java
rename to quickstep/src/com/android/launcher3/appprediction/DynamicItemCache.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/InstantAppItemInfo.java b/quickstep/src/com/android/launcher3/appprediction/InstantAppItemInfo.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/InstantAppItemInfo.java
rename to quickstep/src/com/android/launcher3/appprediction/InstantAppItemInfo.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java
rename to quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java
rename to quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
similarity index 99%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
rename to quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index 4f95254..8ebf125 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -284,4 +284,3 @@
         return new Intent(SETTINGS_ACTION).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     }
 }
-
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
rename to quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatFileLog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatFileLog.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatFileLog.java
rename to quickstep/src/com/android/launcher3/hybridhotseat/HotseatFileLog.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
rename to quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
rename to quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java
rename to quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/model/AppEventProducer.java
rename to quickstep/src/com/android/launcher3/model/AppEventProducer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/model/PredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/model/PredictionUpdateTask.java
rename to quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/model/QuickstepModelDelegate.java
rename to quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
rename to quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIconInflater.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIconInflater.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIconInflater.java
rename to quickstep/src/com/android/launcher3/uioverrides/PredictedAppIconInflater.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
similarity index 96%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
rename to quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 4107698..f7bc0b3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -60,7 +60,6 @@
 import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
-import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController;
 import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController;
 import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
 import com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController;
@@ -80,8 +79,8 @@
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
-
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -306,14 +305,7 @@
             if (TestProtocol.sDebugTracing) {
                 Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.2");
             }
-            if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
-                if (TestProtocol.sDebugTracing) {
-                    Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.3");
-                }
-                list.add(new NoButtonNavbarToOverviewTouchController(this));
-            } else {
-                list.add(new FlingAndHoldTouchController(this));
-            }
+            list.add(new NoButtonNavbarToOverviewTouchController(this));
         } else {
             if (getDeviceProfile().isVerticalBarLayout()) {
                 list.add(new OverviewToAllAppsTouchController(this));
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
rename to quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index e7cd393..bce73cd 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -16,8 +16,7 @@
 package com.android.launcher3.uioverrides.states;
 
 import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
-import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
+import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
 
 import android.content.Context;
 
@@ -25,7 +24,6 @@
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.quickstep.SysUINavigationMode;
 
 /**
  * Definition for AllApps state
@@ -65,13 +63,7 @@
     public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
         ScaleAndTranslation scaleAndTranslation = LauncherState.OVERVIEW
                 .getWorkspaceScaleAndTranslation(launcher);
-        if (SysUINavigationMode.getMode(launcher) == NO_BUTTON && !ENABLE_OVERVIEW_ACTIONS.get()) {
-            float normalScale = 1;
-            // Scale down halfway to where we'd be in overview, to prepare for a potential pause.
-            scaleAndTranslation.scale = (scaleAndTranslation.scale + normalScale) / 2;
-        } else {
-            scaleAndTranslation.scale = 1;
-        }
+        scaleAndTranslation.scale = 1;
         return scaleAndTranslation;
     }
 
@@ -92,7 +84,8 @@
 
     @Override
     public float[] getOverviewScaleAndOffset(Launcher launcher) {
-        return new float[] {0.9f, 0};
+        float offset = removeShelfFromOverview(launcher) ? 1 : 0;
+        return new float[] {0.9f, offset};
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
rename to quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
rename to quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
similarity index 94%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
rename to quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index d174bfd..6ec114e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.uioverrides.states;
 
 import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
 import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
 import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
 import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
@@ -65,7 +64,7 @@
     public int getTransitionDuration(Context context) {
         // In no-button mode, overview comes in all the way from the left, so give it more time.
         boolean isNoButtonMode = SysUINavigationMode.INSTANCE.get(context).getMode() == NO_BUTTON;
-        return isNoButtonMode && ENABLE_OVERVIEW_ACTIONS.get() ? 380 : 250;
+        return isNoButtonMode ? 380 : 250;
     }
 
     @Override
@@ -108,8 +107,7 @@
 
     @Override
     public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) {
-        if (this == OVERVIEW && ENABLE_OVERVIEW_ACTIONS.get()
-                && removeShelfFromOverview(launcher)) {
+        if (this == OVERVIEW && removeShelfFromOverview(launcher)) {
             // Treat the QSB as part of the hotseat so they move together.
             return getHotseatScaleAndTranslation(launcher);
         }
@@ -129,7 +127,7 @@
     @Override
     public int getVisibleElements(Launcher launcher) {
         RecentsView recentsView = launcher.getOverviewPanel();
-        if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(launcher) ||
+        if (removeShelfFromOverview(launcher) ||
                 hideShelfInTwoButtonLandscape(launcher, recentsView.getPagedOrientationHandler())) {
             return OVERVIEW_BUTTONS;
         } else if (launcher.getDeviceProfile().isVerticalBarLayout()) {
@@ -191,10 +189,6 @@
         return new BackgroundAppState(id);
     }
 
-    public static OverviewState newPeekState(int id) {
-        return new OverviewPeekState(id);
-    }
-
     public static OverviewState newSwitchState(int id) {
         return new QuickSwitchState(id);
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
rename to quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
similarity index 88%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
rename to quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index daa1aad..94af134 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -22,28 +22,24 @@
 import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
 import static com.android.launcher3.WorkspaceStateTransitionAnimation.getSpringScaleAnimator;
 import static com.android.launcher3.anim.Interpolators.ACCEL;
 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.anim.Interpolators.DEACCEL;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_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;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
@@ -190,23 +186,14 @@
             if (!isHotseatVisible) {
                 hotseat.setScaleX(0.92f);
                 hotseat.setScaleY(0.92f);
-                if (ENABLE_OVERVIEW_ACTIONS.get()) {
-                    AllAppsContainerView qsbContainer = mActivity.getAppsView();
-                    View qsb = qsbContainer.getSearchView();
-                    boolean qsbVisible = qsb.getVisibility() == VISIBLE && qsb.getAlpha() > 0;
-                    if (!qsbVisible) {
-                        qsbContainer.setScaleX(0.92f);
-                        qsbContainer.setScaleY(0.92f);
-                    }
+                AllAppsContainerView qsbContainer = mActivity.getAppsView();
+                View qsb = qsbContainer.getSearchView();
+                boolean qsbVisible = qsb.getVisibility() == VISIBLE && qsb.getAlpha() > 0;
+                if (!qsbVisible) {
+                    qsbContainer.setScaleX(0.92f);
+                    qsbContainer.setScaleY(0.92f);
                 }
             }
-        } else if (toState == NORMAL && fromState == OVERVIEW_PEEK) {
-            // Keep fully visible until the very end (when overview is offscreen) to make invisible.
-            config.setInterpolator(ANIM_OVERVIEW_FADE, FINAL_FRAME);
-        } else if (toState == OVERVIEW_PEEK && fromState == NORMAL) {
-            config.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
-            config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
-            config.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN);
         } else if ((fromState == NORMAL || fromState == HINT_STATE) && toState == OVERVIEW) {
             if (SysUINavigationMode.getMode(mActivity) == NO_BUTTON) {
                 config.setInterpolator(ANIM_WORKSPACE_SCALE,
@@ -227,8 +214,7 @@
             config.setInterpolator(ANIM_ALL_APPS_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)
+            Interpolator translationInterpolator = removeShelfFromOverview(mActivity)
                     ? OVERSHOOT_1_2
                     : OVERSHOOT_1_7;
             config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
similarity index 64%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index dbff20a..591d3ca 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -16,30 +16,44 @@
 
 package com.android.launcher3.uioverrides.touchcontrollers;
 
+import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.HINT_STATE;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
 import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.graphics.PointF;
 import android.util.Log;
 import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.graphics.OverviewScrim;
-import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.launcher3.util.VibratorWrapper;
+import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
+import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.OverviewToHomeAnim;
 import com.android.quickstep.views.RecentsView;
 
@@ -48,7 +62,7 @@
  * the nav bar falls back to go to All Apps. Swiping from the nav bar without holding goes to the
  * first home screen instead of to Overview.
  */
-public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchController {
+public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouchController {
 
 
     // How much of the movement to use for translating overview after swipe and hold.
@@ -57,6 +71,8 @@
     private static final float TRANSLATION_ANIM_VELOCITY_DP_PER_MS = 0.8f;
 
     private final RecentsView mRecentsView;
+    private final MotionPauseDetector mMotionPauseDetector;
+    private final float mMotionPauseMinDisplacement;
 
     private boolean mDidTouchStartInNavBar;
     private boolean mReachedOverview;
@@ -69,21 +85,16 @@
     private ObjectAnimator mNormalToHintOverviewScrimAnimator;
 
     public NoButtonNavbarToOverviewTouchController(Launcher l) {
-        super(l);
+        super(l, false /* allowDragToOverview */);
         mRecentsView = l.getOverviewPanel();
+        mMotionPauseDetector = new MotionPauseDetector(l);
+        mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
         if (TestProtocol.sDebugTracing) {
             Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NoButtonNavbarToOverviewTouchController.ctor");
         }
     }
 
     @Override
-    protected float getMotionPauseMaxDisplacement() {
-        // No need to disallow pause when swiping up all the way up the screen (unlike
-        // FlingAndHoldTouchController where user is probably intending to go to all apps).
-        return Float.MAX_VALUE;
-    }
-
-    @Override
     protected boolean canInterceptTouch(MotionEvent ev) {
         mDidTouchStartInNavBar = (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
         return super.canInterceptTouch(ev);
@@ -113,6 +124,13 @@
     @Override
     public void onDragStart(boolean start, float startDisplacement) {
         super.onDragStart(start, startDisplacement);
+
+        mMotionPauseDetector.clear();
+
+        if (handlingOverviewAnim()) {
+            mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseChanged);
+        }
+
         if (mFromState == NORMAL && mToState == HINT_STATE) {
             mNormalToHintOverviewScrimAnimator = ObjectAnimator.ofFloat(
                     mLauncher.getDragLayer().getOverviewScrim(),
@@ -134,8 +152,24 @@
 
     @Override
     public void onDragEnd(float velocity) {
-        super.onDragEnd(velocity);
+        if (mMotionPauseDetector.isPaused() && handlingOverviewAnim()) {
+            goToOverviewOrHomeOnDragEnd(velocity);
+        } else {
+            super.onDragEnd(velocity);
+        }
+
+        View searchView = mLauncher.getAppsView().getSearchView();
+        if (searchView instanceof FeedbackHandler) {
+            ((FeedbackHandler) searchView).resetFeedback();
+        }
+
+        mMotionPauseDetector.clear();
         mNormalToHintOverviewScrimAnimator = null;
+        if (mLauncher.isInState(OVERVIEW)) {
+            // Normally we would cleanup the state based on mCurrentAnimation, but since we stop
+            // using that when we pause to go to Overview, we need to clean up ourselves.
+            clearState();
+        }
     }
 
     @Override
@@ -151,8 +185,7 @@
         }
     }
 
-    @Override
-    protected void onMotionPauseChanged(boolean isPaused) {
+    private void onMotionPauseChanged(boolean isPaused) {
         if (mCurrentAnimation == null) {
             return;
         }
@@ -175,9 +208,10 @@
         }
     }
 
-    @Override
-    protected boolean handlingOverviewAnim() {
-        return mDidTouchStartInNavBar && super.handlingOverviewAnim();
+    private boolean handlingOverviewAnim() {
+        int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
+        return mDidTouchStartInNavBar && mStartState == NORMAL
+                && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0;
     }
 
     @Override
@@ -203,14 +237,18 @@
             // Stay in Overview.
             return true;
         }
+
+        float upDisplacement = -yDisplacement;
+        mMotionPauseDetector.setDisallowPause(!handlingOverviewAnim()
+                || upDisplacement < mMotionPauseMinDisplacement);
+        mMotionPauseDetector.addPosition(event);
+
         return super.onDrag(yDisplacement, xDisplacement, event);
     }
 
-    @Override
-    protected void goToOverviewOnDragEnd(float velocity) {
+    private void goToOverviewOrHomeOnDragEnd(float velocity) {
         float velocityDp = dpiFromPx(velocity);
         boolean isFling = Math.abs(velocityDp) > 1;
-        StateManager<LauncherState> stateManager = mLauncher.getStateManager();
         boolean goToHomeInsteadOfOverview = isFling;
         if (goToHomeInsteadOfOverview) {
             new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL, Touch.FLING))
@@ -243,4 +281,54 @@
     private float dpiFromPx(float pixels) {
         return Utilities.dpiFromPx(pixels, mLauncher.getResources().getDisplayMetrics());
     }
+
+    @Override
+    protected StateAnimationConfig getConfigForStates(
+            LauncherState fromState, LauncherState toState) {
+        if (fromState == NORMAL && toState == ALL_APPS) {
+            StateAnimationConfig builder = new StateAnimationConfig();
+            // Fade in prediction icons quickly, then rest of all apps after reaching overview.
+            float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher)
+                    - OVERVIEW.getVerticalProgress(mLauncher);
+            builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
+                    ACCEL,
+                    0,
+                    ALL_APPS_CONTENT_FADE_THRESHOLD));
+            builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
+                    ACCEL,
+                    progressToReachOverview,
+                    progressToReachOverview + ALL_APPS_CONTENT_FADE_THRESHOLD));
+
+            // Get workspace out of the way quickly, to prepare for potential pause.
+            builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3);
+            builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, DEACCEL_3);
+            builder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_3);
+            return builder;
+        } else if (fromState == ALL_APPS && toState == NORMAL) {
+            StateAnimationConfig builder = new StateAnimationConfig();
+            // Keep all apps/predictions opaque until the very end of the transition.
+            float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher);
+            builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
+                    DEACCEL,
+                    progressToReachOverview - ALL_APPS_CONTENT_FADE_THRESHOLD,
+                    progressToReachOverview));
+            builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
+                    DEACCEL,
+                    1 - ALL_APPS_CONTENT_FADE_THRESHOLD,
+                    1));
+            return builder;
+        }
+        return super.getConfigForStates(fromState, toState);
+    }
+
+    /**
+     * Interface for views with feedback animation requiring reset
+     */
+    public interface FeedbackHandler {
+
+        /**
+         * reset searchWidget feedback
+         */
+        void resetFeedback();
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
similarity index 90%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 5c9fd47..4b0642f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.uioverrides.touchcontrollers;
 
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.LauncherState.OVERVIEW_BUTTONS;
@@ -25,7 +24,6 @@
 import static com.android.launcher3.anim.Interpolators.DEACCEL_5;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEDOWN;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEUP;
@@ -38,11 +36,8 @@
 import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
 import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
 import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_PAUSE_TO_OVERVIEW_ANIM;
-import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
+import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
-import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.CANCEL;
-import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
-import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
@@ -60,10 +55,8 @@
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.OverviewScrim;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.states.StateAnimationConfig;
@@ -79,8 +72,6 @@
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.MotionPauseDetector;
-import com.android.quickstep.util.ShelfPeekAnim;
-import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
 import com.android.quickstep.util.StaggeredWorkspaceAnim;
 import com.android.quickstep.views.LauncherRecentsView;
 
@@ -99,7 +90,6 @@
 
     private final BaseQuickstepLauncher mLauncher;
     private final BothAxesSwipeDetector mSwipeDetector;
-    private final ShelfPeekAnim mShelfPeekAnim;
     private final float mXRange;
     private final float mYRange;
     private final float mMaxYProgress;
@@ -121,7 +111,6 @@
     public NoButtonQuickSwitchTouchController(BaseQuickstepLauncher launcher) {
         mLauncher = launcher;
         mSwipeDetector = new BothAxesSwipeDetector(mLauncher, this);
-        mShelfPeekAnim = mLauncher.getShelfPeekAnim();
         mRecentsView = mLauncher.getOverviewPanel();
         mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
         mYRange = LayoutUtils.getShelfTrackingDistance(
@@ -191,25 +180,6 @@
     @Override
     public void onMotionPauseChanged(boolean isPaused) {
         VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
-
-        if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
-            return;
-        }
-
-        ShelfAnimState shelfState = isPaused ? PEEK : HIDE;
-        if (shelfState == PEEK) {
-            // Some shelf elements (e.g. qsb) were hidden, but we need them visible when peeking.
-            AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
-            allAppsController.setAlphas(
-                    NORMAL, new StateAnimationConfig(), NO_ANIM_PROPERTY_SETTER);
-
-            if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
-                // Hotseat was hidden, but we need it visible when peeking.
-                mLauncher.getHotseat().setAlpha(1);
-            }
-        }
-        mShelfPeekAnim.setShelfState(shelfState, ShelfPeekAnim.INTERPOLATOR,
-                ShelfPeekAnim.DURATION);
     }
 
     private void setupAnimators() {
@@ -301,10 +271,6 @@
         mIsHomeScreenVisible = FADE_OUT_INTERPOLATOR.getInterpolation(xProgress)
                 <= 1 - ALPHA_CUTOFF_THRESHOLD;
 
-        if (wasHomeScreenVisible && !mIsHomeScreenVisible) {
-            // Get the shelf all the way offscreen so it pops up when we decide to peek it.
-            mShelfPeekAnim.setShelfState(HIDE, LINEAR, 0);
-        }
 
         // Only allow motion pause if the home screen is invisible, since some
         // home screen elements will appear in the shelf on motion pause.
@@ -312,11 +278,6 @@
                 || -displacement.y < mMotionPauseMinDisplacement);
         mMotionPauseDetector.addPosition(ev);
 
-        if (mIsHomeScreenVisible) {
-            // Cancel the shelf anim so it doesn't clobber mNonOverviewAnim.
-            mShelfPeekAnim.setShelfState(CANCEL, LINEAR, 0);
-        }
-
         if (mXOverviewAnim != null) {
             mXOverviewAnim.setPlayFraction(xProgress);
         }
@@ -474,7 +435,6 @@
         if (mYOverviewAnim != null) {
             mYOverviewAnim.cancelAnimation();
         }
-        mShelfPeekAnim.setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
         mMotionPauseDetector.clear();
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 20ee61d..1208c6c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -24,7 +24,6 @@
 import static com.android.launcher3.anim.Interpolators.ACCEL;
 import static com.android.launcher3.anim.Interpolators.DEACCEL;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
 import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
@@ -142,6 +141,10 @@
                 Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
                         "PortraitStatesTouchController.getTargetState 1");
             }
+            if (removeShelfFromOverview(mLauncher)) {
+                // Don't allow swiping down to overview.
+                return NORMAL;
+            }
             return TouchInteractionService.isConnected() ?
                     mLauncher.getStateManager().getLastState() : NORMAL;
         } else if (fromState == OVERVIEW) {
@@ -150,7 +153,7 @@
                         "PortraitStatesTouchController.getTargetState 2");
             }
             LauncherState positiveDragTarget = ALL_APPS;
-            if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(mLauncher)) {
+            if (removeShelfFromOverview(mLauncher)) {
                 // Don't allow swiping up to all apps.
                 positiveDragTarget = OVERVIEW;
             }
@@ -245,7 +248,7 @@
 
         final StateAnimationConfig config = totalShift == 0 ? new StateAnimationConfig()
                 : getConfigForStates(mFromState, mToState);
-        config.animFlags = updateAnimComponentsOnReinit(animFlags);
+        config.animFlags = animFlags;
         config.duration = maxAccuracy;
 
         cancelPendingAnim();
@@ -279,14 +282,6 @@
         return 1 / totalShift;
     }
 
-    /**
-     * Give subclasses the chance to update the animation when we re-initialize towards a new state.
-     */
-    @AnimationFlags
-    protected int updateAnimComponentsOnReinit(@AnimationFlags int animComponents) {
-        return animComponents;
-    }
-
     private void cancelPendingAnim() {
         if (mPendingAnimation != null) {
             mPendingAnimation.finish(false, Touch.SWIPE);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
similarity index 97%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/AbsSwipeUpHandler.java
rename to quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index d2fee30..aaa2720 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -20,7 +20,6 @@
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
 import static com.android.launcher3.anim.Interpolators.DEACCEL;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -29,7 +28,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
-import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
+import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
 import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
@@ -41,8 +40,6 @@
 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.util.ShelfPeekAnim.ShelfAnimState.HIDE;
-import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
 
@@ -93,8 +90,6 @@
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.InputConsumerProxy;
 import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.util.ShelfPeekAnim;
-import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.TransformParams;
 import com.android.quickstep.views.LiveTileOverlay;
@@ -205,7 +200,7 @@
 
     // Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
     private RunningWindowAnim mRunningWindowAnim;
-    private boolean mIsShelfPeeking;
+    private boolean mIsMotionPaused;
 
     private boolean mContinuingLastGesture;
 
@@ -491,7 +486,9 @@
      * Called when motion pause is detected
      */
     public void onMotionPauseChanged(boolean isPaused) {
-        setShelfState(isPaused ? PEEK : HIDE, ShelfPeekAnim.INTERPOLATOR, ShelfPeekAnim.DURATION);
+        mIsMotionPaused = isPaused;
+        maybeUpdateRecentsAttachedState();
+        performHapticFeedback();
     }
 
     public void maybeUpdateRecentsAttachedState() {
@@ -522,7 +519,7 @@
             // The window is going away so make sure recents is always visible in this case.
             recentsAttachedToAppWindow = true;
         } else {
-            recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask;
+            recentsAttachedToAppWindow = mIsMotionPaused || mIsLikelyToStartNewTask;
         }
         mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
 
@@ -552,19 +549,6 @@
         }
     }
 
-    @UiThread
-    public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator, long duration) {
-        mAnimationFactory.setShelfState(shelfState, interpolator, duration);
-        boolean wasShelfPeeking = mIsShelfPeeking;
-        mIsShelfPeeking = shelfState == PEEK;
-        if (mIsShelfPeeking != wasShelfPeeking) {
-            maybeUpdateRecentsAttachedState();
-        }
-        if (shelfState.shouldPreformHaptic) {
-            performHapticFeedback();
-        }
-    }
-
     private void buildAnimationController() {
         if (!canCreateNewOrUpdateExistingLauncherTransitionController()) {
             return;
@@ -852,7 +836,7 @@
             if (isCancel) {
                 endTarget = LAST_TASK;
             } else if (mDeviceState.isFullyGesturalNavMode()) {
-                if (mIsShelfPeeking) {
+                if (mIsMotionPaused) {
                     endTarget = RECENTS;
                 } else if (goingToNewTask) {
                     endTarget = NEW_TASK;
@@ -874,7 +858,7 @@
 
             if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp && !willGoToNewTaskOnSwipeUp) {
                 endTarget = HOME;
-            } else if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp && !mIsShelfPeeking) {
+            } else if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp && !mIsMotionPaused) {
                 // If swiping at a diagonal, base end target on the faster velocity.
                 endTarget = NEW_TASK;
             } else if (isSwipeUp) {
@@ -942,7 +926,6 @@
             mInputConsumerProxy.enable();
         }
         if (endTarget == HOME) {
-            setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
             duration = Math.max(MIN_OVERSHOOT_DURATION, duration);
         } else if (endTarget == RECENTS) {
             LiveTileOverlay.INSTANCE.startIconAnimation();
@@ -958,9 +941,6 @@
                 }
                 duration = Math.max(duration, mRecentsView.getScroller().getDuration());
             }
-            if (mDeviceState.isFullyGesturalNavMode()) {
-                setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration);
-            }
         }
 
         // Let RecentsView handle the scrolling to the task, which we launch in startNewTask()
@@ -1059,6 +1039,7 @@
         }
 
         if (mGestureState.getEndTarget() == HOME) {
+            mTaskViewSimulator.setDrawsBelowRecents(false);
             HomeAnimationFactory homeAnimFactory = createHomeAnimationFactory(duration);
             RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
             windowAnim.addAnimatorListener(new AnimationSuccessListener() {
@@ -1266,7 +1247,6 @@
     }
 
     private void endLauncherTransitionController() {
-        setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
         if (mLauncherTransitionController != null) {
             // End the animation, but stay at the same visual progress.
             mLauncherTransitionController.getNormalController().dispatchSetInterpolator(
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
rename to quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 1a4620b..8b108ac 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -18,7 +18,6 @@
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
 import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
 import static com.android.quickstep.SysUINavigationMode.getMode;
 import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
@@ -37,7 +36,6 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.view.MotionEvent;
-import android.view.animation.Interpolator;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
@@ -54,7 +52,6 @@
 import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
-import com.android.quickstep.util.ShelfPeekAnim;
 import com.android.quickstep.util.SplitScreenBounds;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -299,9 +296,6 @@
 
         default void onTransitionCancelled() { }
 
-        default void setShelfState(ShelfPeekAnim.ShelfAnimState animState,
-                Interpolator interpolator, long duration) { }
-
         /**
          * @param attached Whether to show RecentsView alongside the app window. If false, recents
          *                 will be hidden by some property we can animate, e.g. alpha.
@@ -409,6 +403,6 @@
     }
 
     protected static boolean showOverviewActions(Context context) {
-        return ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context);
+        return removeShelfFromOverview(context);
     }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
rename to quickstep/src/com/android/quickstep/FallbackActivityInterface.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
rename to quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/ImageActionsApi.java b/quickstep/src/com/android/quickstep/ImageActionsApi.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/ImageActionsApi.java
rename to quickstep/src/com/android/quickstep/ImageActionsApi.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
similarity index 96%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
rename to quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 4e38f49..036d473 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -27,7 +27,6 @@
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.util.Log;
-import android.view.animation.Interpolator;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
@@ -50,7 +49,6 @@
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.LayoutUtils;
-import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.plugins.shared.LauncherOverlayManager;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -122,12 +120,6 @@
         notifyRecentsOfOrientation(deviceState.getRotationTouchHelper());
         DefaultAnimationFactory factory = new DefaultAnimationFactory(callback) {
             @Override
-            public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator,
-                    long duration) {
-                mActivity.getShelfPeekAnim().setShelfState(shelfState, interpolator, duration);
-            }
-
-            @Override
             protected void createBackgroundToOverviewAnim(BaseQuickstepLauncher activity,
                     PendingAnimation pa) {
                 super.createBackgroundToOverviewAnim(activity, pa);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandlerV2.java
rename to quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index b2bce0c..eb33f98 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -37,7 +37,7 @@
 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.launcher3.util.DisplayController.Info;
 
 import java.io.PrintWriter;
 
@@ -85,7 +85,7 @@
      * QUICKSTEP_ROTATION_UNINITIALIZED, then user has not tapped on an active nav region.
      * Otherwise it will be the rotation of the display when the user first interacted with the
      * active nav bar region.
-     * The "session" ends when {@link #enableMultipleRegions(boolean, DefaultDisplay.Info)} is
+     * The "session" ends when {@link #enableMultipleRegions(boolean, Info)} is
      * called - usually from a timeout or if user starts interacting w/ the foreground app.
      *
      * This is different than {@link #mLastRectTouched} as it can get reset by the system whereas
@@ -108,7 +108,7 @@
         mNavBarGesturalHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
     }
 
-    private void refreshTouchRegion(DefaultDisplay.Info info, Resources newRes) {
+    private void refreshTouchRegion(Info info, Resources newRes) {
         // Swipe touch regions are independent of nav mode, so we have to clear them explicitly
         // here to avoid, for ex, a nav region for 2-button rotation 0 being used for 3-button mode
         // It tries to cache and reuse swipe regions whenever possible based only on rotation
@@ -117,7 +117,7 @@
         resetSwipeRegions(info);
     }
 
-    void setNavigationMode(SysUINavigationMode.Mode newMode, DefaultDisplay.Info info,
+    void setNavigationMode(SysUINavigationMode.Mode newMode, Info info,
             Resources newRes) {
         if (mMode == newMode) {
             return;
@@ -126,7 +126,7 @@
         refreshTouchRegion(info, newRes);
     }
 
-    void setGesturalHeight(int newGesturalHeight, DefaultDisplay.Info info, Resources newRes) {
+    void setGesturalHeight(int newGesturalHeight, Info info, Resources newRes) {
         if (mNavBarGesturalHeight == newGesturalHeight) {
             return;
         }
@@ -140,9 +140,9 @@
      * alongside other regions.
      * Ok to call multiple times
      *
-     * @see #enableMultipleRegions(boolean, DefaultDisplay.Info)
+     * @see #enableMultipleRegions(boolean, Info)
      */
-    void createOrAddTouchRegion(DefaultDisplay.Info info) {
+    void createOrAddTouchRegion(Info info) {
         mCurrentDisplayRotation = info.rotation;
         if (mQuickStepStartingRotation > QUICKSTEP_ROTATION_UNINITIALIZED
                 && mCurrentDisplayRotation == mQuickStepStartingRotation) {
@@ -170,7 +170,7 @@
      * @param enableMultipleRegions Set to true to start tracking multiple nav bar regions
      * @param info The current displayInfo which will be the start of the quickswitch gesture
      */
-    void enableMultipleRegions(boolean enableMultipleRegions, DefaultDisplay.Info info) {
+    void enableMultipleRegions(boolean enableMultipleRegions, Info info) {
         mEnableMultipleRegions = enableMultipleRegions &&
                 mMode != SysUINavigationMode.Mode.TWO_BUTTONS;
         if (mEnableMultipleRegions) {
@@ -191,7 +191,7 @@
      *
      * @param displayInfo The display whos rotation will be used as the current active rotation
      */
-    void setSingleActiveRegion(DefaultDisplay.Info displayInfo) {
+    void setSingleActiveRegion(Info displayInfo) {
         mActiveTouchRotation = displayInfo.rotation;
         resetSwipeRegions(displayInfo);
     }
@@ -202,7 +202,7 @@
      * To be called whenever we want to stop tracking more than one swipe region.
      * Ok to call multiple times.
      */
-    private void resetSwipeRegions(DefaultDisplay.Info region) {
+    private void resetSwipeRegions(Info region) {
         if (DEBUG) {
             Log.d(TAG, "clearing all regions except rotation: " + mCurrentDisplayRotation);
         }
@@ -226,7 +226,7 @@
         }
     }
 
-    private OrientationRectF createRegionForDisplay(DefaultDisplay.Info display) {
+    private OrientationRectF createRegionForDisplay(Info display) {
         if (DEBUG) {
             Log.d(TAG, "creating rotation region for: " + mCurrentDisplayRotation);
         }
diff --git a/quickstep/src/com/android/quickstep/OverscrollPluginFactory.java b/quickstep/src/com/android/quickstep/OverscrollPluginFactory.java
new file mode 100644
index 0000000..4c261ab
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OverscrollPluginFactory.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.systemui.plugins.OverscrollPlugin;
+
+/**
+ * Resource overrideable factory for forcing a local overscroll plugin.
+ * Override {@link R.string#overscroll_plugin_factory_class} to set a different class.
+ */
+public class OverscrollPluginFactory implements ResourceBasedOverride {
+    public static final MainThreadInitializedObject<OverscrollPluginFactory> INSTANCE = forOverride(
+            OverscrollPluginFactory.class,
+            R.string.overscroll_plugin_factory_class);
+
+    /**
+     * Get the plugin that is defined locally in launcher, as opposed to a dynamic side loaded one.
+     */
+    public OverscrollPlugin getLocalOverscrollPlugin() {
+        return null;
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
rename to quickstep/src/com/android/quickstep/OverviewCommandHelper.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
similarity index 92%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
rename to quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 5026f36..e4b8ce2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -53,12 +53,6 @@
                         Bundle::putInt, PortraitStatesTouchController::getHotseatTop);
             }
 
-            case TestProtocol.REQUEST_OVERVIEW_ACTIONS_ENABLED: {
-                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
-                        FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get());
-                return response;
-            }
-
             case TestProtocol.REQUEST_OVERVIEW_SHARE_ENABLED: {
                 response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
                         FeatureFlags.ENABLE_OVERVIEW_SHARE.get());
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
rename to quickstep/src/com/android/quickstep/RecentsActivity.java
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index fe152a0..e9fc423 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -17,8 +17,8 @@
 
 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.DisplayController.DisplayHolder.CHANGE_ALL;
+import static com.android.launcher3.util.DisplayController.DisplayHolder.CHANGE_FRAME_DELAY;
 import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
 import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
 import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
@@ -56,7 +56,10 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.DisplayHolder;
+import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
+import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.SecureSettingsObserver;
 import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
 import com.android.quickstep.SysUINavigationMode.OneHandedModeChangeListener;
@@ -76,14 +79,14 @@
  */
 public class RecentsAnimationDeviceState implements
         NavigationModeChangeListener,
-        DefaultDisplay.DisplayInfoChangeListener,
+        DisplayInfoChangeListener,
         OneHandedModeChangeListener {
 
     static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
 
     private final Context mContext;
     private final SysUINavigationMode mSysUiNavMode;
-    private final DefaultDisplay mDefaultDisplay;
+    private final DisplayHolder mDisplayHolder;
     private final int mDisplayId;
     private final RotationTouchHelper mRotationTouchHelper;
 
@@ -120,13 +123,17 @@
     private boolean mIsUserSetupComplete;
 
     public RecentsAnimationDeviceState(Context context) {
+        this(context, DisplayController.getDefaultDisplay(context));
+    }
+
+    public RecentsAnimationDeviceState(Context context, DisplayHolder displayHolder) {
         mContext = context;
+        mDisplayHolder = displayHolder;
         mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context);
-        mDefaultDisplay = DefaultDisplay.INSTANCE.get(context);
-        mDisplayId = mDefaultDisplay.getInfo().id;
+        mDisplayId = mDisplayHolder.getInfo().id;
         mIsOneHandedModeSupported = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false);
-        runOnDestroy(() -> mDefaultDisplay.removeChangeListener(this));
-        mRotationTouchHelper = new RotationTouchHelper(context);
+        runOnDestroy(() -> mDisplayHolder.removeChangeListener(this));
+        mRotationTouchHelper = new RotationTouchHelper(context, mDisplayHolder);
         runOnDestroy(mRotationTouchHelper::destroy);
 
         // Register for user unlocked if necessary
@@ -232,9 +239,9 @@
 
     @Override
     public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
-        mDefaultDisplay.removeChangeListener(this);
-        mDefaultDisplay.addChangeListener(this);
-        onDisplayInfoChanged(mDefaultDisplay.getInfo(), CHANGE_ALL);
+        mDisplayHolder.removeChangeListener(this);
+        mDisplayHolder.addChangeListener(this);
+        onDisplayInfoChanged(mDisplayHolder.getInfo(), CHANGE_ALL);
 
         if (newMode == NO_BUTTON) {
             mExclusionListener.register();
@@ -242,12 +249,12 @@
             mExclusionListener.unregister();
         }
 
-        mNavBarPosition = new NavBarPosition(newMode, mDefaultDisplay.getInfo());
+        mNavBarPosition = new NavBarPosition(newMode, mDisplayHolder.getInfo());
         mMode = newMode;
     }
 
     @Override
-    public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) {
+    public void onDisplayInfoChanged(Info info, int flags) {
         if (info.id != getDisplayId() || flags == CHANGE_FRAME_DELAY) {
             // ignore displays that aren't running launcher and frame refresh rate changes
             return;
@@ -529,7 +536,7 @@
         }
 
         if (mIsOneHandedModeEnabled || mIsSwipeToNotificationEnabled) {
-            final DefaultDisplay.Info displayInfo = mDefaultDisplay.getInfo();
+            final Info displayInfo = mDisplayHolder.getInfo();
             return (mRotationTouchHelper.touchInOneHandedModeRegion(ev)
                 && displayInfo.rotation != Surface.ROTATION_90
                 && displayInfo.rotation != Surface.ROTATION_270
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 2b5e42a..2cf3212 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -17,8 +17,8 @@
 
 import static android.view.Surface.ROTATION_0;
 
-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.DisplayController.DisplayHolder.CHANGE_ALL;
+import static com.android.launcher3.util.DisplayController.DisplayHolder.CHANGE_FRAME_DELAY;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
 
@@ -28,8 +28,9 @@
 import android.view.OrientationEventListener;
 
 import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.util.DefaultDisplay;
-import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.DisplayController.DisplayHolder;
+import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
+import com.android.launcher3.util.DisplayController.Info;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -40,10 +41,10 @@
 
 public class RotationTouchHelper implements
         SysUINavigationMode.NavigationModeChangeListener,
-        DefaultDisplay.DisplayInfoChangeListener {
+        DisplayInfoChangeListener {
 
     private final OrientationTouchTransformer mOrientationTouchTransformer;
-    private final DefaultDisplay mDefaultDisplay;
+    private final DisplayHolder mDisplayHolder;
     private final SysUINavigationMode mSysUiNavMode;
     private final int mDisplayId;
     private int mDisplayRotation;
@@ -120,12 +121,12 @@
 
     private final Context mContext;
 
-    public RotationTouchHelper(Context context) {
+    public RotationTouchHelper(Context context, DisplayHolder displayHolder) {
         mContext = context;
+        mDisplayHolder = displayHolder;
         Resources resources = mContext.getResources();
         mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context);
-        mDefaultDisplay = DefaultDisplay.INSTANCE.get(context);
-        mDisplayId = mDefaultDisplay.getInfo().id;
+        mDisplayId = mDisplayHolder.getInfo().id;
 
         mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode,
                 () -> QuickStepContract.getWindowCornerRadius(resources));
@@ -200,7 +201,7 @@
             return;
         }
 
-        mOrientationTouchTransformer.createOrAddTouchRegion(mDefaultDisplay.getInfo());
+        mOrientationTouchTransformer.createOrAddTouchRegion(mDisplayHolder.getInfo());
     }
 
     /**
@@ -222,11 +223,11 @@
 
     @Override
     public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
-        mDefaultDisplay.removeChangeListener(this);
-        mDefaultDisplay.addChangeListener(this);
-        onDisplayInfoChanged(mDefaultDisplay.getInfo(), CHANGE_ALL);
+        mDisplayHolder.removeChangeListener(this);
+        mDisplayHolder.addChangeListener(this);
+        onDisplayInfoChanged(mDisplayHolder.getInfo(), CHANGE_ALL);
 
-        mOrientationTouchTransformer.setNavigationMode(newMode, mDefaultDisplay.getInfo(),
+        mOrientationTouchTransformer.setNavigationMode(newMode, mDisplayHolder.getInfo(),
             mContext.getResources());
         if (!mMode.hasGestures && newMode.hasGestures) {
             setupOrientationSwipeHandler();
@@ -242,7 +243,7 @@
     }
 
     @Override
-    public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) {
+    public void onDisplayInfoChanged(Info info, int flags) {
         if (info.id != mDisplayId|| flags == CHANGE_FRAME_DELAY) {
             // ignore displays that aren't running launcher and frame refresh rate changes
             return;
@@ -275,7 +276,7 @@
      * Sets the gestural height.
      */
     void setGesturalHeight(int newGesturalHeight) {
-        mOrientationTouchTransformer.setGesturalHeight(newGesturalHeight, mDefaultDisplay.getInfo(),
+        mOrientationTouchTransformer.setGesturalHeight(newGesturalHeight, mDisplayHolder.getInfo(),
             mContext.getResources());
     }
 
@@ -292,7 +293,7 @@
     }
 
     private void enableMultipleRegions(boolean enable) {
-        mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
+        mOrientationTouchTransformer.enableMultipleRegions(enable, mDisplayHolder.getInfo());
         notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getQuickStepStartingRotation());
         if (enable && !mInOverview && !TestProtocol.sDisableSensorRotation) {
             // Clear any previous state from sensor manager
@@ -355,7 +356,7 @@
      * notifies system UI of the primary rotation the user is interacting with
      */
     private void toggleSecondaryNavBarsForRotation() {
-        mOrientationTouchTransformer.setSingleActiveRegion(mDefaultDisplay.getInfo());
+        mOrientationTouchTransformer.setSingleActiveRegion(mDisplayHolder.getInfo());
         notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java
rename to quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
similarity index 87%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
rename to quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index db512fa..3a47024 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -18,7 +18,7 @@
 
 import static android.view.Surface.ROTATION_0;
 
-import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
 import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL;
 import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
 
@@ -39,13 +39,12 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.ResourceBasedOverride;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.views.OverviewActionsView;
+import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskThumbnailView;
 import com.android.quickstep.views.TaskView;
-import com.android.systemui.plugins.OverscrollPlugin;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
@@ -91,20 +90,22 @@
         return shortcuts;
     }
 
-    public static final MainThreadInitializedObject<TaskOverlayFactory> INSTANCE =
-            forOverride(TaskOverlayFactory.class, R.string.task_overlay_factory_class);
-
-    /**
-     * @return a launcher-provided OverscrollPlugin if available, otherwise null
-     */
-    public OverscrollPlugin getLocalOverscrollPlugin() {
-        return null;
-    }
-
     public TaskOverlay createOverlay(TaskThumbnailView thumbnailView) {
         return new TaskOverlay(thumbnailView);
     }
 
+    /**
+     * Subclasses can attach any system listeners in this method, must be paired with
+     * {@link #removeListeners()}
+     */
+    public void initListeners() { }
+
+    /**
+     * Subclasses should remove any system listeners in this method, must be paired with
+     * {@link #initListeners()}
+     */
+    public void removeListeners() { }
+
     /** Note that these will be shown in order from top to bottom, if available for the task. */
     private static final TaskShortcutFactory[] MENU_OPTIONS = new TaskShortcutFactory[]{
             TaskShortcutFactory.APP_INFO,
@@ -156,6 +157,7 @@
                 getActionsView().setCallbacks(new OverlayUICallbacks() {
                     @Override
                     public void onShare() {
+                        endLiveTileMode(isAllowedByPolicy);
                         if (isAllowedByPolicy) {
                             mImageApi.startShareActivity();
                         } else {
@@ -166,6 +168,7 @@
                     @SuppressLint("NewApi")
                     @Override
                     public void onScreenshot() {
+                        endLiveTileMode(isAllowedByPolicy);
                         saveScreenshot(task);
                     }
                 });
@@ -173,6 +176,23 @@
         }
 
         /**
+         * End rendering live tile in Overview.
+         *
+         * @param showScreenshot if it's true, we take a screenshot and switch to it.
+         */
+        public void endLiveTileMode(boolean showScreenshot) {
+            if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+                RecentsView recentsView = mThumbnailView.getTaskView().getRecentsView();
+                if (showScreenshot) {
+                    recentsView.switchToScreenshot(
+                            () -> recentsView.finishRecentsAnimation(true /* toRecents */, null));
+                } else {
+                    recentsView.finishRecentsAnimation(true /* toRecents */, null);
+                }
+            }
+        }
+
+        /**
          * Called to save screenshot of the task thumbnail.
          */
         @SuppressLint("NewApi")
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
similarity index 96%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java
rename to quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index ff051b6..3b245b3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -18,7 +18,6 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SELECTIONS;
 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;
@@ -310,16 +309,11 @@
     TaskShortcutFactory WELLBEING = (activity, view) ->
             WellbeingModel.SHORTCUT_FACTORY.getShortcut(activity, view.getItemInfo());
 
-    TaskShortcutFactory SCREENSHOT = (activity, tv) -> {
-        if (ENABLE_OVERVIEW_ACTIONS.get()) {
-            return tv.getThumbnail().getTaskOverlay()
-                .getScreenshotShortcut(activity, tv.getItemInfo());
-        }
-        return null;
-    };
+    TaskShortcutFactory SCREENSHOT = (activity, tv) -> tv.getThumbnail().getTaskOverlay()
+            .getScreenshotShortcut(activity, tv.getItemInfo());
 
     TaskShortcutFactory MODAL = (activity, tv) -> {
-        if (ENABLE_OVERVIEW_ACTIONS.get() && ENABLE_OVERVIEW_SELECTIONS.get()) {
+        if (ENABLE_OVERVIEW_SELECTIONS.get()) {
             return tv.getThumbnail().getTaskOverlay().getModalStateSystemShortcut(tv.getItemInfo());
         }
         return null;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
similarity index 98%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
rename to quickstep/src/com/android/quickstep/TaskViewUtils.java
index e2e25f3..a5af181 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -41,7 +41,7 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.statehandlers.DepthController;
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TransformParams;
@@ -146,7 +146,7 @@
         DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
         // RecentsView never updates the display rotation until swipe-up so the value may be stale.
         // Use the display value instead.
-        int displayRotation = DefaultDisplay.INSTANCE.get(context).getInfo().rotation;
+        int displayRotation = DisplayController.getDefaultDisplay(context).getInfo().rotation;
 
         TaskViewSimulator topMostSimulator = null;
         if (targets.apps.length > 0) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
similarity index 99%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
rename to quickstep/src/com/android/quickstep/TouchInteractionService.java
index 2baba78..5ec6377 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -576,9 +576,8 @@
             if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) {
                 OverscrollPlugin plugin = null;
                 if (FeatureFlags.FORCE_LOCAL_OVERSCROLL_PLUGIN.get()) {
-                    TaskOverlayFactory factory =
-                            TaskOverlayFactory.INSTANCE.get(getApplicationContext());
-                    plugin = factory.getLocalOverscrollPlugin();  // may be null
+                    plugin = OverscrollPluginFactory.INSTANCE.get(
+                            getApplicationContext()).getLocalOverscrollPlugin();
                 }
 
                 // If not local plugin was forced, use the actual overscroll plugin if available.
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/ViewUtils.java b/quickstep/src/com/android/quickstep/ViewUtils.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/ViewUtils.java
rename to quickstep/src/com/android/quickstep/ViewUtils.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
similarity index 95%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
rename to quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
index be3fdde..a4a7bd3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
@@ -21,7 +21,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.Utilities;
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.TouchController;
 import com.android.quickstep.RecentsActivity;
 import com.android.quickstep.SysUINavigationMode;
@@ -43,7 +43,7 @@
         SysUINavigationMode.Mode sysUINavigationMode = SysUINavigationMode.getMode(mActivity);
         if (sysUINavigationMode == SysUINavigationMode.Mode.NO_BUTTON) {
             NavBarPosition navBarPosition = new NavBarPosition(sysUINavigationMode,
-                    DefaultDisplay.INSTANCE.get(mActivity).getInfo());
+                    DisplayController.getDefaultDisplay(mActivity).getInfo());
             mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mActivity,
                     true /* disableHorizontalSwipe */, navBarPosition,
                     null /* onInterceptTouch */, this);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
rename to quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
rename to quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsDragLayer.java b/quickstep/src/com/android/quickstep/fallback/RecentsDragLayer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsDragLayer.java
rename to quickstep/src/com/android/quickstep/fallback/RecentsDragLayer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsState.java
rename to quickstep/src/com/android/quickstep/fallback/RecentsState.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsTaskController.java b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsTaskController.java
rename to quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
similarity index 98%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 7032fae..584ff28 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -41,7 +41,7 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
@@ -115,7 +115,7 @@
                 R.dimen.device_locked_y_offset);
 
         // Do not use DeviceProfile as the user data might be locked
-        mDisplaySize = DefaultDisplay.INSTANCE.get(context).getInfo().realSize;
+        mDisplaySize = DisplayController.getDefaultDisplay(context).getInfo().realSize;
 
         // Init states
         mStateCallback = new MultiStateCallback(STATE_NAMES);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 60d8ef6..865b66e 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -16,7 +16,7 @@
 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.launcher3.util.DisplayController.getSingleFrameMs;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.quickstep.AbsSwipeUpHandler.MAX_SWIPE_DURATION;
 import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java
rename to quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AssistantUtilities.java b/quickstep/src/com/android/quickstep/util/AssistantUtilities.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/AssistantUtilities.java
rename to quickstep/src/com/android/quickstep/util/AssistantUtilities.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/InputConsumerProxy.java b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/InputConsumerProxy.java
rename to quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index f7bd1e2..b88a195 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -15,7 +15,6 @@
  */
 package com.android.quickstep.util;
 
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
 import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
 
 import android.content.Context;
@@ -45,7 +44,7 @@
     public static int getShelfTrackingDistance(Context context, DeviceProfile dp,
             PagedOrientationHandler orientationHandler) {
         // Track the bottom of the window.
-        if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
+        if (removeShelfFromOverview(context)) {
             Rect taskSize = new Rect();
             LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
                     orientationHandler);
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index 969fa50..b862936 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -15,12 +15,13 @@
  */
 package com.android.quickstep.util;
 
-import static com.android.launcher3.config.FeatureFlags.ENABLE_LSQ_VELOCITY_PROVIDER;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SYSTEM_VELOCITY_PROVIDER;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.Log;
 import android.view.MotionEvent;
+import android.view.VelocityTracker;
 
 import com.android.launcher3.Alarm;
 import com.android.launcher3.R;
@@ -92,8 +93,8 @@
         mForcePauseTimeout = new Alarm();
         mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
         mMakePauseHarderToTrigger = makePauseHarderToTrigger;
-        mVelocityProvider = ENABLE_LSQ_VELOCITY_PROVIDER.get()
-                ? new LSqVelocityProvider(axis) : new LinearVelocityProvider(axis);
+        mVelocityProvider = ENABLE_SYSTEM_VELOCITY_PROVIDER.get()
+                ? new SystemVelocityProvider(axis) : new LinearVelocityProvider(axis);
     }
 
     /**
@@ -264,141 +265,28 @@
         }
     }
 
-    /**
-     * Java implementation of {@link android.view.VelocityTracker} using the Least Square (deg 2)
-     * algorithm.
-     */
-    private static class LSqVelocityProvider implements VelocityProvider {
+    private static class SystemVelocityProvider implements VelocityProvider {
 
-        // Maximum age of a motion event to be considered when calculating the velocity.
-        private static final long HORIZON_MS = 100;
-        // Number of samples to keep.
-        private static final int HISTORY_SIZE = 20;
-
-        // Position history are stored in a circular array
-        private final float[] mHistoricTimes = new float[HISTORY_SIZE];
-        private final float[] mHistoricPos = new float[HISTORY_SIZE];
-        private int mHistoryCount = 0;
-        private int mHistoryStart = 0;
-
+        private final VelocityTracker mVelocityTracker;
         private final int mAxis;
 
-        LSqVelocityProvider(int axis) {
+        SystemVelocityProvider(int axis) {
+            mVelocityTracker = VelocityTracker.obtain();
             mAxis = axis;
         }
 
         @Override
-        public void clear() {
-            mHistoryCount = mHistoryStart = 0;
-        }
-
-        private void addPositionAndTime(float eventTime, float eventPosition) {
-            mHistoricTimes[mHistoryStart] = eventTime;
-            mHistoricPos[mHistoryStart] = eventPosition;
-            mHistoryStart++;
-            if (mHistoryStart >= HISTORY_SIZE) {
-                mHistoryStart = 0;
-            }
-            mHistoryCount = Math.min(HISTORY_SIZE, mHistoryCount + 1);
+        public Float addMotionEvent(MotionEvent ev, int pointer) {
+            mVelocityTracker.addMovement(ev);
+            mVelocityTracker.computeCurrentVelocity(1); // px / ms
+            return mAxis == MotionEvent.AXIS_X
+                    ? mVelocityTracker.getXVelocity(pointer)
+                    : mVelocityTracker.getYVelocity(pointer);
         }
 
         @Override
-        public Float addMotionEvent(MotionEvent ev, int pointer) {
-            // Add all historic points
-            int historyCount = ev.getHistorySize();
-            for (int i = 0; i < historyCount; i++) {
-                addPositionAndTime(
-                        ev.getHistoricalEventTime(i), ev.getHistoricalAxisValue(mAxis, pointer, i));
-            }
-
-            // Start index for the last position (about to be added)
-            int eventStartIndex = mHistoryStart;
-            addPositionAndTime(ev.getEventTime(), ev.getAxisValue(mAxis, pointer));
-            return solveUnweightedLeastSquaresDeg2(eventStartIndex);
-        }
-
-        /**
-         * Solves the instantaneous velocity.
-         * Based on solveUnweightedLeastSquaresDeg2 in VelocityTracker.cpp
-         */
-        private Float solveUnweightedLeastSquaresDeg2(final int pointPos) {
-            final float eventTime = mHistoricTimes[pointPos];
-
-            float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
-            int count = 0;
-            for (int i = 0; i < mHistoryCount; i++) {
-                int index = pointPos - i;
-                if (index < 0) {
-                    index += HISTORY_SIZE;
-                }
-
-                float time = mHistoricTimes[index];
-                float age = eventTime - time;
-                if (age > HORIZON_MS) {
-                    break;
-                }
-                count++;
-                float xi = -age;
-
-                float yi = mHistoricPos[index];
-                float xi2 = xi * xi;
-                float xi3 = xi2 * xi;
-                float xi4 = xi3 * xi;
-                float xiyi = xi * yi;
-                float xi2yi = xi2 * yi;
-
-                sxi += xi;
-                sxi2 += xi2;
-                sxiyi += xiyi;
-                sxi2yi += xi2yi;
-                syi += yi;
-                sxi3 += xi3;
-                sxi4 += xi4;
-            }
-
-            if (count < 3) {
-                // Too few samples
-                switch (count) {
-                    case 2: {
-                        int endPos = pointPos - 1;
-                        if (endPos < 0) {
-                            endPos += HISTORY_SIZE;
-                        }
-                        float denominator = eventTime - mHistoricTimes[endPos];
-                        if (denominator != 0) {
-                            return (mHistoricPos[pointPos] - mHistoricPos[endPos]) / denominator;
-                        }
-                    }
-                    // fall through
-                    case 1:
-                        return 0f;
-                    default:
-                        return null;
-                }
-            }
-
-            float Sxx = sxi2 - sxi * sxi / count;
-            float Sxy = sxiyi - sxi * syi / count;
-            float Sxx2 = sxi3 - sxi * sxi2 / count;
-            float Sx2y = sxi2yi - sxi2 * syi / count;
-            float Sx2x2 = sxi4 - sxi2 * sxi2 / count;
-
-            float denominator = Sxx * Sx2x2 - Sxx2 * Sxx2;
-            if (denominator == 0) {
-                // division by 0 when computing velocity
-                return null;
-            }
-            // Compute a
-            // float numerator = Sx2y*Sxx - Sxy*Sxx2;
-
-            // Compute b
-            float numerator = Sxy * Sx2x2 - Sx2y * Sxx2;
-            float b = numerator / denominator;
-
-            // Compute c
-            // float c = syi/count - b * sxi/count - a * sxi2/count;
-
-            return b;
+        public void clear() {
+            mVelocityTracker.clear();
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/NavBarPosition.java b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
index 0a98e1b..449dba8 100644
--- a/quickstep/src/com/android/quickstep/util/NavBarPosition.java
+++ b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
@@ -19,7 +19,7 @@
 
 import android.view.Surface;
 
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController.Info;
 import com.android.quickstep.SysUINavigationMode;
 
 /**
@@ -30,7 +30,7 @@
     private final SysUINavigationMode.Mode mMode;
     private final int mDisplayRotation;
 
-    public NavBarPosition(SysUINavigationMode.Mode mode, DefaultDisplay.Info info) {
+    public NavBarPosition(SysUINavigationMode.Mode mode, Info info) {
         mMode = mode;
         mDisplayRotation = info.rotation;
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
similarity index 94%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/OverviewToHomeAnim.java
rename to quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index d2e1ded..6278e14 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -76,6 +76,7 @@
         if (startState != OVERVIEW) {
             Log.e(TAG, "animateFromOverviewToHome: unexpected start state " + startState);
         }
+        AnimatorSet anim = new AnimatorSet();
 
         boolean playStaggeredWorkspaceAnim = velocity < 0;
         if (playStaggeredWorkspaceAnim) {
@@ -87,7 +88,8 @@
                     mIsHomeStaggeredAnimFinished = true;
                     maybeOverviewToHomeAnimComplete();
                 }
-            }).start();
+            });
+            anim.play(staggeredWorkspaceAnim.getAnimators());
         } else {
             mIsHomeStaggeredAnimFinished = true;
         }
@@ -108,16 +110,17 @@
         config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, FINAL_FRAME);
         config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME);
         config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, INSTANT);
-        AnimatorSet anim = stateManager.createAtomicAnimation(
+        AnimatorSet stateAnim = stateManager.createAtomicAnimation(
                 startState, NORMAL, config);
-        anim.addListener(new AnimationSuccessListener() {
+        stateAnim.addListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationSuccess(Animator animator) {
                 mIsOverviewHidden = true;
                 maybeOverviewToHomeAnimComplete();
             }
         });
-        stateManager.cancelAnimation();
+        anim.play(stateAnim);
+        stateManager.setCurrentAnimation(anim, NORMAL);
         anim.start();
         recentsView.snapToPage(DEFAULT_PAGE, duration);
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ProtoTracer.java b/quickstep/src/com/android/quickstep/util/ProtoTracer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/ProtoTracer.java
rename to quickstep/src/com/android/quickstep/util/ProtoTracer.java
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index c2e67c1..7eda627 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -21,7 +21,6 @@
 import static com.android.launcher3.LauncherState.HINT_STATE;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
 import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
 import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
 
@@ -66,8 +65,7 @@
         }
 
         boolean shelfBounceSeen = getBoolean(SHELF_BOUNCE_SEEN);
-        if (!shelfBounceSeen && ENABLE_OVERVIEW_ACTIONS.get()
-                && removeShelfFromOverview(launcher)) {
+        if (!shelfBounceSeen && removeShelfFromOverview(launcher)) {
             // There's no shelf in overview, so don't bounce it (can't get to all apps anyway).
             shelfBounceSeen = true;
             mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, shelfBounceSeen).apply();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
rename to quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
rename to quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
diff --git a/quickstep/src/com/android/quickstep/util/SplitScreenBounds.java b/quickstep/src/com/android/quickstep/util/SplitScreenBounds.java
index a770e8e..176478f 100644
--- a/quickstep/src/com/android/quickstep/util/SplitScreenBounds.java
+++ b/quickstep/src/com/android/quickstep/util/SplitScreenBounds.java
@@ -32,7 +32,7 @@
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.R;
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.WindowBounds;
 
 import java.util.ArrayList;
@@ -77,7 +77,7 @@
 
         WindowBounds bounds = new WindowBounds(wm.getBounds(),
                 new Rect(insets.left, insets.top, insets.right, insets.bottom));
-        int rotation = DefaultDisplay.INSTANCE.get(context).getInfo().rotation;
+        int rotation = DisplayController.getDefaultDisplay(context).getInfo().rotation;
         int halfDividerSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
rename to quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/SurfaceTransactionApplier.java
rename to quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskCornerRadius.java b/quickstep/src/com/android/quickstep/util/TaskCornerRadius.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskCornerRadius.java
rename to quickstep/src/com/android/quickstep/util/TaskCornerRadius.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
similarity index 97%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
rename to quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index e5f4d38..903e87a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -325,9 +325,10 @@
                 .withWindowCrop(mTmpCropRect)
                 .withCornerRadius(getCurrentCornerRadius());
 
-        if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mDrawsBelowRecents
-                && params.getRecentsSurface() != null) {
-            builder.withRelativeLayerTo(params.getRecentsSurface(), Integer.MIN_VALUE);
+        if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) {
+            // When relativeLayer = 0, it reverts the surfaces back to the original order.
+            builder.withRelativeLayerTo(params.getRecentsSurface(),
+                    mDrawsBelowRecents ? Integer.MIN_VALUE : 0);
         }
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java b/quickstep/src/com/android/quickstep/util/TransformParams.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
rename to quickstep/src/com/android/quickstep/util/TransformParams.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
rename to quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java
rename to quickstep/src/com/android/quickstep/views/AllAppsEduView.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java
rename to quickstep/src/com/android/quickstep/views/ClearAllButton.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java
rename to quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/IconView.java
rename to quickstep/src/com/android/quickstep/views/IconView.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
similarity index 96%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
rename to quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index f31bc19..b338bd0 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -43,6 +43,7 @@
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.quickstep.LauncherActivityInterface;
 import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.util.OverviewToHomeAnim;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.RecentsExtraCard;
 
@@ -93,12 +94,14 @@
 
     @Override
     public void startHome() {
+        Runnable onReachedHome = () -> mActivity.getStateManager().goToState(NORMAL, false);
+        OverviewToHomeAnim overviewToHomeAnim = new OverviewToHomeAnim(mActivity, onReachedHome);
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             switchToScreenshot(null,
                     () -> finishRecentsAnimation(true /* toRecents */,
-                            () -> mActivity.getStateManager().goToState(NORMAL)));
+                            () -> overviewToHomeAnim.animateWithVelocity(0)));
         } else {
-            mActivity.getStateManager().goToState(NORMAL);
+            overviewToHomeAnim.animateWithVelocity(0);
         }
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LiveTileOverlay.java b/quickstep/src/com/android/quickstep/views/LiveTileOverlay.java
similarity index 92%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/LiveTileOverlay.java
rename to quickstep/src/com/android/quickstep/views/LiveTileOverlay.java
index 30c9f77..c6c2d7e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LiveTileOverlay.java
+++ b/quickstep/src/com/android/quickstep/views/LiveTileOverlay.java
@@ -40,14 +40,13 @@
     public static final LiveTileOverlay INSTANCE = new LiveTileOverlay();
 
     private final Paint mPaint = new Paint();
+    private final RectF mCurrentRect = new RectF();
     private final Rect mBoundsRect = new Rect();
 
-    private RectF mCurrentRect;
     private float mCornerRadius;
     private Drawable mIcon;
     private Animator mIconAnimator;
 
-    private boolean mDrawEnabled = true;
     private float mIconAnimationProgress = 0f;
     private boolean mIsAttached;
 
@@ -58,7 +57,7 @@
     public void update(RectF currentRect, float cornerRadius) {
         invalidateSelf();
 
-        mCurrentRect = currentRect;
+        mCurrentRect.set(currentRect);
         mCornerRadius = cornerRadius;
 
         mCurrentRect.roundOut(mBoundsRect);
@@ -93,16 +92,9 @@
         return mIconAnimationProgress;
     }
 
-    public void setDrawEnabled(boolean drawEnabled) {
-        if (mDrawEnabled != drawEnabled) {
-            mDrawEnabled = drawEnabled;
-            invalidateSelf();
-        }
-    }
-
     @Override
     public void draw(Canvas canvas) {
-        if (mCurrentRect != null && mDrawEnabled) {
+        if (mCurrentRect != null) {
             canvas.drawRoundRect(mCurrentRect, mCornerRadius, mCornerRadius, mPaint);
             if (mIcon != null && mIconAnimationProgress > 0f) {
                 canvas.save();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
similarity index 93%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
rename to quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 1bf2fbf..8f60991 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -16,7 +16,6 @@
 
 package com.android.quickstep.views;
 
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SHARE;
 import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
 
@@ -53,7 +52,6 @@
 
     @IntDef(flag = true, value = {
             HIDDEN_UNSUPPORTED_NAVIGATION,
-            HIDDEN_DISABLED_FEATURE,
             HIDDEN_NON_ZERO_ROTATION,
             HIDDEN_NO_TASKS,
             HIDDEN_GESTURE_RUNNING,
@@ -62,11 +60,10 @@
     public @interface ActionsHiddenFlags { }
 
     public static final int HIDDEN_UNSUPPORTED_NAVIGATION = 1 << 0;
-    public static final int HIDDEN_DISABLED_FEATURE = 1 << 1;
-    public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 2;
-    public static final int HIDDEN_NO_TASKS = 1 << 3;
-    public static final int HIDDEN_GESTURE_RUNNING = 1 << 4;
-    public static final int HIDDEN_NO_RECENTS = 1 << 5;
+    public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 1;
+    public static final int HIDDEN_NO_TASKS = 1 << 2;
+    public static final int HIDDEN_GESTURE_RUNNING = 1 << 3;
+    public static final int HIDDEN_NO_RECENTS = 1 << 4;
 
     @IntDef(flag = true, value = {
             DISABLED_SCROLLING,
@@ -145,7 +142,6 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        updateHiddenFlags(HIDDEN_DISABLED_FEATURE, !ENABLE_OVERVIEW_ACTIONS.get());
         updateHiddenFlags(HIDDEN_UNSUPPORTED_NAVIGATION, !removeShelfFromOverview(getContext()));
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsExtraViewContainer.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java
rename to quickstep/src/com/android/quickstep/views/RecentsExtraViewContainer.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
similarity index 97%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
rename to quickstep/src/com/android/quickstep/views/RecentsView.java
index 4d58a0d..a9b5bf3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -24,6 +24,7 @@
 import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
 import static com.android.launcher3.Utilities.mapToRange;
 import static com.android.launcher3.Utilities.squaredHypot;
@@ -93,6 +94,7 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherState;
 import com.android.launcher3.PagedView;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -115,6 +117,7 @@
 import com.android.launcher3.util.DynamicResource;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.OverScroller;
+import com.android.launcher3.util.ResourceBasedOverride.Overrides;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.ViewPool;
 import com.android.quickstep.BaseActivityInterface;
@@ -123,6 +126,7 @@
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TaskOverlayFactory;
 import com.android.quickstep.TaskThumbnailCache;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.ViewUtils;
@@ -279,6 +283,8 @@
 
     private final ViewPool<TaskView> mTaskViewPool;
 
+    private final TaskOverlayFactory mTaskOverlayFactory;
+
     private boolean mDwbToastShown;
     protected boolean mDisallowScrollToClearAll;
     private boolean mOverlayEnabled;
@@ -467,6 +473,11 @@
         updateEmptyMessage();
         mOrientationHandler = mOrientationState.getOrientationHandler();
 
+        mTaskOverlayFactory = Overrides.getObject(
+                TaskOverlayFactory.class,
+                context.getApplicationContext(),
+                R.string.task_overlay_factory_class);
+
         // Initialize quickstep specific cache params here, as this is constructed only once
         mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
 
@@ -568,6 +579,7 @@
                 mIPinnedStackAnimationListener);
         mOrientationState.initListeners();
         SplitScreenBounds.INSTANCE.addOnChangeListener(this);
+        mTaskOverlayFactory.initListeners();
     }
 
     @Override
@@ -585,6 +597,7 @@
         SplitScreenBounds.INSTANCE.removeOnChangeListener(this);
         mIPinnedStackAnimationListener.setActivity(null);
         mOrientationState.destroyListeners();
+        mTaskOverlayFactory.removeListeners();
     }
 
     @Override
@@ -1748,6 +1761,12 @@
             updateOrientationHandler();
         }
         mLiveTileTaskViewSimulator.setRecentsRotation(rotation);
+        // If overview is in modal state when rotate, reset it to overview state without running
+        // animation.
+        if (mActivity.isInState(OVERVIEW_MODAL_TASK)) {
+            mActivity.getStateManager().goToState(LauncherState.OVERVIEW, false);
+            resetModalVisuals();
+        }
     }
 
     public void setLayoutRotation(int touchRotation, int displayRotation) {
@@ -2275,13 +2294,13 @@
         mRecentsAnimationController.finish(toRecents, () -> {
             if (onFinishComplete != null) {
                 onFinishComplete.run();
-                // After we finish the recents animation, the current task id should be correctly
-                // reset so that when the task is launched from Overview later, it goes through the
-                // flow of starting a new task instead of finishing recents animation to app. A
-                // typical example of this is (1) user swipes up from app to Overview (2) user
-                // taps on QSB (3) user goes back to Overview and launch the most recent task.
-                setCurrentTask(-1);
             }
+            // After we finish the recents animation, the current task id should be correctly
+            // reset so that when the task is launched from Overview later, it goes through the
+            // flow of starting a new task instead of finishing recents animation to app. A
+            // typical example of this is (1) user swipes up from app to Overview (2) user
+            // taps on QSB (3) user goes back to Overview and launch the most recent task.
+            setCurrentTask(-1);
         });
     }
 
@@ -2409,7 +2428,19 @@
         }
     }
 
-    /** If it's in the live tile mode, switch the running task into screenshot mode. */
+    /**
+     * Switch the current running task view to static snapshot mode,
+     * capturing the snapshot at the same time.
+     */
+    public void switchToScreenshot(Runnable onFinishRunnable) {
+        switchToScreenshot(mRunningTaskId == -1 ? null
+                : mRecentsAnimationController.screenshotTask(mRunningTaskId), onFinishRunnable);
+    }
+
+    /**
+     * Switch the current running task view to static snapshot mode, using the
+     * provided thumbnail data as the snapshot.
+     */
     public void switchToScreenshot(ThumbnailData thumbnailData, Runnable onFinishRunnable) {
         TaskView taskView = getRunningTaskView();
         if (taskView != null) {
@@ -2459,6 +2490,10 @@
      */
     public void setModalStateEnabled(boolean isModalState) { }
 
+    public TaskOverlayFactory getTaskOverlayFactory() {
+        return mTaskOverlayFactory;
+    }
+
     public BaseActivityInterface getSizeStrategy() {
         return mSizeStrategy;
     }
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index f1ac6a5..e6613eb 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -16,9 +16,7 @@
 package com.android.quickstep.views;
 
 import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
-import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.LauncherState.QUICK_SWITCH;
 import static com.android.launcher3.anim.Interpolators.ACCEL;
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -38,11 +36,9 @@
 
 import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.uioverrides.states.OverviewState;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ScrimView;
@@ -155,8 +151,7 @@
 
             Context context = getContext();
             if ((OVERVIEW.getVisibleElements(mLauncher) & ALL_APPS_HEADER_EXTRA) == 0) {
-                if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()
-                        && SysUINavigationMode.removeShelfFromOverview(context)) {
+                if (SysUINavigationMode.removeShelfFromOverview(context)) {
                     // Fade in all apps background quickly to distinguish from swiping from nav bar.
                     mMidAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha);
                     mMidProgress = OverviewState.getDefaultVerticalProgress(mLauncher);
@@ -198,13 +193,6 @@
         if (mProgress >= 1) {
             mRemainingScreenColor = 0;
             mShelfColor = 0;
-            LauncherState state = mLauncher.getStateManager().getState();
-            if (mSysUINavigationMode == Mode.NO_BUTTON
-                    && (state == BACKGROUND_APP || state == QUICK_SWITCH)
-                    && mLauncher.getShelfPeekAnim().isPeeking()) {
-                // Show the shelf background when peeking during swipe up.
-                mShelfColor = setColorAlphaBound(mEndScrim, mMidAlpha);
-            }
         } else if (mProgress >= mMidProgress) {
             mRemainingScreenColor = 0;
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java
rename to quickstep/src/com/android/quickstep/views/TaskMenuView.java
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
similarity index 98%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
rename to quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index c5f673f..dfb3860 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -52,7 +52,6 @@
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
-import com.android.quickstep.TaskOverlayFactory;
 import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
 import com.android.quickstep.views.TaskView.FullscreenDrawParams;
 import com.android.systemui.plugins.OverviewScreenshotActions;
@@ -85,7 +84,7 @@
             };
 
     private final BaseActivity mActivity;
-    private final TaskOverlay mOverlay;
+    private TaskOverlay mOverlay;
     private final boolean mIsDarkTextTheme;
     private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -118,7 +117,6 @@
 
     public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mOverlay = TaskOverlayFactory.INSTANCE.get(context).createOverlay(this);
         mPaint.setFilterBitmap(true);
         mBackgroundPaint.setColor(Color.WHITE);
         mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
@@ -134,7 +132,7 @@
      * @param task
      */
     public void bind(Task task) {
-        mOverlay.reset();
+        getTaskOverlay().reset();
         mTask = task;
         int color = task == null ? Color.BLACK : task.colorBackground | 0xFF000000;
         mPaint.setColor(color);
@@ -176,7 +174,7 @@
             mBitmapShader = null;
             mThumbnailData = null;
             mPaint.setShader(null);
-            mOverlay.reset();
+            getTaskOverlay().reset();
         }
         if (mOverviewScreenshotActionsPlugin != null) {
             mOverviewScreenshotActionsPlugin.setupActions(getTaskView(), getThumbnail(), mActivity);
@@ -200,6 +198,9 @@
     }
 
     public TaskOverlay getTaskOverlay() {
+        if (mOverlay == null) {
+            mOverlay = getTaskView().getRecentsView().getTaskOverlayFactory().createOverlay(this);
+        }
         return mOverlay;
     }
 
@@ -349,10 +350,10 @@
 
     private void updateOverlay() {
         if (mOverlayEnabled) {
-            mOverlay.initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
+            getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
                     mPreviewPositionHelper.mIsOrientationChanged);
         } else {
-            mOverlay.reset();
+            getTaskOverlay().reset();
         }
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
similarity index 100%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
rename to quickstep/src/com/android/quickstep/views/TaskView.java
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index bd8c53c..cbc3abc 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -17,7 +17,7 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
-import static com.android.launcher3.util.DefaultDisplay.CHANGE_ROTATION;
+import static com.android.launcher3.util.DisplayController.DisplayHolder.CHANGE_ROTATION;
 
 import android.app.ActivityOptions;
 import android.content.ActivityNotFoundException;
@@ -50,9 +50,9 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.uioverrides.WallpaperColorInfo;
-import com.android.launcher3.util.DefaultDisplay;
-import com.android.launcher3.util.DefaultDisplay.DisplayInfoChangeListener;
-import com.android.launcher3.util.DefaultDisplay.Info;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
+import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TraceHelper;
@@ -84,7 +84,7 @@
 
         mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
                 () -> getPackageManager().isSafeMode());
-        DefaultDisplay.INSTANCE.get(this).addChangeListener(this);
+        DisplayController.getDefaultDisplay(this).addChangeListener(this);
 
         // Update theme
         WallpaperColorInfo.INSTANCE.get(this).addOnChangeListener(this);
@@ -257,7 +257,7 @@
     protected void onDestroy() {
         super.onDestroy();
         WallpaperColorInfo.INSTANCE.get(this).removeOnChangeListener(this);
-        DefaultDisplay.INSTANCE.get(this).removeChangeListener(this);
+        DisplayController.getDefaultDisplay(this).removeChangeListener(this);
     }
 
     public void runOnceOnStart(Runnable action) {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 49caa93..12ce9f3 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -28,7 +28,8 @@
 import com.android.launcher3.graphics.IconShape;
 import com.android.launcher3.icons.DotRenderer;
 import com.android.launcher3.icons.IconNormalizer;
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.WindowBounds;
 
 public class DeviceProfile {
@@ -38,7 +39,7 @@
 
 
     public final InvariantDeviceProfile inv;
-    private final DefaultDisplay.Info mInfo;
+    private final Info mInfo;
 
     // Device properties
     public final boolean isTablet;
@@ -140,7 +141,7 @@
     public DotRenderer mDotRendererWorkSpace;
     public DotRenderer mDotRendererAllApps;
 
-    DeviceProfile(Context context, InvariantDeviceProfile inv, DefaultDisplay.Info info,
+    DeviceProfile(Context context, InvariantDeviceProfile inv, Info info,
             Point minSize, Point maxSize, int width, int height, boolean isLandscape,
             boolean isMultiWindowMode, boolean transposeLayoutWithOrientation,
             Point windowPosition) {
@@ -606,7 +607,7 @@
      */
     public boolean updateIsSeascape(Context context) {
         if (isVerticalBarLayout()) {
-            boolean isSeascape = DefaultDisplay.INSTANCE.get(context).getInfo().rotation
+            boolean isSeascape = DisplayController.getDefaultDisplay(context).getInfo().rotation
                     == Surface.ROTATION_270;
             if (mIsSeascape != isSeascape) {
                 mIsSeascape = isSeascape;
@@ -638,7 +639,7 @@
         }
     }
 
-    private static Context getContext(Context c, DefaultDisplay.Info info, int orientation) {
+    private static Context getContext(Context c, Info info, int orientation) {
         Configuration config = new Configuration(c.getResources().getConfiguration());
         config.orientation = orientation;
         config.densityDpi = info.metrics.densityDpi;
@@ -662,7 +663,7 @@
     public static class Builder {
         private Context mContext;
         private InvariantDeviceProfile mInv;
-        private DefaultDisplay.Info mInfo;
+        private Info mInfo;
 
         private final Point mWindowPosition = new Point();
         private Point mMinSize, mMaxSize;
@@ -672,7 +673,7 @@
         private boolean mIsMultiWindowMode = false;
         private boolean mTransposeLayoutWithOrientation;
 
-        public Builder(Context context, InvariantDeviceProfile inv, DefaultDisplay.Info info) {
+        public Builder(Context context, InvariantDeviceProfile inv, Info info) {
             mContext = context;
             mInv = inv;
             mInfo = info;
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index 6c5bc40..a199a57 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -15,7 +15,7 @@
  */
 package com.android.launcher3;
 
-import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
+import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index e39e89c..370bd6f 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -48,8 +48,8 @@
 
 import com.android.launcher3.graphics.IconShape;
 import com.android.launcher3.util.ConfigMonitor;
-import com.android.launcher3.util.DefaultDisplay;
-import com.android.launcher3.util.DefaultDisplay.Info;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Themes;
@@ -198,7 +198,7 @@
 
         // Get the display info based on default display and interpolate it to existing display
         DisplayOption defaultDisplayOption = invDistWeightedInterpolate(
-                DefaultDisplay.INSTANCE.get(context).getInfo(),
+                DisplayController.getDefaultDisplay(context).getInfo(),
                 getPredefinedDeviceProfiles(context, gridName));
 
         Info myInfo = new Info(context, display);
@@ -231,7 +231,7 @@
     }
 
     private String initGrid(Context context, String gridName) {
-        DefaultDisplay.Info displayInfo = DefaultDisplay.INSTANCE.get(context).getInfo();
+        Info displayInfo = DisplayController.getDefaultDisplay(context).getInfo();
         ArrayList<DisplayOption> allOptions = getPredefinedDeviceProfiles(context, gridName);
 
         DisplayOption displayOption = invDistWeightedInterpolate(displayInfo, allOptions);
@@ -240,7 +240,7 @@
     }
 
     private void initGrid(
-            Context context, DefaultDisplay.Info displayInfo, DisplayOption displayOption) {
+            Context context, Info displayInfo, DisplayOption displayOption) {
         GridOption closestProfile = displayOption.grid;
         numRows = closestProfile.numRows;
         numColumns = closestProfile.numColumns;
@@ -466,7 +466,7 @@
 
     @VisibleForTesting
     static DisplayOption invDistWeightedInterpolate(
-            DefaultDisplay.Info displayInfo, ArrayList<DisplayOption> points) {
+            Info displayInfo, ArrayList<DisplayOption> points) {
         Point smallestSize = new Point(displayInfo.smallestSize);
         Point largestSize = new Point(displayInfo.largestSize);
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2ddaaea..51a9dfe 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -33,7 +33,6 @@
 import static com.android.launcher3.LauncherState.NO_OFFSET;
 import static com.android.launcher3.LauncherState.NO_SCALE;
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
 import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
@@ -454,7 +453,7 @@
                 float alpha = 1f - mCurrentAssistantVisibility;
                 if (finalState == NORMAL) {
                     mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
-                } else if (finalState == OVERVIEW || finalState == OVERVIEW_PEEK) {
+                } else if (finalState == OVERVIEW) {
                     mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
                     mScrimView.setAlpha(alpha);
                 } else {
@@ -554,7 +553,7 @@
         LauncherState state = mStateManager.getState();
         if (state == NORMAL) {
             mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
-        } else if (state == OVERVIEW || state == OVERVIEW_PEEK) {
+        } else if (state == OVERVIEW) {
             mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
             mScrimView.setAlpha(alpha);
         }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index f306c78..c51a84e 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -61,7 +61,6 @@
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.Preconditions;
 
@@ -86,7 +85,6 @@
 
     private final LauncherAppState mApp;
     private final Object mLock = new Object();
-    private final LooperExecutor mMainExecutor = MAIN_EXECUTOR;
 
     private LoaderTask mLoaderTask;
     private boolean mIsLoaderTaskRunning;
@@ -339,13 +337,13 @@
             if (callbacksList.length > 0) {
                 // Clear any pending bind-runnables from the synchronized load process.
                 for (Callbacks cb : callbacksList) {
-                    mMainExecutor.execute(cb::clearPendingBinds);
+                    MAIN_EXECUTOR.execute(cb::clearPendingBinds);
                 }
 
                 // If there is already one running, tell it to stop.
                 stopLoader();
                 LoaderResults loaderResults = new LoaderResults(
-                        mApp, mBgDataModel, mBgAllAppsList, callbacksList, mMainExecutor);
+                        mApp, mBgDataModel, mBgAllAppsList, callbacksList);
                 if (mModelLoaded && !mIsLoaderTaskRunning) {
                     // Divide the set of loaded items into those that we are binding synchronously,
                     // and everything else that is to be bound normally (asynchronously).
@@ -532,7 +530,7 @@
     }
 
     public void enqueueModelUpdateTask(ModelUpdateTask task) {
-        task.init(mApp, this, mBgDataModel, mBgAllAppsList, mMainExecutor);
+        task.init(mApp, this, mBgDataModel, mBgAllAppsList, MAIN_EXECUTOR);
         MODEL_EXECUTOR.execute(task);
     }
 
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 39b0f2f..b6bc500 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -21,7 +21,6 @@
 import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
 import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
 import static com.android.launcher3.testing.TestProtocol.OVERVIEW_MODAL_TASK_STATE_ORDINAL;
-import static com.android.launcher3.testing.TestProtocol.OVERVIEW_PEEK_STATE_ORDINAL;
 import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
 import static com.android.launcher3.testing.TestProtocol.QUICK_SWITCH_STATE_ORDINAL;
 import static com.android.launcher3.testing.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
@@ -117,8 +116,6 @@
     public static final LauncherState HINT_STATE = new HintState(HINT_STATE_ORDINAL);
 
     public static final LauncherState OVERVIEW = new OverviewState(OVERVIEW_STATE_ORDINAL);
-    public static final LauncherState OVERVIEW_PEEK =
-            OverviewState.newPeekState(OVERVIEW_PEEK_STATE_ORDINAL);
     public static final LauncherState OVERVIEW_MODAL_TASK = OverviewState.newModalTaskState(
             OVERVIEW_MODAL_TASK_STATE_ORDINAL);
     public static final LauncherState QUICK_SWITCH =
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 06faaac..0d87481 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -15,15 +15,23 @@
  */
 package com.android.launcher3.allapps.search;
 
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.View.OnFocusChangeListener;
 import android.view.inputmethod.EditorInfo;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
+import android.widget.Toast;
+
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.ExtendedEditText;
@@ -32,23 +40,31 @@
 import com.android.launcher3.allapps.AlphabeticalAppsList;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.util.PackageManagerHelper;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.PluginListener;
 
 import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * An interface to a search box that AllApps can command.
  */
 public class AllAppsSearchBarController
         implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
-        OnFocusChangeListener {
+        OnFocusChangeListener, PluginListener<AllAppsSearchPlugin> {
 
+    private static final String TAG = "AllAppsSearchBarContoller";
     protected BaseDraggingActivity mLauncher;
     protected Callbacks mCb;
     protected ExtendedEditText mInput;
     protected String mQuery;
 
     protected SearchAlgorithm mSearchAlgorithm;
+    private AllAppsSearchPlugin mPlugin;
+    private Consumer mPlubinCb;
 
     public void setVisibility(int visibility) {
         mInput.setVisibility(visibility);
@@ -59,7 +75,7 @@
      */
     public final void initialize(
             SearchAlgorithm searchAlgorithm, ExtendedEditText input,
-            BaseDraggingActivity launcher, Callbacks cb) {
+            BaseDraggingActivity launcher, Callbacks cb, Consumer<List<Bundle>> secondaryCb) {
         mCb = cb;
         mLauncher = launcher;
 
@@ -69,11 +85,19 @@
         mInput.setOnBackKeyListener(this);
         mInput.setOnFocusChangeListener(this);
         mSearchAlgorithm = searchAlgorithm;
+
+        PluginManagerWrapper.INSTANCE.get(launcher).addPluginListener(this,
+                AllAppsSearchPlugin.class);
+        mPlubinCb = secondaryCb;
     }
 
     @Override
     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-        // Do nothing
+        if (mPlugin != null) {
+            if (s.length() == 0) {
+                mPlugin.startedTyping();
+            }
+        }
     }
 
     @Override
@@ -90,6 +114,9 @@
         } else {
             mSearchAlgorithm.cancel(false);
             mSearchAlgorithm.doSearch(mQuery, mCb);
+            if (mPlugin != null) {
+                mPlugin.performSearch(mQuery, mPlubinCb);
+            }
         }
     }
 
@@ -170,13 +197,52 @@
         return mInput.isFocused();
     }
 
+    @Override
+    public void onPluginConnected(AllAppsSearchPlugin allAppsSearchPlugin, Context context) {
+        if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+            mPlugin = allAppsSearchPlugin;
+            checkCallPermission();
+        }
+    }
+
+    /**
+     * Check call permissions.
+     */
+    public void checkCallPermission() {
+        final String[] permission = {"android.permission.CALL_PHONE",
+                "android.permission.READ_CONTACTS"};
+        boolean request = false;
+        for (String p : permission) {
+            int permissionCheck = ContextCompat.checkSelfPermission(mLauncher, p);
+            if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
+                request = true;
+            }
+        }
+
+        if (!request) return;
+        boolean rationale = false;
+        for (String p : permission) {
+            if (mLauncher.shouldShowRequestPermissionRationale(p)) {
+                rationale = true;
+            }
+            if (rationale) {
+                Log.e(TAG, p + " Show rationale");
+                Toast.makeText(mLauncher, "Requesting Permissions", Toast.LENGTH_SHORT).show();
+            } else {
+                ActivityCompat.requestPermissions(mLauncher,  permission,  123);
+                Log.e(TAG, p + " request permission");
+            }
+        }
+
+    }
+
     /**
      * Callback for getting search results.
      */
     public interface Callbacks {
 
         /**
-         * Called when the search is complete.
+         * Called when the search from primary source is complete.
          *
          * @param items sorted list of search result adapter items.
          */
@@ -187,5 +253,4 @@
          */
         void clearSearchResult();
     }
-
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 16a1efd..e8a0d7a 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -24,6 +24,7 @@
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.method.TextKeyListener;
@@ -47,13 +48,15 @@
 import com.android.launcher3.anim.PropertySetter;
 
 import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Layout to contain the All-apps search UI.
  */
 public class AppsSearchContainerLayout extends ExtendedEditText
         implements SearchUiManager, AllAppsSearchBarController.Callbacks,
-        AllAppsStore.OnUpdateListener, Insettable {
+        AllAppsStore.OnUpdateListener, Insettable, Consumer<List<Bundle>> {
 
     private final BaseDraggingActivity mLauncher;
     private final AllAppsSearchBarController mSearchBarController;
@@ -136,7 +139,7 @@
         mAppsView = appsView;
         mSearchBarController.initialize(
                 new DefaultAppSearchAlgorithm(LauncherAppState.getInstance(mLauncher)), this,
-                mLauncher, this);
+                mLauncher, this, this);
     }
 
     @Override
@@ -220,4 +223,9 @@
     public EditText getEditText() {
         return this;
     }
+
+    @Override
+    public void accept(List<Bundle> bundles) {
+        // TODO: Render the result on mAppsView object
+    }
 }
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index ea0ff8b..dcdfb6e 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -19,7 +19,7 @@
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.clampToProgress;
 import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
+import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 6ad43ea..8016b2d 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -16,7 +16,7 @@
 
 package com.android.launcher3.anim;
 
-import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
+import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 
 import android.content.Context;
 import android.graphics.Path;
diff --git a/src/com/android/launcher3/anim/SpringAnimationBuilder.java b/src/com/android/launcher3/anim/SpringAnimationBuilder.java
index a9702b4..bd52158 100644
--- a/src/com/android/launcher3/anim/SpringAnimationBuilder.java
+++ b/src/com/android/launcher3/anim/SpringAnimationBuilder.java
@@ -25,7 +25,7 @@
 import androidx.annotation.FloatRange;
 import androidx.dynamicanimation.animation.SpringForce;
 
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController;
 
 /**
  * Utility class to build an object animator which follows the same path as a spring animation for
@@ -134,7 +134,7 @@
     }
 
     public SpringAnimationBuilder computeParams() {
-        int singleFrameMs = DefaultDisplay.getSingleFrameMs(mContext);
+        int singleFrameMs = DisplayController.getSingleFrameMs(mContext);
         double naturalFreq = Math.sqrt(mStiffness);
         double dampedFreq = naturalFreq * Math.sqrt(1 - mDampingRatio * mDampingRatio);
 
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 0ab74af..37d2d40 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -92,7 +92,7 @@
 
     // Keep as DeviceFlag to allow remote disable in emergency.
     public static final BooleanFlag ENABLE_SUGGESTED_ACTIONS_OVERVIEW = new DeviceFlag(
-            "ENABLE_SUGGESTED_ACTIONS_OVERVIEW", false, "Show chip hints on the overview screen");
+            "ENABLE_SUGGESTED_ACTIONS_OVERVIEW", true, "Show chip hints on the overview screen");
 
 
     public static final BooleanFlag ENABLE_DEVICE_SEARCH = getDebugFlag(
@@ -142,10 +142,6 @@
     public static final BooleanFlag ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER = getDebugFlag(
             "ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", true, "Show launcher preview in grid picker");
 
-    public static final BooleanFlag ENABLE_OVERVIEW_ACTIONS = getDebugFlag(
-            "ENABLE_OVERVIEW_ACTIONS", true, "Show app actions instead of the shelf in Overview."
-            + " As part of this decoupling, also distinguish swipe up from nav bar vs above it.");
-
     // Keep as DeviceFlag for remote disable in emergency.
     public static final BooleanFlag ENABLE_OVERVIEW_SELECTIONS = new DeviceFlag(
             "ENABLE_OVERVIEW_SELECTIONS", true, "Show Select Mode button in Overview Actions");
@@ -161,9 +157,9 @@
             "ENABLE_UNIVERSAL_SMARTSPACE", false,
             "Replace Smartspace with a version rendered by System UI.");
 
-    public static final BooleanFlag ENABLE_LSQ_VELOCITY_PROVIDER = getDebugFlag(
-            "ENABLE_LSQ_VELOCITY_PROVIDER", true,
-            "Use Least Square algorithm for motion pause detection.");
+    public static final BooleanFlag ENABLE_SYSTEM_VELOCITY_PROVIDER = getDebugFlag(
+            "ENABLE_SYSTEM_VELOCITY_PROVIDER", true,
+            "Use system VelocityTracker's algorithm for motion pause detection.");
 
     public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS =
             getDebugFlag(
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index d8eb838..cca9836 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -117,7 +117,8 @@
  *   4) Measure and draw the view on a canvas
  */
 @TargetApi(Build.VERSION_CODES.O)
-public class LauncherPreviewRenderer {
+public class LauncherPreviewRenderer extends ContextThemeWrapper
+        implements ActivityContext, WorkspaceLayoutManager, LayoutInflater.Factory2 {
 
     private static final String TAG = "LauncherPreviewRenderer";
 
@@ -211,10 +212,14 @@
     private final DeviceProfile mDp;
     private final boolean mMigrated;
     private final Rect mInsets;
-
     private final WorkspaceItemInfo mWorkspaceItemInfo;
+    private final LayoutInflater mHomeElementInflater;
+    private final InsettableFrameLayout mRootView;
+    private final Hotseat mHotseat;
+    private final CellLayout mWorkspace;
 
     public LauncherPreviewRenderer(Context context, InvariantDeviceProfile idp, boolean migrated) {
+        super(context, R.style.AppTheme);
         mUiHandler = new Handler(Looper.getMainLooper());
         mContext = context;
         mIdp = idp;
@@ -239,291 +244,286 @@
         mWorkspaceItemInfo.intent = new Intent();
         mWorkspaceItemInfo.contentDescription = mWorkspaceItemInfo.title =
                 context.getString(R.string.label_application);
+
+        mHomeElementInflater = LayoutInflater.from(
+                new ContextThemeWrapper(this, R.style.HomeScreenElementTheme));
+        mHomeElementInflater.setFactory2(this);
+
+        mRootView = (InsettableFrameLayout) mHomeElementInflater.inflate(
+                R.layout.launcher_preview_layout, null, false);
+        mRootView.setInsets(mInsets);
+        measureView(mRootView, mDp.widthPx, mDp.heightPx);
+
+        mHotseat = mRootView.findViewById(R.id.hotseat);
+        mHotseat.resetLayout(false);
+
+        mWorkspace = mRootView.findViewById(R.id.workspace);
+        mWorkspace.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingLeftRightPx,
+                mDp.workspacePadding.top,
+                mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
+                mDp.workspacePadding.bottom);
     }
 
     /** Populate preview and render it. */
     public View getRenderedView() {
-        MainThreadRenderer renderer = new MainThreadRenderer(mContext);
-        renderer.populate();
-        return renderer.mRootView;
+        populate();
+        return mRootView;
     }
 
-    private class MainThreadRenderer extends ContextThemeWrapper
-            implements ActivityContext, WorkspaceLayoutManager, LayoutInflater.Factory2 {
+    public boolean shouldShowRealLauncherPreview() {
+        return ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get();
+    }
 
-        private final LayoutInflater mHomeElementInflater;
-        private final InsettableFrameLayout mRootView;
+    public boolean shouldShowQsb() {
+        return FeatureFlags.QSB_ON_FIRST_SCREEN;
+    }
 
-        private final Hotseat mHotseat;
-        private final CellLayout mWorkspace;
+    @Override
+    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+        if ("TextClock".equals(name)) {
+            // Workaround for TextClock accessing handler for unregistering ticker.
+            return new TextClock(context, attrs) {
 
-        MainThreadRenderer(Context context) {
-            super(context, R.style.AppTheme);
-
-            mHomeElementInflater = LayoutInflater.from(
-                    new ContextThemeWrapper(this, R.style.HomeScreenElementTheme));
-            mHomeElementInflater.setFactory2(this);
-
-            mRootView = (InsettableFrameLayout) mHomeElementInflater.inflate(
-                    R.layout.launcher_preview_layout, null, false);
-            mRootView.setInsets(mInsets);
-            measureView(mRootView, mDp.widthPx, mDp.heightPx);
-
-            mHotseat = mRootView.findViewById(R.id.hotseat);
-            mHotseat.resetLayout(false);
-
-            mWorkspace = mRootView.findViewById(R.id.workspace);
-            mWorkspace.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingLeftRightPx,
-                    mDp.workspacePadding.top,
-                    mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
-                    mDp.workspacePadding.bottom);
+                @Override
+                public Handler getHandler() {
+                    return mUiHandler;
+                }
+            };
+        } else if (!"fragment".equals(name)) {
+            return null;
         }
 
-        @Override
-        public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
-            if ("TextClock".equals(name)) {
-                // Workaround for TextClock accessing handler for unregistering ticker.
-                return new TextClock(context, attrs) {
+        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PreviewFragment);
+        FragmentWithPreview f = (FragmentWithPreview) Fragment.instantiate(
+                context, ta.getString(R.styleable.PreviewFragment_android_name));
+        f.enterPreviewMode(context);
+        f.onInit(null);
 
-                    @Override
-                    public Handler getHandler() {
-                        return mUiHandler;
-                    }
-                };
-            } else if (!"fragment".equals(name)) {
-                return null;
-            }
+        View view = f.onCreateView(LayoutInflater.from(context), (ViewGroup) parent, null);
+        view.setId(ta.getInt(R.styleable.PreviewFragment_android_id, View.NO_ID));
+        return view;
+    }
 
-            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PreviewFragment);
-            FragmentWithPreview f = (FragmentWithPreview) Fragment.instantiate(
-                    context, ta.getString(R.styleable.PreviewFragment_android_name));
-            f.enterPreviewMode(context);
-            f.onInit(null);
+    @Override
+    public View onCreateView(String name, Context context, AttributeSet attrs) {
+        return onCreateView(null, name, context, attrs);
+    }
 
-            View view = f.onCreateView(LayoutInflater.from(context), (ViewGroup) parent, null);
-            view.setId(ta.getInt(R.styleable.PreviewFragment_android_id, View.NO_ID));
-            return view;
+    @Override
+    public BaseDragLayer getDragLayer() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DeviceProfile getDeviceProfile() {
+        return mDp;
+    }
+
+    @Override
+    public Hotseat getHotseat() {
+        return mHotseat;
+    }
+
+    @Override
+    public CellLayout getScreenWithId(int screenId) {
+        return mWorkspace;
+    }
+
+    private void inflateAndAddIcon(WorkspaceItemInfo info) {
+        BubbleTextView icon = (BubbleTextView) mHomeElementInflater.inflate(
+                R.layout.app_icon, mWorkspace, false);
+        icon.applyFromWorkspaceItem(info);
+        addInScreenFromBind(icon, info);
+    }
+
+    private void inflateAndAddFolder(FolderInfo info) {
+        FolderIcon folderIcon = FolderIcon.inflateIcon(R.layout.folder_icon, this, mWorkspace,
+                info);
+        addInScreenFromBind(folderIcon, info);
+    }
+
+    private void inflateAndAddWidgets(
+            LauncherAppWidgetInfo info,
+            Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap) {
+        if (widgetProviderInfoMap == null) {
+            return;
         }
-
-        @Override
-        public View onCreateView(String name, Context context, AttributeSet attrs) {
-            return onCreateView(null, name, context, attrs);
+        AppWidgetProviderInfo providerInfo = widgetProviderInfoMap.get(
+                new ComponentKey(info.providerName, info.user));
+        if (providerInfo == null) {
+            return;
         }
+        inflateAndAddWidgets(info, LauncherAppWidgetProviderInfo.fromProviderInfo(
+                getApplicationContext(), providerInfo));
+    }
 
-        @Override
-        public BaseDragLayer getDragLayer() {
-            throw new UnsupportedOperationException();
+    private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
+        WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
+                info.providerName);
+        if (widgetItem == null) {
+            return;
         }
+        inflateAndAddWidgets(info, widgetItem.widgetInfo);
+    }
 
-        @Override
-        public DeviceProfile getDeviceProfile() {
-            return mDp;
-        }
+    private void inflateAndAddWidgets(
+            LauncherAppWidgetInfo info, LauncherAppWidgetProviderInfo providerInfo) {
+        AppWidgetHostView view = new AppWidgetHostView(mContext);
+        view.setAppWidget(-1, providerInfo);
+        view.updateAppWidget(null);
+        view.setTag(info);
+        addInScreenFromBind(view, info);
+    }
 
-        @Override
-        public Hotseat getHotseat() {
-            return mHotseat;
-        }
-
-        @Override
-        public CellLayout getScreenWithId(int screenId) {
-            return mWorkspace;
-        }
-
-        private void inflateAndAddIcon(WorkspaceItemInfo info) {
-            BubbleTextView icon = (BubbleTextView) mHomeElementInflater.inflate(
-                    R.layout.app_icon, mWorkspace, false);
-            icon.applyFromWorkspaceItem(info);
-            addInScreenFromBind(icon, info);
-        }
-
-        private void inflateAndAddFolder(FolderInfo info) {
-            FolderIcon folderIcon = FolderIcon.inflateIcon(R.layout.folder_icon, this, mWorkspace,
-                    info);
-            addInScreenFromBind(folderIcon, info);
-        }
-
-        private void inflateAndAddWidgets(LauncherAppWidgetInfo info,
-                Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap) {
-            if (widgetProviderInfoMap == null) {
-                return;
-            }
-            AppWidgetProviderInfo providerInfo = widgetProviderInfoMap.get(
-                    new ComponentKey(info.providerName, info.user));
-            if (providerInfo == null) {
-                return;
-            }
-            inflateAndAddWidgets(info, LauncherAppWidgetProviderInfo.fromProviderInfo(
-                    getApplicationContext(), providerInfo));
-        }
-
-        private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
-            WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
-                    info.providerName);
-            if (widgetItem == null) {
-                return;
-            }
-            inflateAndAddWidgets(info, widgetItem.widgetInfo);
-        }
-
-        private void inflateAndAddWidgets(LauncherAppWidgetInfo info,
-                LauncherAppWidgetProviderInfo providerInfo) {
-            AppWidgetHostView view = new AppWidgetHostView(mContext);
-            view.setAppWidget(-1, providerInfo);
-            view.updateAppWidget(null);
-            view.setTag(info);
+    private void inflateAndAddPredictedIcon(WorkspaceItemInfo info) {
+        View view = PredictedAppIconInflater.inflate(mHomeElementInflater, mWorkspace, info);
+        if (view != null) {
             addInScreenFromBind(view, info);
         }
+    }
 
-        private void inflateAndAddPredictedIcon(WorkspaceItemInfo info) {
-            View view = PredictedAppIconInflater.inflate(mHomeElementInflater, mWorkspace, info);
-            if (view != null) {
-                addInScreenFromBind(view, info);
-            }
+    private void dispatchVisibilityAggregated(View view, boolean isVisible) {
+        // Similar to View.dispatchVisibilityAggregated implementation.
+        final boolean thisVisible = view.getVisibility() == VISIBLE;
+        if (thisVisible || !isVisible) {
+            view.onVisibilityAggregated(isVisible);
         }
 
-        private void dispatchVisibilityAggregated(View view, boolean isVisible) {
-            // Similar to View.dispatchVisibilityAggregated implementation.
-            final boolean thisVisible = view.getVisibility() == VISIBLE;
-            if (thisVisible || !isVisible) {
-                view.onVisibilityAggregated(isVisible);
-            }
+        if (view instanceof ViewGroup) {
+            isVisible = thisVisible && isVisible;
+            ViewGroup vg = (ViewGroup) view;
+            int count = vg.getChildCount();
 
-            if (view instanceof ViewGroup) {
-                isVisible = thisVisible && isVisible;
-                ViewGroup vg = (ViewGroup) view;
-                int count = vg.getChildCount();
-
-                for (int i = 0; i < count; i++) {
-                    dispatchVisibilityAggregated(vg.getChildAt(i), isVisible);
-                }
+            for (int i = 0; i < count; i++) {
+                dispatchVisibilityAggregated(vg.getChildAt(i), isVisible);
             }
         }
+    }
 
-        private void populate() {
-            if (ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get()) {
-                WorkspaceFetcher fetcher;
-                PreviewContext previewContext = null;
-                if (mMigrated) {
-                    previewContext = new PreviewContext(mContext, mIdp);
-                    LauncherAppState appForPreview = new LauncherAppState(
-                            previewContext, null /* iconCacheFileName */);
-                    fetcher = new WorkspaceItemsInfoFromPreviewFetcher(appForPreview);
-                    MODEL_EXECUTOR.execute(fetcher);
-                } else {
-                    fetcher = new WorkspaceItemsInfoFetcher();
-                    LauncherAppState.getInstance(mContext).getModel().enqueueModelUpdateTask(
-                            (LauncherModel.ModelUpdateTask) fetcher);
-                }
-                WorkspaceResult workspaceResult = fetcher.get();
-                if (previewContext != null) {
-                    previewContext.onDestroy();
-                }
-
-                if (workspaceResult == null) {
-                    return;
-                }
-
-                // Separate the items that are on the current screen, and all the other remaining
-                // items
-                ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
-                ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>();
-                ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>();
-                ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>();
-
-                filterCurrentWorkspaceItems(0 /* currentScreenId */,
-                        workspaceResult.mWorkspaceItems, currentWorkspaceItems,
-                        otherWorkspaceItems);
-                filterCurrentWorkspaceItems(0 /* currentScreenId */, workspaceResult.mAppWidgets,
-                        currentAppWidgets, otherAppWidgets);
-                sortWorkspaceItemsSpatially(mIdp, currentWorkspaceItems);
-
-                for (ItemInfo itemInfo : currentWorkspaceItems) {
-                    switch (itemInfo.itemType) {
-                        case Favorites.ITEM_TYPE_APPLICATION:
-                        case Favorites.ITEM_TYPE_SHORTCUT:
-                        case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
-                            inflateAndAddIcon((WorkspaceItemInfo) itemInfo);
-                            break;
-                        case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
-                            inflateAndAddFolder((FolderInfo) itemInfo);
-                            break;
-                        default:
-                            break;
-                    }
-                }
-                for (ItemInfo itemInfo : currentAppWidgets) {
-                    switch (itemInfo.itemType) {
-                        case Favorites.ITEM_TYPE_APPWIDGET:
-                        case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
-                            if (mMigrated) {
-                                inflateAndAddWidgets((LauncherAppWidgetInfo) itemInfo,
-                                        workspaceResult.mWidgetProvidersMap);
-                            } else {
-                                inflateAndAddWidgets((LauncherAppWidgetInfo) itemInfo,
-                                        workspaceResult.mWidgetsModel);
-                            }
-                            break;
-                        default:
-                            break;
-                    }
-                }
-
-                IntArray ranks = getMissingHotseatRanks(currentWorkspaceItems,
-                        mIdp.numHotseatIcons);
-                int count = Math.min(ranks.size(), workspaceResult.mCachedPredictedItems.size());
-                for (int i = 0; i < count; i++) {
-                    AppInfo appInfo = workspaceResult.mCachedPredictedItems.get(i);
-                    int rank = ranks.get(i);
-                    WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(appInfo);
-                    itemInfo.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
-                    itemInfo.rank = rank;
-                    itemInfo.cellX = mHotseat.getCellXFromOrder(rank);
-                    itemInfo.cellY = mHotseat.getCellYFromOrder(rank);
-                    itemInfo.screenId = rank;
-                    inflateAndAddPredictedIcon(itemInfo);
-                }
+    private void populate() {
+        if (shouldShowRealLauncherPreview()) {
+            WorkspaceFetcher fetcher;
+            PreviewContext previewContext = null;
+            if (mMigrated) {
+                previewContext = new PreviewContext(mContext, mIdp);
+                LauncherAppState appForPreview = new LauncherAppState(
+                        previewContext, null /* iconCacheFileName */);
+                fetcher = new WorkspaceItemsInfoFromPreviewFetcher(appForPreview);
+                MODEL_EXECUTOR.execute(fetcher);
             } else {
-                // Add hotseat icons
-                for (int i = 0; i < mIdp.numHotseatIcons; i++) {
-                    WorkspaceItemInfo info = new WorkspaceItemInfo(mWorkspaceItemInfo);
-                    info.container = Favorites.CONTAINER_HOTSEAT;
-                    info.screenId = i;
-                    inflateAndAddIcon(info);
-                }
-                // Add workspace icons
-                for (int i = 0; i < mIdp.numColumns; i++) {
-                    WorkspaceItemInfo info = new WorkspaceItemInfo(mWorkspaceItemInfo);
-                    info.container = Favorites.CONTAINER_DESKTOP;
-                    info.screenId = 0;
-                    info.cellX = i;
-                    info.cellY = mIdp.numRows - 1;
-                    inflateAndAddIcon(info);
-                }
+                fetcher = new WorkspaceItemsInfoFetcher();
+                LauncherAppState.getInstance(mContext).getModel().enqueueModelUpdateTask(
+                        (LauncherModel.ModelUpdateTask) fetcher);
+            }
+            WorkspaceResult workspaceResult = fetcher.get();
+            if (previewContext != null) {
+                previewContext.onDestroy();
             }
 
-            // Add first page QSB
-            if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
-                View qsb = mHomeElementInflater.inflate(
-                        R.layout.search_container_workspace, mWorkspace, false);
-                CellLayout.LayoutParams lp =
-                        new CellLayout.LayoutParams(0, 0, mWorkspace.getCountX(), 1);
-                lp.canReorder = false;
-                mWorkspace.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true);
+            if (workspaceResult == null) {
+                return;
             }
 
-            // Setup search view
-            SearchUiManager searchUiManager =
-                    mRootView.findViewById(R.id.search_container_all_apps);
-            mRootView.findViewById(R.id.apps_view).setTranslationY(
-                    mDp.heightPx - searchUiManager.getScrollRangeDelta(mInsets));
-
-            measureView(mRootView, mDp.widthPx, mDp.heightPx);
-            dispatchVisibilityAggregated(mRootView, true);
-            measureView(mRootView, mDp.widthPx, mDp.heightPx);
-            // Additional measure for views which use auto text size API
-            measureView(mRootView, mDp.widthPx, mDp.heightPx);
+            // Separate the items that are on the current screen, and the other remaining items.
+            ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
+            ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>();
+            ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>();
+            ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>();
+            filterCurrentWorkspaceItems(0 /* currentScreenId */,
+                    workspaceResult.mWorkspaceItems, currentWorkspaceItems,
+                    otherWorkspaceItems);
+            filterCurrentWorkspaceItems(0 /* currentScreenId */, workspaceResult.mAppWidgets,
+                    currentAppWidgets, otherAppWidgets);
+            sortWorkspaceItemsSpatially(mIdp, currentWorkspaceItems);
+            for (ItemInfo itemInfo : currentWorkspaceItems) {
+                switch (itemInfo.itemType) {
+                    case Favorites.ITEM_TYPE_APPLICATION:
+                    case Favorites.ITEM_TYPE_SHORTCUT:
+                    case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+                        inflateAndAddIcon((WorkspaceItemInfo) itemInfo);
+                        break;
+                    case Favorites.ITEM_TYPE_FOLDER:
+                        inflateAndAddFolder((FolderInfo) itemInfo);
+                        break;
+                    default:
+                        break;
+                }
+            }
+            for (ItemInfo itemInfo : currentAppWidgets) {
+                switch (itemInfo.itemType) {
+                    case Favorites.ITEM_TYPE_APPWIDGET:
+                    case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
+                        if (mMigrated) {
+                            inflateAndAddWidgets((LauncherAppWidgetInfo) itemInfo,
+                                    workspaceResult.mWidgetProvidersMap);
+                        } else {
+                            inflateAndAddWidgets((LauncherAppWidgetInfo) itemInfo,
+                                    workspaceResult.mWidgetsModel);
+                        }
+                        break;
+                    default:
+                        break;
+                }
+            }
+            IntArray ranks = getMissingHotseatRanks(currentWorkspaceItems,
+                    mIdp.numHotseatIcons);
+            int count = Math.min(ranks.size(), workspaceResult.mCachedPredictedItems.size());
+            for (int i = 0; i < count; i++) {
+                AppInfo appInfo = workspaceResult.mCachedPredictedItems.get(i);
+                int rank = ranks.get(i);
+                WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(appInfo);
+                itemInfo.container = Favorites.CONTAINER_HOTSEAT_PREDICTION;
+                itemInfo.rank = rank;
+                itemInfo.cellX = mHotseat.getCellXFromOrder(rank);
+                itemInfo.cellY = mHotseat.getCellYFromOrder(rank);
+                itemInfo.screenId = rank;
+                inflateAndAddPredictedIcon(itemInfo);
+            }
+        } else {
+            // Add hotseat icons
+            for (int i = 0; i < mIdp.numHotseatIcons; i++) {
+                WorkspaceItemInfo info = new WorkspaceItemInfo(mWorkspaceItemInfo);
+                info.container = Favorites.CONTAINER_HOTSEAT;
+                info.screenId = i;
+                inflateAndAddIcon(info);
+            }
+            // Add workspace icons
+            for (int i = 0; i < mIdp.numColumns; i++) {
+                WorkspaceItemInfo info = new WorkspaceItemInfo(mWorkspaceItemInfo);
+                info.container = Favorites.CONTAINER_DESKTOP;
+                info.screenId = 0;
+                info.cellX = i;
+                info.cellY = mIdp.numRows - 1;
+                inflateAndAddIcon(info);
+            }
         }
+
+        // Add first page QSB
+        if (shouldShowQsb()) {
+            View qsb = mHomeElementInflater.inflate(
+                    R.layout.search_container_workspace, mWorkspace, false);
+            CellLayout.LayoutParams lp =
+                    new CellLayout.LayoutParams(0, 0, mWorkspace.getCountX(), 1);
+            lp.canReorder = false;
+            mWorkspace.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true);
+        }
+
+        // Setup search view
+        SearchUiManager searchUiManager =
+                mRootView.findViewById(R.id.search_container_all_apps);
+        mRootView.findViewById(R.id.apps_view).setTranslationY(
+                mDp.heightPx - searchUiManager.getScrollRangeDelta(mInsets));
+        ViewGroup searchView = (ViewGroup) searchUiManager;
+        searchView.setEnabled(false);
+        for (int i = 0; i < searchView.getChildCount(); i++) {
+            searchView.getChildAt(i).setEnabled(false);
+        }
+
+        measureView(mRootView, mDp.widthPx, mDp.heightPx);
+        dispatchVisibilityAggregated(mRootView, true);
+        measureView(mRootView, mDp.widthPx, mDp.heightPx);
+        // Additional measure for views which use auto text size API
+        measureView(mRootView, mDp.widthPx, mDp.heightPx);
     }
 
     private static void measureView(View view, int width, int height) {
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 6ff1254..beb5b68 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -312,7 +312,13 @@
                 handler.setStateWithAnimation(state, mConfig, builder);
             }
         }
-        builder.addListener(new AnimationSuccessListener() {
+        builder.addListener(createStateAnimationListener(state));
+        mConfig.setAnimation(builder.buildAnim(), state);
+        return builder;
+    }
+
+    private AnimatorListener createStateAnimationListener(STATE_TYPE state) {
+        return new AnimationSuccessListener() {
 
             @Override
             public void onAnimationStart(Animator animation) {
@@ -327,9 +333,7 @@
                 }
                 onStateTransitionEnd(state);
             }
-        });
-        mConfig.setAnimation(builder.buildAnim(), state);
-        return builder;
+        };
     }
 
     private void onStateTransitionStart(STATE_TYPE state) {
@@ -397,6 +401,19 @@
     }
 
     /**
+     * @see #setCurrentAnimation(AnimatorSet, Animator...). Using this method tells the StateManager
+     * that this is a custom animation to the given state, and thus the StateManager will add an
+     * animation listener to call {@link #onStateTransitionStart} and {@link #onStateTransitionEnd}.
+     * @param anim The custom animation to the given state.
+     * @param toState The state we are animating towards.
+     */
+    public void setCurrentAnimation(AnimatorSet anim, STATE_TYPE toState) {
+        cancelAnimation();
+        setCurrentAnimation(anim);
+        anim.addListener(createStateAnimationListener(toState));
+    }
+
+    /**
      * Sets the animation as the current state animation, i.e., canceled when
      * starting another animation and may block some launcher interactions while running.
      *
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 8616881..30f8fb0 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -27,12 +27,11 @@
     public static final int NORMAL_STATE_ORDINAL = 0;
     public static final int SPRING_LOADED_STATE_ORDINAL = 1;
     public static final int OVERVIEW_STATE_ORDINAL = 2;
-    public static final int OVERVIEW_PEEK_STATE_ORDINAL = 3;
-    public static final int OVERVIEW_MODAL_TASK_STATE_ORDINAL = 4;
-    public static final int QUICK_SWITCH_STATE_ORDINAL = 5;
-    public static final int ALL_APPS_STATE_ORDINAL = 6;
-    public static final int BACKGROUND_APP_STATE_ORDINAL = 7;
-    public static final int HINT_STATE_ORDINAL = 8;
+    public static final int OVERVIEW_MODAL_TASK_STATE_ORDINAL = 3;
+    public static final int QUICK_SWITCH_STATE_ORDINAL = 4;
+    public static final int ALL_APPS_STATE_ORDINAL = 5;
+    public static final int BACKGROUND_APP_STATE_ORDINAL = 6;
+    public static final int HINT_STATE_ORDINAL = 7;
     public static final String TAPL_EVENTS_TAG = "TaplEvents";
     public static final String SEQUENCE_MAIN = "Main";
     public static final String SEQUENCE_TIS = "TIS";
@@ -46,8 +45,6 @@
                 return "SpringLoaded";
             case OVERVIEW_STATE_ORDINAL:
                 return "Overview";
-            case OVERVIEW_PEEK_STATE_ORDINAL:
-                return "OverviewPeek";
             case OVERVIEW_MODAL_TASK_STATE_ORDINAL:
                 return "OverviewModal";
             case QUICK_SWITCH_STATE_ORDINAL:
@@ -98,7 +95,6 @@
     public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
     public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing";
 
-    public static final String REQUEST_OVERVIEW_ACTIONS_ENABLED = "overview-actions-enabled";
     public static final String REQUEST_OVERVIEW_SHARE_ENABLED = "overview-share-enabled";
 
     public static boolean sDisableSensorRotation;
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 02ca926..8ee5a6e 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -26,7 +26,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
 import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.PLAY_NON_ATOMIC;
-import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
+import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
diff --git a/src/com/android/launcher3/util/ConfigMonitor.java b/src/com/android/launcher3/util/ConfigMonitor.java
index 0f81520..b3b69f6 100644
--- a/src/com/android/launcher3/util/ConfigMonitor.java
+++ b/src/com/android/launcher3/util/ConfigMonitor.java
@@ -26,14 +26,16 @@
 import android.graphics.Point;
 import android.util.Log;
 
+import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
+import com.android.launcher3.util.DisplayController.Info;
+
 import java.util.function.Consumer;
 
 /**
  * {@link BroadcastReceiver} which watches configuration changes and
  * notifies the callback in case changes which affect the device profile occur.
  */
-public class ConfigMonitor extends BroadcastReceiver implements
-        DefaultDisplay.DisplayInfoChangeListener {
+public class ConfigMonitor extends BroadcastReceiver implements DisplayInfoChangeListener {
 
     private static final String TAG = "ConfigMonitor";
 
@@ -57,9 +59,9 @@
         mFontScale = config.fontScale;
         mDensity = config.densityDpi;
 
-        DefaultDisplay display = DefaultDisplay.INSTANCE.get(context);
+        DisplayController.DisplayHolder display = DisplayController.getDefaultDisplay(context);
         display.addChangeListener(this);
-        DefaultDisplay.Info displayInfo = display.getInfo();
+        Info displayInfo = display.getInfo();
         mDisplayId = displayInfo.id;
 
         mRealSize = new Point(displayInfo.realSize);
@@ -82,7 +84,7 @@
     }
 
     @Override
-    public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) {
+    public void onDisplayInfoChanged(Info info, int flags) {
         if (info.id != mDisplayId) {
             return;
         }
@@ -113,8 +115,7 @@
     public void unregister() {
         try {
             mContext.unregisterReceiver(this);
-            DefaultDisplay display = DefaultDisplay.INSTANCE.get(mContext);
-            display.removeChangeListener(this);
+            DisplayController.getDefaultDisplay(mContext).removeChangeListener(this);
         } catch (Exception e) {
             Log.e(TAG, "Failed to unregister config monitor", e);
         }
diff --git a/src/com/android/launcher3/util/DefaultDisplay.java b/src/com/android/launcher3/util/DefaultDisplay.java
deleted file mode 100644
index 35788a5..0000000
--- a/src/com/android/launcher3/util/DefaultDisplay.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.util;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-
-import android.content.Context;
-import android.graphics.Point;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.Handler;
-import android.os.Message;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Display;
-
-import androidx.annotation.VisibleForTesting;
-
-import java.util.ArrayList;
-
-/**
- * Utility class to cache properties of default display to avoid a system RPC on every call.
- */
-public class DefaultDisplay implements DisplayListener {
-
-    public static final MainThreadInitializedObject<DefaultDisplay> INSTANCE =
-            new MainThreadInitializedObject<>(DefaultDisplay::new);
-
-    private static final String TAG = "DefaultDisplay";
-
-    public static final int CHANGE_SIZE = 1 << 0;
-    public static final int CHANGE_ROTATION = 1 << 1;
-    public static final int CHANGE_FRAME_DELAY = 1 << 2;
-
-    public static final int CHANGE_ALL = CHANGE_SIZE | CHANGE_ROTATION | CHANGE_FRAME_DELAY;
-
-    private final Context mDisplayContext;
-    private final int mId;
-    private final ArrayList<DisplayInfoChangeListener> mListeners = new ArrayList<>();
-    private final Handler mChangeHandler;
-    private Info mInfo;
-
-    private DefaultDisplay(Context context) {
-        DisplayManager dm = context.getSystemService(DisplayManager.class);
-        // Use application context to create display context so that it can have its own Resources.
-        mDisplayContext = context.getApplicationContext().createDisplayContext(
-                dm.getDisplay(DEFAULT_DISPLAY));
-        // Note that the Display object must be obtained from DisplayManager which is associated to
-        // the display context, so the Display is isolated from Activity and Application to provide
-        // the actual state of device that excludes the additional adjustment and override.
-        mInfo = new Info(mDisplayContext);
-        mId = mInfo.id;
-        mChangeHandler = new Handler(this::onChange);
-
-        dm.registerDisplayListener(this, UI_HELPER_EXECUTOR.getHandler());
-    }
-
-    @Override
-    public final void onDisplayAdded(int displayId) {  }
-
-    @Override
-    public final void onDisplayRemoved(int displayId) { }
-
-    @Override
-    public final void onDisplayChanged(int displayId) {
-        if (displayId != mId) {
-            return;
-        }
-
-        Info oldInfo = mInfo;
-        Info info = new Info(mDisplayContext);
-
-        int change = 0;
-        if (info.hasDifferentSize(oldInfo)) {
-            change |= CHANGE_SIZE;
-        }
-        if (oldInfo.rotation != info.rotation) {
-            change |= CHANGE_ROTATION;
-        }
-        if (info.singleFrameMs != oldInfo.singleFrameMs) {
-            change |= CHANGE_FRAME_DELAY;
-        }
-
-        if (change != 0) {
-            mInfo = info;
-            mChangeHandler.sendEmptyMessage(change);
-        }
-    }
-
-    public static int getSingleFrameMs(Context context) {
-        return INSTANCE.get(context).getInfo().singleFrameMs;
-    }
-
-    public Info getInfo() {
-        return mInfo;
-    }
-
-    public void addChangeListener(DisplayInfoChangeListener listener) {
-        mListeners.add(listener);
-    }
-
-    public void removeChangeListener(DisplayInfoChangeListener listener) {
-        mListeners.remove(listener);
-    }
-
-    private boolean onChange(Message msg) {
-        for (int i = mListeners.size() - 1; i >= 0; i--) {
-            mListeners.get(i).onDisplayInfoChanged(mInfo, msg.what);
-        }
-        return true;
-    }
-
-    public static class Info {
-
-        public final int id;
-        public final int rotation;
-        public final int singleFrameMs;
-
-        public final Point realSize;
-        public final Point smallestSize;
-        public final Point largestSize;
-
-        public final DisplayMetrics metrics;
-
-        @VisibleForTesting
-        public Info(int id, int rotation, int singleFrameMs, Point realSize, Point smallestSize,
-                Point largestSize, DisplayMetrics metrics) {
-            this.id = id;
-            this.rotation = rotation;
-            this.singleFrameMs = singleFrameMs;
-            this.realSize = realSize;
-            this.smallestSize = smallestSize;
-            this.largestSize = largestSize;
-            this.metrics = metrics;
-        }
-
-        private Info(Context context) {
-            this(context, context.getSystemService(DisplayManager.class)
-                    .getDisplay(DEFAULT_DISPLAY));
-        }
-
-        public Info(Context context, Display display) {
-            id = display.getDisplayId();
-            rotation = display.getRotation();
-
-            float refreshRate = display.getRefreshRate();
-            singleFrameMs = refreshRate > 0 ? (int) (1000 / refreshRate) : 16;
-
-            realSize = new Point();
-            smallestSize = new Point();
-            largestSize = new Point();
-            display.getRealSize(realSize);
-            display.getCurrentSizeRange(smallestSize, largestSize);
-
-            metrics = context.getResources().getDisplayMetrics();
-        }
-
-        private boolean hasDifferentSize(Info info) {
-            if (!realSize.equals(info.realSize)
-                    && !realSize.equals(info.realSize.y, info.realSize.x)) {
-                Log.d(TAG, String.format("Display size changed from %s to %s",
-                        info.realSize, realSize));
-                return true;
-            }
-
-            if (!smallestSize.equals(info.smallestSize) || !largestSize.equals(info.largestSize)) {
-                Log.d(TAG, String.format("Available size changed from [%s, %s] to [%s, %s]",
-                        smallestSize, largestSize, info.smallestSize, info.largestSize));
-                return true;
-            }
-
-            return false;
-        }
-    }
-
-    /**
-     * Interface for listening for display changes
-     */
-    public interface DisplayInfoChangeListener {
-
-        void onDisplayInfoChanged(Info info, int flags);
-    }
-}
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
new file mode 100644
index 0000000..e5c8441
--- /dev/null
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Display;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.util.ArrayList;
+
+/**
+ * Utility class to cache properties of default display to avoid a system RPC on every call.
+ */
+public class DisplayController implements DisplayListener {
+
+    private static final String TAG = "DisplayController";
+
+    public static final MainThreadInitializedObject<DisplayController> INSTANCE =
+            new MainThreadInitializedObject<>(DisplayController::new);
+
+    private final SparseArray<DisplayHolder> mOtherDisplays = new SparseArray<>(0);
+    // We store the default display separately, to avoid null checks for primary use case.
+    private final DisplayHolder mDefaultDisplay;
+
+    private final ArrayList<DisplayListChangeListener> mListListeners = new ArrayList<>();
+
+    private DisplayController(Context context) {
+        mDefaultDisplay = new DisplayHolder(context, DEFAULT_DISPLAY);
+
+        DisplayManager dm = context.getSystemService(DisplayManager.class);
+        dm.registerDisplayListener(this, UI_HELPER_EXECUTOR.getHandler());
+    }
+
+    @Override
+    public final void onDisplayAdded(int displayId) {
+        DisplayHolder holder = new DisplayHolder(mDefaultDisplay.mDisplayContext, displayId);
+        synchronized (mOtherDisplays) {
+            mOtherDisplays.put(displayId, holder);
+        }
+        MAIN_EXECUTOR.execute(() -> mListListeners.forEach(l-> l.onDisplayAdded(holder)));
+    }
+
+    @Override
+    public final void onDisplayRemoved(int displayId) {
+        synchronized (mOtherDisplays) {
+            mOtherDisplays.remove(displayId);
+        }
+        MAIN_EXECUTOR.execute(() -> mListListeners.forEach(l-> l.onDisplayRemoved(displayId)));
+    }
+
+    /**
+     * Returns the holder corresponding to the given display
+     */
+    public DisplayHolder getHolder(int displayId) {
+        if (displayId == mDefaultDisplay.mId) {
+            return mDefaultDisplay;
+        } else {
+            synchronized (mOtherDisplays) {
+                return mOtherDisplays.get(displayId);
+            }
+        }
+    }
+
+    /**
+     * Adds a listener for display list changes
+     */
+    public void addListChangeListener(DisplayListChangeListener listener) {
+        mListListeners.add(listener);
+    }
+
+    /**
+     * Removes a previously added display list change listener
+     */
+    public void removeListChangeListener(DisplayListChangeListener listener) {
+        mListListeners.remove(listener);
+    }
+
+    @Override
+    public final void onDisplayChanged(int displayId) {
+        DisplayHolder holder = getHolder(displayId);
+        if (holder != null) {
+            holder.handleOnChange();
+        }
+    }
+
+    public static int getSingleFrameMs(Context context) {
+        return getDefaultDisplay(context).getInfo().singleFrameMs;
+    }
+
+    public static DisplayHolder getDefaultDisplay(Context context) {
+        return INSTANCE.get(context).mDefaultDisplay;
+    }
+
+    /**
+     * A listener to receiving addition or removal of new displays
+     */
+    public interface DisplayListChangeListener {
+
+        /**
+         * Called when a new display is added
+         */
+        void onDisplayAdded(DisplayHolder holder);
+
+        /**
+         * Called when a previously added display is removed
+         */
+        void onDisplayRemoved(int displayId);
+    }
+
+    /**
+     * Interface for listening for display changes
+     */
+    public interface DisplayInfoChangeListener {
+
+        void onDisplayInfoChanged(Info info, int flags);
+    }
+
+    public static class DisplayHolder {
+
+        public static final int CHANGE_SIZE = 1 << 0;
+        public static final int CHANGE_ROTATION = 1 << 1;
+        public static final int CHANGE_FRAME_DELAY = 1 << 2;
+
+        public static final int CHANGE_ALL = CHANGE_SIZE | CHANGE_ROTATION | CHANGE_FRAME_DELAY;
+
+        final Context mDisplayContext;
+        final int mId;
+        private final ArrayList<DisplayInfoChangeListener> mListeners = new ArrayList<>();
+        private DisplayController.Info mInfo;
+
+        public DisplayHolder(Context context, int id) {
+            DisplayManager dm = context.getSystemService(DisplayManager.class);
+            // Use application context to create display context so that it can have its own
+            // Resources.
+            mDisplayContext = context.getApplicationContext()
+                    .createDisplayContext(dm.getDisplay(id));
+            // Note that the Display object must be obtained from DisplayManager which is
+            // associated to the display context, so the Display is isolated from Activity and
+            // Application to provide the actual state of device that excludes the additional
+            // adjustment and override.
+            mInfo = new DisplayController.Info(mDisplayContext);
+            mId = mInfo.id;
+        }
+
+        public void addChangeListener(DisplayInfoChangeListener listener) {
+            mListeners.add(listener);
+        }
+
+        public void removeChangeListener(DisplayInfoChangeListener listener) {
+            mListeners.remove(listener);
+        }
+
+        public DisplayController.Info getInfo() {
+            return mInfo;
+        }
+
+        protected void handleOnChange() {
+            Info oldInfo = mInfo;
+            Info info = new Info(mDisplayContext);
+
+            int change = 0;
+            if (info.hasDifferentSize(oldInfo)) {
+                change |= CHANGE_SIZE;
+            }
+            if (oldInfo.rotation != info.rotation) {
+                change |= CHANGE_ROTATION;
+            }
+            if (info.singleFrameMs != oldInfo.singleFrameMs) {
+                change |= CHANGE_FRAME_DELAY;
+            }
+
+            if (change != 0) {
+                mInfo = info;
+                final int flags = change;
+                MAIN_EXECUTOR.execute(() -> notifyChange(flags));
+            }
+        }
+
+        private void notifyChange(int flags) {
+            for (int i = mListeners.size() - 1; i >= 0; i--) {
+                mListeners.get(i).onDisplayInfoChanged(mInfo, flags);
+            }
+        }
+
+    }
+
+    public static class Info {
+
+        public final int id;
+        public final int rotation;
+        public final int singleFrameMs;
+
+        public final Point realSize;
+        public final Point smallestSize;
+        public final Point largestSize;
+
+        public final DisplayMetrics metrics;
+
+        @VisibleForTesting
+        public Info(int id, int rotation, int singleFrameMs, Point realSize, Point smallestSize,
+                Point largestSize, DisplayMetrics metrics) {
+            this.id = id;
+            this.rotation = rotation;
+            this.singleFrameMs = singleFrameMs;
+            this.realSize = realSize;
+            this.smallestSize = smallestSize;
+            this.largestSize = largestSize;
+            this.metrics = metrics;
+        }
+
+        private Info(Context context) {
+            this(context, context.getSystemService(DisplayManager.class)
+                    .getDisplay(DEFAULT_DISPLAY));
+        }
+
+        public Info(Context context, Display display) {
+            id = display.getDisplayId();
+            rotation = display.getRotation();
+
+            float refreshRate = display.getRefreshRate();
+            singleFrameMs = refreshRate > 0 ? (int) (1000 / refreshRate) : 16;
+
+            realSize = new Point();
+            smallestSize = new Point();
+            largestSize = new Point();
+            display.getRealSize(realSize);
+            display.getCurrentSizeRange(smallestSize, largestSize);
+
+            metrics = context.getResources().getDisplayMetrics();
+        }
+
+        private boolean hasDifferentSize(Info info) {
+            if (!realSize.equals(info.realSize)
+                    && !realSize.equals(info.realSize.y, info.realSize.x)) {
+                Log.d(TAG, String.format("Display size changed from %s to %s",
+                        info.realSize, realSize));
+                return true;
+            }
+
+            if (!smallestSize.equals(info.smallestSize) || !largestSize.equals(info.largestSize)) {
+                Log.d(TAG, String.format("Available size changed from [%s, %s] to [%s, %s]",
+                        smallestSize, largestSize, info.smallestSize, info.largestSize));
+                return true;
+            }
+
+            return false;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 357eeb8..2be827b 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -20,7 +20,7 @@
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_UP;
 
-import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
+import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 
 import android.annotation.TargetApi;
 import android.app.WallpaperInfo;
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index 040619e..9582232 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -40,7 +40,7 @@
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Executors;
 
 /**
@@ -97,7 +97,7 @@
 
         // Remove after some time, to avoid flickering
         Executors.MAIN_EXECUTOR.getHandler().postDelayed(mRemoveViewRunnable,
-                DefaultDisplay.INSTANCE.get(mLauncher).getInfo().singleFrameMs);
+                DisplayController.getDefaultDisplay(mLauncher).getInfo().singleFrameMs);
     }
 
     private void removeViewFromParent() {
diff --git a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
index c57f07d..be20e2d 100644
--- a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
@@ -16,35 +16,28 @@
 
 package com.android.systemui.plugins;
 
-import android.app.Activity;
-import android.view.ViewGroup;
-import android.widget.EditText;
+import android.os.Bundle;
 
 import com.android.systemui.plugins.annotations.ProvidesInterface;
 
+import java.util.List;
+import java.util.function.Consumer;
+
 /**
- * Implement this plugin interface to replace the all apps recycler view of the all apps drawer.
+ * Implement this plugin interface to fetch search result data from the plugin side.
  */
 @ProvidesInterface(action = AllAppsSearchPlugin.ACTION, version = AllAppsSearchPlugin.VERSION)
 public interface AllAppsSearchPlugin extends Plugin {
     String ACTION = "com.android.systemui.action.PLUGIN_ALL_APPS_SEARCH_ACTIONS";
-    int VERSION = 3;
-
-    /** Following are the order that these methods should be called. */
-    void setup(ViewGroup parent, Activity activity, float allAppsContainerHeight);
+    int VERSION = 4;
 
     /**
-     * When drag starts, pass window inset related fields and the progress to indicate
-     * whether user is swiping down or swiping up
+     * Send signal when user starts typing.
      */
-    void onDragStart(float progress);
+    void startedTyping();
 
-    /** progress is between [0, 1] 1: down, 0: up */
-    void setProgress(float progress);
-
-    /** Called when container animation stops, so that plugin can perform cleanups */
-    void onAnimationEnd(float progress);
-
-    /** pass over the search box object */
-    void setEditText(EditText editText);
+    /**
+     * Send over the query and get the search results.
+     */
+    void performSearch(String query, Consumer<List<Bundle>> results);
 }
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/LoaderResults.java b/src_shortcuts_overrides/com/android/launcher3/model/LoaderResults.java
index dcb4636..269af7b 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/LoaderResults.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/LoaderResults.java
@@ -21,7 +21,6 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.widget.WidgetListRowEntry;
 
 import java.util.ArrayList;
@@ -34,12 +33,7 @@
 
     public LoaderResults(LauncherAppState app, BgDataModel dataModel,
             AllAppsList allAppsList, Callbacks[] callbacks) {
-        this(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
-    }
-
-    public LoaderResults(LauncherAppState app, BgDataModel dataModel,
-            AllAppsList allAppsList, Callbacks[] callbacks, LooperExecutor executor) {
-        super(app, dataModel, allAppsList, callbacks, executor);
+        super(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
     }
 
     @Override
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
index 7a6332c..d102bcc 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -38,10 +38,6 @@
         return new OverviewState(id);
     }
 
-    public static OverviewState newPeekState(int id) {
-        return new OverviewState(id);
-    }
-
     public static OverviewState newSwitchState(int id) {
         return new OverviewState(id);
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 92ab9b8..80adf05 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1304,17 +1304,8 @@
         if (getNavigationModel() == NavigationModel.TWO_BUTTON) {
             return true;
         }
-        // Overview actions hide all apps
-        if (overviewActionsEnabled()) {
-            return false;
-        }
-        // ...otherwise there should be all apps
-        return true;
-    }
-
-    private boolean overviewActionsEnabled() {
-        return getTestInfo(TestProtocol.REQUEST_OVERVIEW_ACTIONS_ENABLED).getBoolean(
-                TestProtocol.TEST_INFO_RESPONSE_FIELD);
+        // ...otherwise there are overview actions, which hide all apps
+        return false;
     }
 
     boolean overviewShareEnabled() {