Merge "Simplifying widget search pipeline" into sc-dev
diff --git a/Android.bp b/Android.bp
index 2c9d664..e30d22f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -179,7 +179,6 @@
     srcs: [ ],
     resource_dirs: [
         "quickstep/res",
-        "quickstep/overview_ui_overrides/res",
     ],
     static_libs: [
         "Launcher3ResLib",
diff --git a/Android.mk b/Android.mk
index 89870a6..54a80b7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -78,9 +78,7 @@
     $(call all-java-files-under, quickstep/src) \
     $(call all-java-files-under, src_shortcuts_overrides)
 
-LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/quickstep/res \
-    $(LOCAL_PATH)/quickstep/overview_ui_overrides/res
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
 LOCAL_PROGUARD_ENABLED := disabled
 
 
@@ -109,9 +107,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/overview_ui_overrides/res
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
 
 LOCAL_FULL_LIBS_MANIFEST_FILES := \
     $(LOCAL_PATH)/quickstep/AndroidManifest-launcher.xml \
@@ -148,10 +144,9 @@
     $(call all-java-files-under, go/quickstep/src)
 
 LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/quickstep/res \
-    $(LOCAL_PATH)/go/res \
     $(LOCAL_PATH)/go/quickstep/res \
-    $(LOCAL_PATH)/go/quickstep/overview_ui_overrides/res
+    $(LOCAL_PATH)/go/res \
+    $(LOCAL_PATH)/quickstep/res
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 LOCAL_PROGUARD_ENABLED := full
diff --git a/go/quickstep/overview_ui_overrides/res/values/config.xml b/go/quickstep/overview_ui_overrides/res/values/config.xml
deleted file mode 100644
index ec21a01..0000000
--- a/go/quickstep/overview_ui_overrides/res/values/config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2021 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-<resources>
-    <string name="task_overlay_factory_class" translatable="false">
-        com.android.quickstep.TaskOverlayFactoryGo</string>
-</resources>
\ No newline at end of file
diff --git a/go/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
similarity index 95%
rename from go/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml
rename to go/quickstep/res/layout/overview_actions_container.xml
index e6af848..866eac6 100644
--- a/go/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -14,11 +14,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<!-- NOTE! don't add dimensions for margins / gravity to root view in this file, they need to be
+     loaded at runtime. -->
 <com.android.quickstep.views.GoOverviewActionsView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center_horizontal|bottom">
+    android:layout_height="wrap_content">
 
     <LinearLayout
         android:id="@+id/action_buttons"
diff --git a/go/quickstep/res/values/config.xml b/go/quickstep/res/values/config.xml
index a21381c..402bf9a 100644
--- a/go/quickstep/res/values/config.xml
+++ b/go/quickstep/res/values/config.xml
@@ -21,4 +21,6 @@
 
     <!-- Feature Flags -->
     <bool name="enable_niu_actions">true</bool>
+
+    <string name="task_overlay_factory_class" translatable="false">com.android.quickstep.TaskOverlayFactoryGo</string>
 </resources>
\ No newline at end of file
diff --git a/quickstep/overview_ui_overrides/res/values/config.xml b/quickstep/overview_ui_overrides/res/values/config.xml
deleted file mode 100644
index 0f09439..0000000
--- a/quickstep/overview_ui_overrides/res/values/config.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <string name="task_overlay_factory_class" translatable="false"/>
-</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
deleted file mode 100644
index c3a3eaf..0000000
--- a/quickstep/recents_ui_overrides/src/REMOVED.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Temp file to prevent build breakage.
-Will be removed in followup cl.
\ No newline at end of file
diff --git a/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
similarity index 93%
rename from quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml
rename to quickstep/res/layout/overview_actions_container.xml
index 1da25e7..b652252 100644
--- a/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -14,10 +14,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<!-- NOTE! don't add dimensions for margins / gravity to root view in this file, they need to be
+     loaded at runtime. -->
 <com.android.quickstep.views.OverviewActionsView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center_horizontal|bottom">
+    android:layout_height="wrap_content">
 
     <LinearLayout
         android:id="@+id/action_buttons"
diff --git a/quickstep/res/layout/overview_clear_all_button.xml b/quickstep/res/layout/overview_clear_all_button.xml
index c61610a..1ee726e 100644
--- a/quickstep/res/layout/overview_clear_all_button.xml
+++ b/quickstep/res/layout/overview_clear_all_button.xml
@@ -21,5 +21,5 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:text="@string/recents_clear_all"
-    android:textColor="?attr/workspaceTextColor"
+    android:textColor="?android:attr/textColorPrimary"
     android:textSize="14sp" />
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index 394e880..d7bcd9e 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -19,8 +19,7 @@
         android:id="@+id/split_placeholder"
         android:layout_width="match_parent"
         android:layout_height="@dimen/split_placeholder_size"
-        android:background="@android:color/white"
-        android:alpha=".8"
+        android:background="@android:color/darker_gray"
         android:visibility="gone" />
 
     <com.android.quickstep.views.LauncherRecentsView
@@ -30,7 +29,6 @@
         android:accessibilityPaneTitle="@string/accessibility_recent_apps"
         android:clipChildren="false"
         android:clipToPadding="false"
-        android:theme="@style/HomeScreenElementTheme"
         android:visibility="invisible" />
 
     <include
diff --git a/quickstep/res/layout/scrim_view.xml b/quickstep/res/layout/scrim_view.xml
index 2cc37f9..3f2daf1 100644
--- a/quickstep/res/layout/scrim_view.xml
+++ b/quickstep/res/layout/scrim_view.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.quickstep.views.ShelfScrimView
+<com.android.quickstep.views.AllAppsScrimView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index be66104..b2ff770 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -15,6 +15,7 @@
 -->
 <resources>
     <string name="overscroll_plugin_factory_class" translatable="false" />
+    <string name="task_overlay_factory_class" translatable="false"/>
 
     <!-- Activities which block home gesture -->
     <string-array name="gesture_blocking_activities" translatable="false">
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 3036341..3e6c78f 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -36,6 +36,7 @@
     <dimen name="overview_grid_bottom_margin">90dp</dimen>
     <dimen name="overview_grid_side_margin">54dp</dimen>
     <dimen name="overview_grid_row_spacing">42dp</dimen>
+    <dimen name="overview_grid_focus_vertical_margin">130dp</dimen>
     <dimen name="split_placeholder_size">110dp</dimen>
 
     <dimen name="recents_page_spacing">16dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 1603321..2a06830 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -59,7 +59,7 @@
     <string name="all_apps_prediction_tip">Your predicted apps</string>
 
     <!-- Content description for a close button. [CHAR LIMIT=NONE] -->
-    <string  name="gesture_tutorial_close_button_content_description" translatable="false">Close</string>
+    <string name="gesture_tutorial_close_button_content_description" translatable="false">Close</string>
 
     <!-- Hotseat educational strings for users who don't qualify for migration -->
     <string name="hotseat_edu_title_migrate">Get app suggestions on the bottom row of your Home screen</string>
@@ -91,14 +91,6 @@
     <!-- content description for hotseat items -->
     <string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
 
-    <!-- primary educational text shown for first time search users -->
-    <string name="search_edu_primary">Search your phone for apps, people, settings and more!</string>
-    <!-- secondary educational text shown for first time search users -->
-    <string name="search_edu_secondary">Tap keyboard search button to launch the first search
-        result.</string>
-
-    <!-- Dismiss button string for search education view -->
-    <string name="search_edu_dismiss">Got it.</string>
     <!-- Feedback shown during interactive parts of Back gesture tutorial for left edge when the gesture is too far from the edge. [CHAR LIMIT=100] -->
     <string name="back_gesture_feedback_swipe_too_far_from_left_edge">Make sure you swipe from the far-left edge.</string>
     <!-- Feedback shown during interactive parts of Back gesture tutorial for left edge when the gesture is cancelled. [CHAR LIMIT=100] -->
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index df089f6..e56397a 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -81,7 +81,7 @@
         parent="@android:style/Widget.DeviceDefault.Button.Borderless">
         <item name="android:textColor">@color/overview_button</item>
         <item name="android:drawableTint">@color/overview_button</item>
-        <item name="android:tint">?attr/workspaceTextColor</item>
+        <item name="android:tint">?android:attr/textColorPrimary</item>
         <item name="android:drawablePadding">8dp</item>
         <item name="android:textAllCaps">false</item>
     </style>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 085db6d..e9ded8a 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -92,6 +92,7 @@
     private final TaskbarStateHandler mTaskbarStateHandler = new TaskbarStateHandler(this);
     // Will be updated when dragging from taskbar.
     private @Nullable DragOptions mNextWorkspaceDragOptions = null;
+    private SplitPlaceholderView mSplitPlaceholderView;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -215,12 +216,12 @@
 
         SysUINavigationMode.INSTANCE.get(this).updateMode();
         mActionsView = findViewById(R.id.overview_actions_view);
-        SplitPlaceholderView splitPlaceholderView = findViewById(R.id.split_placeholder);
+        mSplitPlaceholderView = findViewById(R.id.split_placeholder);
         RecentsView overviewPanel = (RecentsView) getOverviewPanel();
-        splitPlaceholderView.init(
+        mSplitPlaceholderView.init(
                 new SplitSelectStateController(SystemUiProxy.INSTANCE.get(this))
         );
-        overviewPanel.init(mActionsView, splitPlaceholderView);
+        overviewPanel.init(mActionsView, mSplitPlaceholderView);
         mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
 
         mAppTransitionManager = new QuickstepTransitionManager(this);
@@ -256,6 +257,10 @@
         return (T) mActionsView;
     }
 
+    public SplitPlaceholderView getSplitPlaceholderView() {
+        return mSplitPlaceholderView;
+    }
+
     @Override
     protected void closeOpenViews(boolean animate) {
         super.closeOpenViews(animate);
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 8e92b59..cc3ccea 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -237,7 +237,9 @@
             setTranslationY(scroll);
         }
         setAlpha(mScrolledOut ? 0 : 1);
-        AlphaUpdateListener.updateVisibility(this);
+        if (getVisibility() != GONE) {
+            AlphaUpdateListener.updateVisibility(this);
+        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
index ce94305..1f268cc 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
@@ -48,10 +48,6 @@
     @Override
     public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
             PendingAnimation animation) {
-        if (config.onlyPlayAtomicComponent()) {
-            return;
-        }
-
         if (SysUINavigationMode.getMode(mLauncher) != TWO_BUTTONS) {
             return;
         }
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index fe8f0c6..249ef3a 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -193,7 +193,6 @@
     public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
             PendingAnimation animation) {
         if (mSurface == null
-                || config.onlyPlayAtomicComponent()
                 || config.hasAnimationFlag(SKIP_DEPTH_CONTROLLER)
                 || mIgnoreStateChangesDuringMultiWindowAnimation) {
             return;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
index 5202d91..ccf6b41 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
@@ -27,7 +27,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.R;
-import com.android.launcher3.anim.AlphaUpdateListener;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.systemui.shared.system.ViewTreeObserverWrapper;
@@ -83,18 +82,13 @@
 
     private ViewTreeObserverWrapper.OnComputeInsetsListener createTaskbarInsetsComputer() {
         return insetsInfo -> {
-            if (getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD
-                    || mTaskbarView.getVisibility() != VISIBLE || mTaskbarView.isDraggingItem()) {
-                // We're invisible or dragging out of taskbar, let touches pass through us.
+            if (mControllerCallbacks.isTaskbarTouchable()) {
+                 // Accept touches anywhere in our bounds.
+                insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
+            } else {
+                // Let touches pass through us.
                 insetsInfo.touchableRegion.setEmpty();
                 insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
-                // TODO(b/182234653): Shouldn't need to do this, but for the meantime, reporting
-                // that visibleInsets is empty allows DragEvents through. Setting them as completely
-                // empty reverts to default behavior, so set 1 px instead.
-                insetsInfo.visibleInsets.set(0, 0, 0, 1);
-            } else {
-                 // We're visible again, accept touches anywhere in our bounds.
-                insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
             }
 
             // TaskbarContainerView provides insets to other apps based on contentInsets. These
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
index de23ad2..559ede1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
@@ -42,6 +42,7 @@
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.R;
+import com.android.launcher3.anim.AlphaUpdateListener;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
@@ -88,7 +89,6 @@
 
     private @Nullable Animator mAnimator;
     private boolean mIsAnimatingToLauncher;
-    private boolean mIsAnimatingToApp;
 
     public TaskbarController(BaseQuickstepLauncher launcher,
             TaskbarContainerView taskbarContainerView, TaskbarView taskbarViewOnHome) {
@@ -141,6 +141,13 @@
                     setTaskbarWindowFullscreen(false);
                 }
             }
+
+            @Override
+            public boolean isTaskbarTouchable() {
+                return mTaskbarContainerView.getAlpha() > AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD
+                        && mTaskbarViewInApp.getVisibility() == View.VISIBLE
+                        && !mIsAnimatingToLauncher;
+            }
         };
     }
 
@@ -250,7 +257,9 @@
         mHotseatController.init();
         mRecentsController.init();
 
-        updateWhichTaskbarViewIsVisible();
+        setWhichTaskbarViewIsVisible(mLauncher.hasBeenResumed()
+                ? mTaskbarViewOnHome
+                : mTaskbarViewInApp);
     }
 
     private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() {
@@ -284,6 +293,8 @@
         mTaskbarAnimationController.cleanup();
         mHotseatController.cleanup();
         mRecentsController.cleanup();
+
+        setWhichTaskbarViewIsVisible(null);
     }
 
     private void removeFromWindowManager() {
@@ -364,7 +375,7 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 mIsAnimatingToLauncher = false;
-                updateWhichTaskbarViewIsVisible();
+                setWhichTaskbarViewIsVisible(mTaskbarViewOnHome);
             }
         });
 
@@ -377,14 +388,12 @@
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
-                mIsAnimatingToApp = true;
                 mTaskbarViewInApp.updateHotseatItemsVisibility();
-                updateWhichTaskbarViewIsVisible();
+                setWhichTaskbarViewIsVisible(mTaskbarViewInApp);
             }
 
             @Override
             public void onAnimationEnd(Animator animation) {
-                mIsAnimatingToApp = false;
             }
         });
         return anim.buildAnim();
@@ -487,18 +496,12 @@
                 mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom);
     }
 
-    private void updateWhichTaskbarViewIsVisible() {
-        boolean isInApp = !mLauncher.hasBeenResumed() || mIsAnimatingToLauncher
-                || mIsAnimatingToApp;
-        if (isInApp) {
-            mTaskbarViewInApp.setVisibility(View.VISIBLE);
-            mTaskbarViewOnHome.setVisibility(View.INVISIBLE);
-            mLauncher.getHotseat().setIconsAlpha(0);
-        } else {
-            mTaskbarViewInApp.setVisibility(View.INVISIBLE);
-            mTaskbarViewOnHome.setVisibility(View.VISIBLE);
-            mLauncher.getHotseat().setIconsAlpha(1);
-        }
+    private void setWhichTaskbarViewIsVisible(@Nullable TaskbarView visibleTaskbar) {
+        mTaskbarViewInApp.setVisibility(visibleTaskbar == mTaskbarViewInApp
+                ? View.VISIBLE : View.INVISIBLE);
+        mTaskbarViewOnHome.setVisibility(visibleTaskbar == mTaskbarViewOnHome
+                ? View.VISIBLE : View.INVISIBLE);
+        mLauncher.getHotseat().setIconsAlpha(visibleTaskbar != mTaskbarViewInApp ? 1f : 0f);
     }
 
     /**
@@ -549,6 +552,7 @@
      */
     protected interface TaskbarContainerViewCallbacks {
         void onViewRemoved();
+        boolean isTaskbarTouchable();
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index d65c59e..a3a1fef 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -26,8 +26,6 @@
 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.PLAY_ATOMIC_OVERVIEW_PEEK;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
 import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
@@ -83,10 +81,6 @@
     @Override
     public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
             PendingAnimation builder) {
-        if (!config.hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) {
-            // The entire recents animation is played atomically.
-            return;
-        }
         if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
             return;
         }
@@ -122,6 +116,11 @@
                 config.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
         setter.setFloat(scrim, SCRIM_MULTIPLIER, 1f,
                 config.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
+        if (toState.areElementsVisible(mLauncher, LauncherState.SPLIT_PLACHOLDER_VIEW)) {
+            scrim.updateStableScrimmedView(mLauncher.getSplitPlaceholderView());
+        } else {
+            scrim.updateStableScrimmedView(mLauncher.getOverviewPanel());
+        }
 
         setter.setFloat(
                 mRecentsView, getTaskModalnessProperty(),
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index b1c04b1..0ceb8c7 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -28,6 +28,7 @@
 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
 import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
+import static com.android.launcher3.testing.TestProtocol.HINT_STATE_TWO_BUTTON_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.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
@@ -35,6 +36,7 @@
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
+import android.view.HapticFeedbackConstants;
 import android.view.View;
 
 import com.android.launcher3.BaseQuickstepLauncher;
@@ -250,6 +252,11 @@
                 }
                 break;
             }
+            case HINT_STATE_TWO_BUTTON_ORDINAL: {
+                getStateManager().goToState(OVERVIEW);
+                getDragLayer().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+                break;
+            }
             case OVERVIEW_STATE_ORDINAL: {
                 RecentsView rv = getOverviewPanel();
                 sendCustomAccessibilityEvent(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index e1456b1..9097c8b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -103,18 +103,17 @@
 
     private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
             LauncherState state) {
-        float clearAllButtonAlpha = (state.getVisibleElements(mLauncher) & CLEAR_ALL_BUTTON) != 0
-                ? 1 : 0;
+        float clearAllButtonAlpha = state.areElementsVisible(mLauncher, CLEAR_ALL_BUTTON) ? 1 : 0;
         propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
                 clearAllButtonAlpha, LINEAR);
-        float overviewButtonAlpha = (state.getVisibleElements(mLauncher) & OVERVIEW_ACTIONS) != 0
-                ? 1 : 0;
+        float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS)
+                && mRecentsView.shouldShowOverviewActionsForState(state) ? 1 : 0;
         propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
                 MultiValueAlpha.VALUE, overviewButtonAlpha, config.getInterpolator(
                         ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
 
         float splitPlaceholderAlpha = state.areElementsVisible(mLauncher, SPLIT_PLACHOLDER_VIEW) ?
-                1 : 0;
+                0.7f : 0;
         propertySetter.setFloat(mRecentsView.getSplitPlaceholder(), ALPHA_FLOAT,
                 splitPlaceholderAlpha, LINEAR);
     }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index bdba482..6f084a1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -18,6 +18,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
 
 import android.content.Context;
+import android.graphics.Point;
 import android.graphics.Rect;
 
 import com.android.launcher3.BaseDraggingActivity;
@@ -70,13 +71,12 @@
     }
 
     public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
-        Rect out = new Rect();
-        activity.<RecentsView>getOverviewPanel().getTaskSize(out);
-        int taskHeight = out.height();
-        activity.<RecentsView>getOverviewPanel().getModalTaskSize(out);
-        int newHeight = out.height();
+        Point taskSize = activity.<RecentsView>getOverviewPanel().getSelectedTaskSize();
+        Rect modalTaskSize = new Rect();
+        activity.<RecentsView>getOverviewPanel().getModalTaskSize(modalTaskSize);
 
-        float scale = (float) newHeight / taskHeight;
+        float scale = Math.min((float) modalTaskSize.height() / taskSize.y,
+                (float) modalTaskSize.width() / taskSize.x);
 
         return new float[] {scale, NO_OFFSET};
     }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 43e70a3..95a855a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -99,13 +99,12 @@
 
     @Override
     public int getVisibleElements(Launcher launcher) {
-        return displayOverviewTasksAsGrid(launcher.getDeviceProfile()) ? CLEAR_ALL_BUTTON
-                : CLEAR_ALL_BUTTON | OVERVIEW_ACTIONS;
+        return CLEAR_ALL_BUTTON | OVERVIEW_ACTIONS;
     }
 
     @Override
     public float getOverviewScrimAlpha(Launcher launcher) {
-        return 0.5f;
+        return 1f;
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index de7be5d..ba61923 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -18,6 +18,7 @@
 import static android.view.View.VISIBLE;
 
 import static com.android.launcher3.LauncherState.HINT_STATE;
+import static com.android.launcher3.LauncherState.HINT_STATE_TWO_BUTTON;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.WorkspaceStateTransitionAnimation.getSpringScaleAnimator;
@@ -115,7 +116,8 @@
                     qsbContainer.setScaleY(0.92f);
                 }
             }
-        } else if ((fromState == NORMAL || fromState == HINT_STATE) && toState == OVERVIEW) {
+        } else if ((fromState == NORMAL || fromState == HINT_STATE
+                || fromState == HINT_STATE_TWO_BUTTON) && toState == OVERVIEW) {
             if (SysUINavigationMode.getMode(mActivity) == NO_BUTTON) {
                 config.setInterpolator(ANIM_WORKSPACE_SCALE,
                         fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index fc06d29..464b90a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -38,7 +38,6 @@
 import android.animation.ValueAnimator;
 import android.graphics.PointF;
 import android.view.MotionEvent;
-import android.view.View;
 import android.view.ViewConfiguration;
 
 import com.android.launcher3.Launcher;
@@ -108,11 +107,11 @@
     }
 
     @Override
-    protected float initCurrentAnimation(int animComponents) {
-        float progressMultiplier = super.initCurrentAnimation(animComponents);
+    protected float initCurrentAnimation() {
+        float progressMultiplier = super.initCurrentAnimation();
         if (mToState == HINT_STATE) {
             // Track the drag across the entire height of the screen.
-            progressMultiplier = -1 / getShiftRange();
+            progressMultiplier = -1f / mLauncher.getDeviceProfile().heightPx;
         }
         return progressMultiplier;
     }
@@ -155,11 +154,6 @@
             super.onDragEnd(velocity);
         }
 
-        View searchView = mLauncher.getHotseat().getQsb();
-        if (searchView instanceof FeedbackHandler) {
-            ((FeedbackHandler) searchView).resetFeedback();
-        }
-
         mMotionPauseDetector.clear();
         mNormalToHintOverviewScrimAnimator = null;
         if (mLauncher.isInState(OVERVIEW)) {
@@ -188,13 +182,13 @@
         }
         mNormalToHintOverviewScrimAnimator = null;
         mCurrentAnimation.getTarget().addListener(newCancelListener(() ->
-            mLauncher.getStateManager().goToState(OVERVIEW, true, () -> {
-                mOverviewResistYAnim = AnimatorControllerWithResistance
-                        .createRecentsResistanceFromOverviewAnim(mLauncher, null)
-                        .createPlaybackController();
-                mReachedOverview = true;
-                maybeSwipeInteractionToOverviewComplete();
-            })));
+                mLauncher.getStateManager().goToState(OVERVIEW, true, () -> {
+                    mOverviewResistYAnim = AnimatorControllerWithResistance
+                            .createRecentsResistanceFromOverviewAnim(mLauncher, null)
+                            .createPlaybackController();
+                    mReachedOverview = true;
+                    maybeSwipeInteractionToOverviewComplete();
+                })));
 
         mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
         mCurrentAnimation.dispatchOnCancel();
@@ -245,7 +239,7 @@
     private void goToOverviewOrHomeOnDragEnd(float velocity) {
         boolean goToHomeInsteadOfOverview = !mMotionPauseDetector.isPaused();
         if (goToHomeInsteadOfOverview) {
-            new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL))
+            new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(NORMAL))
                     .animateWithVelocity(velocity);
         }
         if (mReachedOverview) {
@@ -281,17 +275,14 @@
             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));
+                    ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD));
             builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
                     ACCEL,
-                    progressToReachOverview,
-                    progressToReachOverview + ALL_APPS_CONTENT_FADE_THRESHOLD));
+                    ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD,
+                    ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD));
 
             // Get workspace out of the way quickly, to prepare for potential pause.
             builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3);
@@ -300,29 +291,17 @@
             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));
+                    1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
+                    1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD));
             builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
                     DEACCEL,
-                    1 - ALL_APPS_CONTENT_FADE_THRESHOLD,
+                    1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_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/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 4766870..61cd13b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -33,6 +33,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
 import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
 import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
@@ -372,7 +373,7 @@
             // animation as from an app.
             StateAnimationConfig config = new StateAnimationConfig();
             // Update mNonOverviewAnim to do nothing so it doesn't interfere.
-            config.animFlags = 0;
+            config.animFlags = SKIP_ALL_ANIMATIONS;
             updateNonOverviewAnim(targetState, config);
             nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer();
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index facfb9d..b8f9452 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -23,17 +23,9 @@
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.anim.Interpolators.ACCEL;
 import static com.android.launcher3.anim.Interpolators.DEACCEL;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-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;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
 
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.util.Log;
 import android.view.MotionEvent;
-import android.view.animation.Interpolator;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
@@ -41,8 +33,6 @@
 import com.android.launcher3.allapps.AllAppsTransitionController;
 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.touch.AbstractStateChangeTouchController;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.launcher3.uioverrides.states.OverviewState;
@@ -59,9 +49,15 @@
     private static final String TAG = "PortraitStatesTouchCtrl";
 
     /**
-     * The progress at which all apps content will be fully visible when swiping up from overview.
+     * The progress at which all apps content will be fully visible.
      */
-    protected static final float ALL_APPS_CONTENT_FADE_THRESHOLD = 0.08f;
+    protected static final float ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD = 0.8f;
+
+    /**
+     * Minimum clamping progress for fading in all apps content
+     */
+    protected static final float ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD = 0.4f;
+
 
     /**
      * The progress at which recents will begin fading out when swiping up from overview.
@@ -70,11 +66,6 @@
 
     private final PortraitOverviewStateTouchHelper mOverviewPortraitStateTouchHelper;
 
-    private final InterpolatorWrapper mAllAppsInterpolatorWrapper = new InterpolatorWrapper();
-
-    // If true, we will finish the current animation instantly on second touch.
-    private boolean mFinishFastOnSecondTouch;
-
     public PortraitStatesTouchController(Launcher l) {
         super(l, SingleAxisSwipeDetector.VERTICAL);
         mOverviewPortraitStateTouchHelper = new PortraitOverviewStateTouchHelper(l);
@@ -85,10 +76,6 @@
         // If we are swiping to all apps instead of overview, allow it from anywhere.
         boolean interceptAnywhere = mLauncher.isInState(NORMAL);
         if (mCurrentAnimation != null) {
-            if (mFinishFastOnSecondTouch) {
-                mCurrentAnimation.getAnimationPlayer().end();
-            }
-
             AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
             if (ev.getY() >= allAppsController.getShiftRange() * allAppsController.getProgress()
                     || interceptAnywhere) {
@@ -96,11 +83,7 @@
                 // the touch is below the current all apps progress (to allow for double swipe).
                 return true;
             }
-            // Otherwise, make sure everything is settled and don't intercept so they can scroll
-            // recents, dismiss a task, etc.
-            if (mAtomicAnim != null) {
-                mAtomicAnim.end();
-            }
+            // Otherwise, don't intercept so they can scroll recents, dismiss a task, etc.
             return false;
         }
         if (mLauncher.isInState(ALL_APPS)) {
@@ -136,43 +119,17 @@
         return fromState;
     }
 
-    private StateAnimationConfig getNormalToOverviewAnimation() {
-        mAllAppsInterpolatorWrapper.baseInterpolator = LINEAR;
-
-        StateAnimationConfig builder = new StateAnimationConfig();
-        builder.setInterpolator(ANIM_VERTICAL_PROGRESS, mAllAppsInterpolatorWrapper);
-        return builder;
-    }
-
-    private static StateAnimationConfig getOverviewToAllAppsAnimation() {
-        StateAnimationConfig builder = new StateAnimationConfig();
-        builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
-                0, ALL_APPS_CONTENT_FADE_THRESHOLD));
-        builder.setInterpolator(ANIM_OVERVIEW_FADE, Interpolators.clampToProgress(DEACCEL,
-                RECENTS_FADE_THRESHOLD, 1));
-        return builder;
-    }
-
-    private StateAnimationConfig getAllAppsToOverviewAnimation() {
-        StateAnimationConfig builder = new StateAnimationConfig();
-        builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
-                1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1));
-        builder.setInterpolator(ANIM_OVERVIEW_FADE, Interpolators.clampToProgress(ACCEL,
-                0f, 1 - RECENTS_FADE_THRESHOLD));
-        return builder;
-    }
-
     private StateAnimationConfig getNormalToAllAppsAnimation() {
         StateAnimationConfig builder = new StateAnimationConfig();
         builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
-                0, ALL_APPS_CONTENT_FADE_THRESHOLD));
+                0, ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD));
         return builder;
     }
 
     private StateAnimationConfig getAllAppsToNormalAnimation() {
         StateAnimationConfig builder = new StateAnimationConfig();
         builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
-                1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1));
+                1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD, 1));
         return builder;
     }
 
@@ -180,24 +137,18 @@
     protected StateAnimationConfig getConfigForStates(
             LauncherState fromState, LauncherState toState) {
         final StateAnimationConfig config;
-        if (fromState == NORMAL && toState == OVERVIEW) {
-            config = getNormalToOverviewAnimation();
-        } else if (fromState == OVERVIEW && toState == ALL_APPS) {
-            config = getOverviewToAllAppsAnimation();
-        } else if (fromState == ALL_APPS && toState == OVERVIEW) {
-            config = getAllAppsToOverviewAnimation();
-        } else if (fromState == NORMAL && toState == ALL_APPS) {
+        if (fromState == NORMAL && toState == ALL_APPS) {
             config = getNormalToAllAppsAnimation();
         } else if (fromState == ALL_APPS && toState == NORMAL) {
             config = getAllAppsToNormalAnimation();
-        }  else {
+        } else {
             config = new StateAnimationConfig();
         }
         return config;
     }
 
     @Override
-    protected float initCurrentAnimation(@AnimationFlags int animFlags) {
+    protected float initCurrentAnimation() {
         float range = getShiftRange();
         long maxAccuracy = (long) (2 * range);
 
@@ -208,7 +159,6 @@
 
         final StateAnimationConfig config = totalShift == 0 ? new StateAnimationConfig()
                 : getConfigForStates(mFromState, mToState);
-        config.animFlags = animFlags;
         config.duration = maxAccuracy;
 
         if (mCurrentAnimation != null) {
@@ -243,35 +193,6 @@
     }
 
     @Override
-    protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
-            LauncherState targetState, float velocity, boolean isFling) {
-        super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
-                velocity, isFling);
-        handleFirstSwipeToOverview(animator, expectedDuration, targetState, velocity, isFling);
-    }
-
-    private void handleFirstSwipeToOverview(final ValueAnimator animator,
-            final long expectedDuration, final LauncherState targetState, final float velocity,
-            final boolean isFling) {
-        if (UNSTABLE_SPRINGS.get() && mFromState == OVERVIEW && mToState == ALL_APPS
-                && targetState == OVERVIEW) {
-            mFinishFastOnSecondTouch = true;
-        } else  if (mFromState == NORMAL && mToState == OVERVIEW && targetState == OVERVIEW) {
-            mFinishFastOnSecondTouch = true;
-            if (isFling && expectedDuration != 0) {
-                // Update all apps interpolator to add a bit of overshoot starting from currFraction
-                final float currFraction = mCurrentAnimation.getProgressFraction();
-                mAllAppsInterpolatorWrapper.baseInterpolator = Interpolators.clampToProgress(
-                        Interpolators.overshootInterpolatorForVelocity(velocity), currFraction, 1);
-                animator.setDuration(Math.min(expectedDuration, ATOMIC_DURATION))
-                        .setInterpolator(LINEAR);
-            }
-        } else {
-            mFinishFastOnSecondTouch = false;
-        }
-    }
-
-    @Override
     protected void onSwipeInteractionCompleted(LauncherState targetState) {
         super.onSwipeInteractionCompleted(targetState);
         if (mStartState == NORMAL && targetState == OVERVIEW) {
@@ -283,7 +204,7 @@
      * Whether the motion event is over the hotseat.
      *
      * @param launcher the launcher activity
-     * @param ev the event to check
+     * @param ev       the event to check
      * @return true if the event is over the hotseat
      */
     static boolean isTouchOverHotseat(Launcher launcher, MotionEvent ev) {
@@ -296,16 +217,6 @@
         return launcher.getDragLayer().getHeight() - hotseatHeight;
     }
 
-    private static class InterpolatorWrapper implements Interpolator {
-
-        public TimeInterpolator baseInterpolator = LINEAR;
-
-        @Override
-        public float getInterpolation(float v) {
-            return baseInterpolator.getInterpolation(v);
-        }
-    }
-
     @Override
     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
         switch (ev.getAction()) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index fc9e1bb..94a7442 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -101,7 +101,7 @@
     }
 
     @Override
-    protected float initCurrentAnimation(int animComponents) {
+    protected float initCurrentAnimation() {
         StateAnimationConfig config = new StateAnimationConfig();
         setupInterpolators(config);
         config.duration = (long) (getShiftRange() * 2);
@@ -137,14 +137,17 @@
 
     private void updateFullscreenProgress(float progress) {
         mOverviewPanel.setFullscreenProgress(progress);
-        int sysuiFlags = 0;
         if (progress > UPDATE_SYSUI_FLAGS_THRESHOLD) {
+            int sysuiFlags = 0;
             TaskView tv = mOverviewPanel.getTaskViewAt(0);
             if (tv != null) {
                 sysuiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
             }
+            mLauncher.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
+        } else {
+            mLauncher.getSystemUiController().updateUiState(
+                    UI_STATE_OVERVIEW, mOverviewPanel.hasLightBackground());
         }
-        mLauncher.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
index 0ed5291..8f9c014 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
@@ -32,8 +32,8 @@
     }
 
     @Override
-    protected float initCurrentAnimation(int animComponents) {
-        float multiplier = super.initCurrentAnimation(animComponents);
+    protected float initCurrentAnimation() {
+        float multiplier = super.initCurrentAnimation();
         return mLauncher.getDeviceProfile().isSeascape() ? multiplier : -multiplier;
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
index faf5054..3f7190f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
@@ -17,17 +17,18 @@
 
 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
 import static com.android.launcher3.AbstractFloatingView.getOpenView;
+import static com.android.launcher3.LauncherState.HINT_STATE_TWO_BUTTON;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
 
 import android.animation.ValueAnimator;
+import android.os.SystemClock;
 import android.view.MotionEvent;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
 import com.android.launcher3.touch.AbstractStateChangeTouchController;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.quickstep.SystemUiProxy;
@@ -91,10 +92,10 @@
         if (mIsTransposed) {
             boolean draggingFromNav =
                     mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive;
-            return draggingFromNav ? OVERVIEW : NORMAL;
+            return draggingFromNav ? HINT_STATE_TWO_BUTTON : NORMAL;
         } else {
             LauncherState startState = mStartState != null ? mStartState : fromState;
-            return isDragTowardPositive ^ (startState == OVERVIEW) ? OVERVIEW : NORMAL;
+            return isDragTowardPositive ^ (startState == OVERVIEW) ? HINT_STATE_TWO_BUTTON : NORMAL;
         }
     }
 
@@ -104,6 +105,12 @@
         super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
                 velocity, isFling);
         mFinishFastOnSecondTouch = !mIsTransposed && mFromState == NORMAL;
+
+        if (targetState == HINT_STATE_TWO_BUTTON) {
+            // We were going to HINT_STATE_TWO_BUTTON, but end that animation immediately so we go
+            // to OVERVIEW instead.
+            animator.setDuration(0);
+        }
     }
 
     @Override
@@ -113,21 +120,35 @@
     }
 
     @Override
-    protected float initCurrentAnimation(@AnimationFlags int animComponent) {
+    protected float initCurrentAnimation() {
         float range = getShiftRange();
         long maxAccuracy = (long) (2 * range);
         mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(mToState,
-                maxAccuracy, animComponent);
+                maxAccuracy);
         return (mLauncher.getDeviceProfile().isSeascape() ? 1 : -1) / range;
     }
 
     @Override
+    protected void updateProgress(float fraction) {
+        super.updateProgress(fraction);
+
+        // We have reached HINT_STATE, end the gesture now to go to OVERVIEW.
+        if (fraction >= 1 && mToState == HINT_STATE_TWO_BUTTON) {
+            final long now = SystemClock.uptimeMillis();
+            MotionEvent event = MotionEvent.obtain(now, now,
+                    MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
+            mDetector.onTouchEvent(event);
+            event.recycle();
+        }
+    }
+
+    @Override
     protected void onSwipeInteractionCompleted(LauncherState targetState) {
         super.onSwipeInteractionCompleted(targetState);
         if (!mIsTransposed) {
             mContinuousTouchCount++;
         }
-        if (mStartState == NORMAL && targetState == OVERVIEW) {
+        if (mStartState == NORMAL && targetState == HINT_STATE_TWO_BUTTON) {
             SystemUiProxy.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
         } else if (targetState == NORMAL
                 && mContinuousTouchCount >= MAX_NUM_SWIPES_TO_TRIGGER_EDU) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6759936..2a903eb 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -93,7 +93,6 @@
 import com.android.launcher3.util.WindowBounds;
 import com.android.quickstep.BaseActivityInterface.AnimationFactory;
 import com.android.quickstep.GestureState.GestureEndTarget;
-import com.android.quickstep.inputconsumers.OverviewInputConsumer;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
@@ -218,6 +217,8 @@
 
     // Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
     private RunningWindowAnim mRunningWindowAnim;
+    // Possible second animation running at the same time as mRunningWindowAnim
+    private Animator mParallelRunningAnim;
     private boolean mIsMotionPaused;
     private boolean mHasMotionEverBeenPaused;
 
@@ -318,9 +319,9 @@
         mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
                 this::invalidateHandlerWithLauncher);
         mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
-                this::notifyTransitionCancelled);
+                this::resetStateForAnimationCancel);
         mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_FINISH_WITH_NO_END,
-                this::notifyTransitionCancelled);
+                this::resetStateForAnimationCancel);
 
         if (!LIVE_TILE.get()) {
             mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
@@ -656,8 +657,13 @@
                     ||  (quickswitchThresholdPassed && centermostTaskFlags != 0));
             mRecentsAnimationController.setSplitScreenMinimized(swipeUpThresholdPassed);
 
-            int sysuiFlags = swipeUpThresholdPassed ? 0 : centermostTaskFlags;
-            mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
+            if (swipeUpThresholdPassed) {
+                mActivity.getSystemUiController().updateUiState(
+                        UI_STATE_OVERVIEW, mRecentsView.hasLightBackground());
+            } else {
+                mActivity.getSystemUiController().updateUiState(
+                        UI_STATE_OVERVIEW, centermostTaskFlags);
+            }
         }
     }
 
@@ -794,6 +800,13 @@
                 mRunningWindowAnim.end();
             }
         }
+        if (mParallelRunningAnim != null) {
+            if (cancel) {
+                mParallelRunningAnim.cancel();
+            } else {
+                mParallelRunningAnim.end();
+            }
+        }
     }
 
     private void onSettledOnEndTarget() {
@@ -1056,7 +1069,11 @@
             ActivityManagerWrapper.getInstance().registerTaskStackListener(
                     mActivityRestartListener);
 
-            mActivityInterface.onAnimateToLauncher(mGestureState.getEndTarget(), duration);
+            mParallelRunningAnim = mActivityInterface.getParallelAnimationToLauncher(
+                    mGestureState.getEndTarget(), duration);
+            if (mParallelRunningAnim != null) {
+                mParallelRunningAnim.start();
+            }
         }
 
         if (mGestureState.getEndTarget() == HOME) {
@@ -1067,9 +1084,9 @@
             HomeAnimationFactory homeAnimFactory = createHomeAnimationFactory(duration);
             mIsSwipingPipToHome = homeAnimFactory.supportSwipePipToHome()
                     && runningTaskTarget != null
-                    && runningTaskTarget.pictureInPictureParams != null
+                    && runningTaskTarget.taskInfo.pictureInPictureParams != null
                     && TaskInfoCompat.isAutoEnterPipEnabled(
-                            runningTaskTarget.pictureInPictureParams);
+                            runningTaskTarget.taskInfo.pictureInPictureParams);
             if (mIsSwipingPipToHome) {
                 mSwipePipToHomeAnimator = getSwipePipToHomeAnimator(
                         homeAnimFactory, runningTaskTarget, start);
@@ -1157,7 +1174,7 @@
         final Rect destinationBounds = SystemUiProxy.INSTANCE.get(mContext)
                 .startSwipePipToHome(taskInfo.topActivity,
                         TaskInfoCompat.getTopActivityInfo(taskInfo),
-                        runningTaskTarget.pictureInPictureParams,
+                        runningTaskTarget.taskInfo.pictureInPictureParams,
                         homeRotation,
                         mDp.hotseatBarSizePx);
         final Rect startBounds = new Rect();
@@ -1166,7 +1183,8 @@
                 runningTaskTarget.taskId,
                 taskInfo.topActivity,
                 runningTaskTarget.leash.getSurfaceControl(),
-                TaskInfoCompat.getPipSourceRectHint(runningTaskTarget.pictureInPictureParams),
+                TaskInfoCompat.getPipSourceRectHint(
+                        runningTaskTarget.taskInfo.pictureInPictureParams),
                 TaskInfoCompat.getWindowConfigurationBounds(taskInfo),
                 startBounds,
                 destinationBounds,
@@ -1365,10 +1383,6 @@
         mActivity.getRootView().setOnApplyWindowInsetsListener(null);
     }
 
-    private void notifyTransitionCancelled() {
-        mAnimationFactory.onTransitionCancelled();
-    }
-
     private void resetStateForAnimationCancel() {
         boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
         mActivityInterface.onTransitionCancelled(wasVisible);
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 0415009..147297a 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -206,18 +206,17 @@
             Rect gridRect = new Rect();
             calculateGridSize(context, dp, gridRect);
 
-            int rowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
-            float rowHeight = (gridRect.height() - rowSpacing) / 2f;
+            int verticalMargin = res.getDimensionPixelSize(
+                    R.dimen.overview_grid_focus_vertical_margin);
+            float taskHeight = gridRect.height() - verticalMargin * 2;
 
             PointF taskDimension = getTaskDimension(context, dp);
-            float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / Math.max(
-                    taskDimension.x, taskDimension.y);
+            float scale = taskHeight / Math.max(taskDimension.x, taskDimension.y);
             int outWidth = Math.round(scale * taskDimension.x);
             int outHeight = Math.round(scale * taskDimension.y);
 
-            int gravity = Gravity.TOP;
+            int gravity = Gravity.CENTER_VERTICAL;
             gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
-            gridRect.inset(0, dp.overviewTaskThumbnailTopMarginPx, 0, 0);
             Gravity.apply(gravity, outWidth, outHeight, gridRect, outRect);
         } else {
             int taskMargin = dp.overviewTaskMarginPx;
@@ -294,6 +293,30 @@
     }
 
     /**
+     * Calculates the overview grid non-focused task size for the provided device configuration.
+     */
+    public final void calculateGridTaskSize(Context context, DeviceProfile dp, Rect outRect,
+            PagedOrientationHandler orientedState) {
+        Resources res = context.getResources();
+        Rect gridRect = new Rect();
+        calculateGridSize(context, dp, gridRect);
+
+        int rowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
+        float rowHeight = (gridRect.height() - rowSpacing) / 2f;
+
+        PointF taskDimension = getTaskDimension(context, dp);
+        float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / Math.max(
+                taskDimension.x, taskDimension.y);
+        int outWidth = Math.round(scale * taskDimension.x);
+        int outHeight = Math.round(scale * taskDimension.y);
+
+        int gravity = Gravity.TOP;
+        gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
+        gridRect.inset(0, dp.overviewTaskThumbnailTopMarginPx, 0, 0);
+        Gravity.apply(gravity, outWidth, outHeight, gridRect, outRect);
+    }
+
+    /**
      * Calculates the modal taskView size for the provided device configuration
      */
     public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
@@ -324,7 +347,9 @@
      * Called when the gesture ends and the animation starts towards the given target. No-op by
      * default, but subclasses can override to add an additional animation with the same duration.
      */
-    public void onAnimateToLauncher(GestureState.GestureEndTarget endTarget, long duration) {
+    public @Nullable Animator getParallelAnimationToLauncher(
+            GestureState.GestureEndTarget endTarget, long duration) {
+        return null;
     }
 
     /**
@@ -343,8 +368,6 @@
 
         void createActivityInterface(long transitionLength);
 
-        default void onTransitionCancelled() { }
-
         /**
          * @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.
@@ -411,11 +434,6 @@
         }
 
         @Override
-        public void onTransitionCancelled() {
-            mActivity.getStateManager().goToState(mStartState, false /* animate */);
-        }
-
-        @Override
         public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
             if (mIsAttachedToWindow == attached && animate) {
                 return;
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 98b96b2..878f5c9 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
 
+import android.animation.Animator;
 import android.content.Context;
 import android.graphics.Rect;
 import android.view.MotionEvent;
@@ -267,13 +268,14 @@
     }
 
     @Override
-    public void onAnimateToLauncher(GestureEndTarget endTarget, long duration) {
+    public @Nullable Animator getParallelAnimationToLauncher(GestureEndTarget endTarget,
+            long duration) {
         TaskbarController taskbarController = getTaskbarController();
         if (taskbarController == null) {
-            return;
+            return null;
         }
         LauncherState toState = stateFromGestureEndTarget(endTarget);
-        taskbarController.createAnimToLauncher(toState, duration).start();
+        return taskbarController.createAnimToLauncher(toState, duration);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 1ce4201..311ac83 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -29,6 +29,7 @@
 import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.views.FloatingIconView;
 import com.android.quickstep.util.RectFSpringAnim;
 import com.android.quickstep.util.StaggeredWorkspaceAnim;
@@ -134,7 +135,7 @@
             // to home.
             long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
             return mActivity.getStateManager().createAnimationToNewWorkspace(
-                    NORMAL, accuracy, 0 /* animComponents */);
+                    NORMAL, accuracy, StateAnimationConfig.SKIP_ALL_ANIMATIONS);
         }
 
         @Override
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index d3ed791..1340abb 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -56,7 +56,6 @@
 import com.android.launcher3.util.ActivityTracker;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SystemUiController;
-import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.quickstep.fallback.FallbackRecentsStateController;
 import com.android.quickstep.fallback.FallbackRecentsView;
@@ -267,7 +266,7 @@
         setupViews();
 
         getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
-                Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
+                mFallbackRecentsView.hasLightBackground());
         ACTIVITY_TRACKER.handleCreate(this);
     }
 
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 458f45a..23e35f6 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -187,7 +187,7 @@
             SettingsCache.OnChangeListener onChangeListener =
                     enabled -> mIsOneHandedModeEnabled = enabled;
             settingsCache.register(oneHandedUri, onChangeListener);
-            settingsCache.dispatchOnChange(oneHandedUri);
+            mIsOneHandedModeEnabled = settingsCache.getValue(oneHandedUri);
             runOnDestroy(() -> settingsCache.unregister(oneHandedUri, onChangeListener));
         } else {
             mIsOneHandedModeEnabled = false;
@@ -199,7 +199,7 @@
         SettingsCache.OnChangeListener onChangeListener =
                 enabled -> mIsSwipeToNotificationEnabled = enabled;
         settingsCache.register(swipeBottomNotificationUri, onChangeListener);
-        settingsCache.dispatchOnChange(swipeBottomNotificationUri);
+        mIsSwipeToNotificationEnabled = settingsCache.getValue(swipeBottomNotificationUri);
         runOnDestroy(() -> settingsCache.unregister(swipeBottomNotificationUri, onChangeListener));
 
         Uri setupCompleteUri = Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE);
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index f4b8b62..a8c09dc 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -29,7 +29,6 @@
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -67,8 +66,6 @@
     // How much further we can drag past recents, as a factor of mTransitionDragLength.
     protected float mDragLengthFactor = 1;
 
-    protected final float mMaxShadowRadius;
-
     protected AnimatorControllerWithResistance mWindowTransitionController;
 
     public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState,
@@ -82,9 +79,6 @@
         mTaskViewSimulator.getOrientationState().update(
                 mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
                 mDeviceState.getRotationTouchHelper().getDisplayRotation());
-
-        mMaxShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.max_shadow_radius);
-        mTransformParams.setShadowRadius(mMaxShadowRadius);
     }
 
     protected void initTransitionEndpoints(DeviceProfile dp) {
@@ -271,11 +265,9 @@
 
             mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
             float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
-            float shadowRadius = Utilities.mapRange(progress, mMaxShadowRadius, 0);
             mTransformParams
                     .setTargetAlpha(getWindowAlpha(progress))
-                    .setCornerRadius(cornerRadius)
-                    .setShadowRadius(shadowRadius);
+                    .setCornerRadius(cornerRadius);
 
             mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
             mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
@@ -286,8 +278,7 @@
                 Builder builder, RemoteAnimationTargetCompat app, TransformParams params) {
             builder.withMatrix(mMatrix)
                     .withWindowCrop(mCropRect)
-                    .withCornerRadius(params.getCornerRadius())
-                    .withShadowRadius(app.isTranslucent ? 0 : params.getShadowRadius());
+                    .withCornerRadius(params.getCornerRadius());
         }
 
         @Override
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index cf71eae..1f332c4 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -88,6 +88,17 @@
     }
 
     @Override
+    public void onBackPressed() {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.onBackPressed();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call onBackPressed", e);
+            }
+        }
+    }
+
+    @Override
     public IBinder asBinder() {
         // Do nothing
         return null;
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index 08503cf..ba1c413 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -146,7 +146,7 @@
                     key.getComponent(), key.userId);
             if (activityInfo != null) {
                 BitmapInfo bitmapInfo = getBitmapInfo(
-                        mIconProvider.getIcon(activityInfo, UserHandle.of(key.userId)),
+                        mIconProvider.getIcon(activityInfo),
                         key.userId,
                         desc.getPrimaryColor(),
                         activityInfo.applicationInfo.isInstantApp());
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 1fb9465..e9d2eb4 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -239,8 +239,9 @@
         @BinderThread
         public void onSystemUiStateChanged(int stateFlags) {
             MAIN_EXECUTOR.execute(() -> {
+                int lastFlags = mDeviceState.getSystemUiStateFlags();
                 mDeviceState.setSystemUiFlags(stateFlags);
-                TouchInteractionService.this.onSystemUiFlagsChanged();
+                TouchInteractionService.this.onSystemUiFlagsChanged(lastFlags);
             });
         }
 
@@ -362,7 +363,7 @@
         mResetGestureInputConsumer = new ResetGestureInputConsumer(mTaskAnimationManager);
         mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
         mInputConsumer.registerInputConsumer();
-        onSystemUiFlagsChanged();
+        onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags());
         onAssistantVisibilityChanged();
 
         // Temporarily disable model preload
@@ -414,7 +415,7 @@
     }
 
     @UiThread
-    private void onSystemUiFlagsChanged() {
+    private void onSystemUiFlagsChanged(int lastSysUIFlags) {
         if (mDeviceState.isUserUnlocked()) {
             int systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
             SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
@@ -422,14 +423,17 @@
             mOverviewComponentObserver.getActivityInterface().onSystemUiFlagsChanged(
                     systemUiStateFlags);
 
-            // Update the tracing state
-            if ((systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED) != 0) {
-                Log.d(TAG, "Starting tracing.");
-                ProtoTracer.INSTANCE.get(this).start();
-            } else {
-                Log.d(TAG, "Stopping tracing. Dumping to file="
-                    + ProtoTracer.INSTANCE.get(this).getTraceFile());
-                ProtoTracer.INSTANCE.get(this).stop();
+            if ((lastSysUIFlags & SYSUI_STATE_TRACING_ENABLED) !=
+                    (systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED)) {
+                // Update the tracing state
+                if ((systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED) != 0) {
+                    Log.d(TAG, "Starting tracing.");
+                    ProtoTracer.INSTANCE.get(this).start();
+                } else {
+                    Log.d(TAG, "Stopping tracing. Dumping to file="
+                            + ProtoTracer.INSTANCE.get(this).getTraceFile());
+                    ProtoTracer.INSTANCE.get(this).stop();
+                }
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 82bfa9b..8962ec9 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -20,8 +20,6 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
 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.PLAY_ATOMIC_OVERVIEW_PEEK;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
@@ -63,10 +61,6 @@
     @Override
     public void setStateWithAnimation(RecentsState toState, StateAnimationConfig config,
             PendingAnimation setter) {
-        if (!config.hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) {
-            // The entire recents animation is played atomically.
-            return;
-        }
         if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
             return;
         }
@@ -82,7 +76,9 @@
         float clearAllButtonAlpha = state.hasClearAllButton() ? 1 : 0;
         setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
                 clearAllButtonAlpha, LINEAR);
-        float overviewButtonAlpha =  state.hasOverviewActions(mActivity) ? 1 : 0;
+        float overviewButtonAlpha =
+                state.hasOverviewActions() && mRecentsView.shouldShowOverviewActionsForState(state)
+                        ? 1 : 0;
         setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
                 MultiValueAlpha.VALUE, overviewButtonAlpha, LINEAR);
 
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index e075045..854a140 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -42,7 +42,7 @@
 import java.util.ArrayList;
 
 @TargetApi(Build.VERSION_CODES.R)
-public class FallbackRecentsView extends RecentsView<RecentsActivity>
+public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
         implements StateListener<RecentsState> {
 
     private RunningTaskInfo mHomeTaskInfo;
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index a9856d2..bbe279e 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -99,8 +99,8 @@
     /**
      * For this state, whether overview actions should be shown.
      */
-    public boolean hasOverviewActions(RecentsActivity activity) {
-        return hasFlag(FLAG_OVERVIEW_ACTIONS) && !showAsGrid(activity.getDeviceProfile());
+    public boolean hasOverviewActions() {
+        return hasFlag(FLAG_OVERVIEW_ACTIONS);
     }
 
     public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index f336bf5..b336d2f 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -80,7 +80,7 @@
         SettingsCache mSettingsCache = SettingsCache.INSTANCE.get(context);
         mSettingsCache.register(NOTIFICATION_BADGING_URI,
                 this::onNotificationDotsChanged);
-        mSettingsCache.dispatchOnChange(NOTIFICATION_BADGING_URI);
+        onNotificationDotsChanged(mSettingsCache.getValue(NOTIFICATION_BADGING_URI));
     }
 
     private static ArrayMap<String, LoggablePref> loadPrefKeys(Context context) {
diff --git a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
index 0f2d778..2285d74 100644
--- a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
+++ b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
@@ -19,9 +19,12 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
 
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
+import android.app.Activity;
+import android.app.ActivityOptions;
 import android.app.prediction.AppTarget;
 import android.content.ClipData;
 import android.content.ClipDescription;
@@ -37,11 +40,13 @@
 import android.graphics.RectF;
 import android.net.Uri;
 import android.util.Log;
+import android.view.View;
 
 import androidx.annotation.UiThread;
 import androidx.annotation.WorkerThread;
 import androidx.core.content.FileProvider;
 
+import com.android.internal.app.ChooserActivity;
 import com.android.launcher3.BuildConfig;
 import com.android.quickstep.SystemUiProxy;
 import com.android.systemui.shared.recents.model.Task;
@@ -126,6 +131,22 @@
     }
 
     /**
+     * Launch the activity to share image with shared element transition.
+     */
+    @UiThread
+    public static void startShareActivity(Context context, Supplier<Bitmap> bitmapSupplier,
+            Rect crop, Intent intent, String tag, View sharedElement) {
+        if (bitmapSupplier.get() == null) {
+            Log.e(tag, "No snapshot available, not starting share.");
+            return;
+        }
+
+        UI_HELPER_EXECUTOR.execute(() -> persistBitmapAndStartActivity(context,
+                bitmapSupplier.get(), crop, intent, ImageActionUtils::getShareIntentForImageUri,
+                tag, sharedElement));
+    }
+
+    /**
      * Starts activity based on given intent created from image uri.
      */
     @WorkerThread
@@ -142,6 +163,30 @@
     }
 
     /**
+     * Starts activity based on given intent created from image uri with shared element transition.
+     */
+    @WorkerThread
+    public static void persistBitmapAndStartActivity(Context context, Bitmap bitmap, Rect crop,
+            Intent intent, BiFunction<Uri, Intent, Intent[]> uriToIntentMap, String tag,
+            View scaledImage) {
+        Intent[] intents = uriToIntentMap.apply(getImageUri(bitmap, crop, context, tag), intent);
+
+        // Work around b/159412574
+        if (intents.length == 1) {
+            MAIN_EXECUTOR.execute(() -> context.startActivity(intents[0],
+                    ActivityOptions.makeSceneTransitionAnimation((Activity) context, scaledImage,
+                            ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle()));
+
+        } else {
+            MAIN_EXECUTOR.execute(() -> context.startActivities(intents,
+                    ActivityOptions.makeSceneTransitionAnimation((Activity) context, scaledImage,
+                            ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle()));
+        }
+    }
+
+
+
+    /**
      * Converts image bitmap to Uri by temporarily saving bitmap to cache, and creating Uri pointing
      * to that location. Used to be able to share an image with another app.
      *
diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index 1031c5b..1128dac 100644
--- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -22,13 +22,11 @@
 import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
 import static com.android.launcher3.anim.Interpolators.clampToProgress;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
 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_TRANSLATE_X;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
-import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
@@ -105,10 +103,6 @@
 
         StateAnimationConfig config = new UseFirstInterpolatorStateAnimConfig();
         config.duration = duration;
-        config.animFlags = playStaggeredWorkspaceAnim
-                // StaggeredWorkspaceAnim doesn't animate overview, so we handle it here.
-                ? PLAY_ATOMIC_OVERVIEW_PEEK
-                : ANIM_ALL_COMPONENTS;
         boolean isLayoutNaturalToLauncher = recentsView.getPagedOrientationHandler()
                 .isLayoutNaturalToLauncher();
         config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, isLayoutNaturalToLauncher
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index 1544f00..6d6e802 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -26,6 +26,7 @@
 import android.content.SharedPreferences;
 
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.hybridhotseat.HotseatPredictionController;
@@ -63,7 +64,8 @@
             });
         }
 
-        if (!hasReachedMaxCount(HOTSEAT_DISCOVERY_TIP_COUNT)) {
+        if (!Utilities.IS_RUNNING_IN_TEST_HARNESS
+                && !hasReachedMaxCount(HOTSEAT_DISCOVERY_TIP_COUNT)) {
             stateManager.addStateListener(new StateListener<LauncherState>() {
                 boolean mFromAllApps = false;
 
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index f68e936..6757e4c 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -21,7 +21,6 @@
 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
 
@@ -184,7 +183,7 @@
      */
     private void prepareToAnimate(Launcher launcher, boolean animateOverviewScrim) {
         StateAnimationConfig config = new StateAnimationConfig();
-        config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER;
+        config.animFlags = SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER;
         config.duration = 0;
         // setRecentsAttachedToAppWindow() will animate recents out.
         launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start();
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 6cfe302..3c8a12c 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -330,8 +330,7 @@
             Builder builder, RemoteAnimationTargetCompat app, TransformParams params) {
         builder.withMatrix(mMatrix)
                 .withWindowCrop(mTmpCropRect)
-                .withCornerRadius(getCurrentCornerRadius())
-                .withShadowRadius(app.isTranslucent ? 0 : params.getShadowRadius());
+                .withCornerRadius(getCurrentCornerRadius());
 
         if (LIVE_TILE.get() && params.getRecentsSurface() != null) {
             // When relativeLayer = 0, it reverts the surfaces back to the original order.
diff --git a/quickstep/src/com/android/quickstep/util/TransformParams.java b/quickstep/src/com/android/quickstep/util/TransformParams.java
index cdf5163..756331d 100644
--- a/quickstep/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/src/com/android/quickstep/util/TransformParams.java
@@ -57,7 +57,6 @@
     private float mProgress;
     private float mTargetAlpha;
     private float mCornerRadius;
-    private float mShadowRadius;
     private RemoteAnimationTargets mTargetSet;
     private SurfaceTransactionApplier mSyncTransactionApplier;
     private SurfaceControl mRecentsSurface;
@@ -69,7 +68,6 @@
         mProgress = 0;
         mTargetAlpha = 1;
         mCornerRadius = -1;
-        mShadowRadius = 0;
     }
 
     /**
@@ -93,14 +91,6 @@
     }
 
     /**
-     * Sets the shadow radius of the transformed window, in pixels.
-     */
-    public TransformParams setShadowRadius(float shadowRadius) {
-        mShadowRadius = shadowRadius;
-        return this;
-    }
-
-    /**
      * Specifies the alpha of the transformed window. Default is 1.
      */
     public TransformParams setTargetAlpha(float targetAlpha) {
@@ -207,10 +197,6 @@
         return mCornerRadius;
     }
 
-    public float getShadowRadius() {
-        return mShadowRadius;
-    }
-
     public SurfaceControl getRecentsSurface() {
         return mRecentsSurface;
     }
diff --git a/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java b/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java
new file mode 100644
index 0000000..185080e5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views;
+
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.animation.Interpolator;
+
+import androidx.core.graphics.ColorUtils;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.ScrimView;
+
+/**
+ * Scrim used for all-apps background. uses interpolator to coordinate fade in with
+ * all-apps contents
+ *
+ * Note: ranges are inverted because progress goes from 1 to 0 for NORMAL->AllAPPS
+ */
+public class AllAppsScrimView extends ScrimView<BaseQuickstepLauncher> {
+
+    private static final float TINT_DECAY_MULTIPLIER = .5f;
+
+    //min progress for scrim to become visible
+    private static final float SCRIM_VISIBLE_THRESHOLD = .9f;
+    //max progress where scrim alpha animates.
+    private static final float SCRIM_SOLID_THRESHOLD = .5f;
+    private final Interpolator mScrimInterpolator = Interpolators.clampToProgress(ACCEL,
+            SCRIM_SOLID_THRESHOLD,
+            SCRIM_VISIBLE_THRESHOLD);
+
+    // In transposed layout, we simply draw a flat color.
+    private boolean mDrawingFlatColor;
+
+    private final int mEndAlpha;
+    private final Paint mPaint;
+
+    private int mCurrentScrimColor;
+    private final int mTintColor;
+
+    public AllAppsScrimView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mMaxScrimAlpha = Math.round(OVERVIEW.getOverviewScrimAlpha(mLauncher) * 255);
+        mTintColor = Themes.getColorAccent(mContext);
+
+
+        mEndAlpha = Color.alpha(mEndScrim);
+        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+        // Just assume the easiest UI for now, until we have the proper layout information.
+        mDrawingFlatColor = true;
+    }
+
+    @Override
+    public void reInitUi() {
+        DeviceProfile dp = mLauncher.getDeviceProfile();
+        mDrawingFlatColor = dp.isVerticalBarLayout();
+        updateColors();
+        updateSysUiColors();
+        invalidate();
+    }
+
+    @Override
+    public void updateColors() {
+        super.updateColors();
+        if (mDrawingFlatColor) {
+            return;
+        }
+
+        if (mProgress >= 1) {
+            mCurrentScrimColor = 0;
+        } else {
+            float interpolationProgress = mScrimInterpolator.getInterpolation(mProgress);
+            // Note that these ranges and interpolators are inverted because progress goes 1 to 0.
+            int alpha = Math.round(Utilities.mapRange(interpolationProgress, mEndAlpha, 0));
+            int color = ColorUtils.blendARGB(mEndScrim, mTintColor,
+                    mProgress * TINT_DECAY_MULTIPLIER);
+            mCurrentScrimColor = setColorAlphaBound(color, alpha);
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mDrawingFlatColor) {
+            if (mCurrentFlatColor != 0) {
+                canvas.drawColor(mCurrentFlatColor);
+            }
+            return;
+        }
+
+        if (Color.alpha(mCurrentScrimColor) == 0) {
+            return;
+        } else if (mProgress <= 0) {
+            canvas.drawColor(mCurrentScrimColor);
+            return;
+        }
+
+        mPaint.setColor(mCurrentScrimColor);
+        canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index 12b59d0..d616f7c 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -45,14 +45,15 @@
     private float mScrollAlpha = 1;
     private float mContentAlpha = 1;
     private float mVisibilityAlpha = 1;
+    private float mFullscreenProgress = 1;
     private float mGridProgress = 1;
 
     private boolean mIsRtl;
     private float mNormalTranslationPrimary;
+    private float mFullscreenTranslationPrimary;
     private float mGridTranslationPrimary;
-    private float mGridTranslationSecondary;
     private float mGridScrollOffset;
-    private float mOffsetTranslationPrimary;
+    private float mScrollOffsetPrimary;
 
     private int mSidePadding;
 
@@ -130,13 +131,13 @@
         setClickable(Math.min(alpha, 1) == 1);
     }
 
-    public void setGridTranslationPrimary(float gridTranslationPrimary) {
-        mGridTranslationPrimary = gridTranslationPrimary;
+    public void setFullscreenTranslationPrimary(float fullscreenTranslationPrimary) {
+        mFullscreenTranslationPrimary = fullscreenTranslationPrimary;
         applyPrimaryTranslation();
     }
 
-    public void setGridTranslationSecondary(float gridTranslationSecondary) {
-        mGridTranslationSecondary = gridTranslationSecondary;
+    public void setGridTranslationPrimary(float gridTranslationPrimary) {
+        mGridTranslationPrimary = gridTranslationPrimary;
         applyPrimaryTranslation();
     }
 
@@ -144,22 +145,34 @@
         mGridScrollOffset = gridScrollOffset;
     }
 
-    public void setOffsetTranslationPrimary(float offsetTranslationPrimary) {
-        mOffsetTranslationPrimary = offsetTranslationPrimary;
-        applyPrimaryTranslation();
+    public void setScrollOffsetPrimary(float scrollOffsetPrimary) {
+        mScrollOffsetPrimary = scrollOffsetPrimary;
     }
 
-    public float getScrollAdjustment(boolean gridEnabled) {
+    public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
         float scrollAdjustment = 0;
+        if (fullscreenEnabled) {
+            scrollAdjustment += mFullscreenTranslationPrimary;
+        }
         if (gridEnabled) {
             scrollAdjustment += mGridTranslationPrimary + mGridScrollOffset;
         }
-        scrollAdjustment += mOffsetTranslationPrimary;
+        scrollAdjustment += mScrollOffsetPrimary;
         return scrollAdjustment;
     }
 
-    public float getOffsetAdjustment(boolean gridEnabled) {
-        return getScrollAdjustment(gridEnabled);
+    public float getOffsetAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
+        return getScrollAdjustment(fullscreenEnabled, gridEnabled);
+    }
+
+    /**
+     * Adjust translation when this TaskView is about to be shown fullscreen.
+     *
+     * @param progress: 0 = no translation; 1 = translate according to TaskVIew translations.
+     */
+    public void setFullscreenProgress(float progress) {
+        mFullscreenProgress = progress;
+        applyPrimaryTranslation();
     }
 
     /**
@@ -181,8 +194,8 @@
         PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
         orientationHandler.getPrimaryViewTranslate().set(this,
                 orientationHandler.getPrimaryValue(0f, getOriginalTranslationY())
-                        + mNormalTranslationPrimary + mOffsetTranslationPrimary + getGridTrans(
-                        mGridTranslationPrimary));
+                        + mNormalTranslationPrimary + getFullscreenTrans(
+                        mFullscreenTranslationPrimary) + getGridTrans(mGridTranslationPrimary));
     }
 
     private void applySecondaryTranslation() {
@@ -193,8 +206,11 @@
 
         PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
         orientationHandler.getSecondaryViewTranslate().set(this,
-                orientationHandler.getSecondaryValue(0f, getOriginalTranslationY())
-                        + getGridTrans(mGridTranslationSecondary));
+                orientationHandler.getSecondaryValue(0f, getOriginalTranslationY()));
+    }
+
+    private float getFullscreenTrans(float endTranslation) {
+        return mFullscreenProgress > 0 ? endTranslation : 0;
     }
 
     private float getGridTrans(float endTranslation) {
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 25ae055..deb674c 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -30,6 +30,7 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.AppUsageLimit;
 import android.graphics.Outline;
+import android.graphics.Paint;
 import android.icu.text.MeasureFormat;
 import android.icu.text.MeasureFormat.FormatWidth;
 import android.icu.util.Measure;
@@ -48,6 +49,7 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.systemui.shared.recents.model.Task;
 
 import java.time.Duration;
@@ -297,4 +299,17 @@
             mBanner.setAlpha(alpha);
         }
     }
+
+    void setBannerColorTint(int color, float amount) {
+        if (mBanner == null) {
+            return;
+        }
+        if (mBannerAlpha == 0 || amount == 0) {
+            mBanner.setLayerType(View.LAYER_TYPE_NONE, null);
+        }
+        Paint layerPaint = new Paint();
+        layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
+        mBanner.setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint);
+        mBanner.setLayerPaint(layerPaint);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index ed642df..5b0ade0 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -21,6 +21,8 @@
 import android.util.AttributeSet;
 import android.view.View;
 
+import com.android.launcher3.Utilities;
+
 /**
  * A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
  * when the drawable changes.
@@ -102,4 +104,16 @@
             setVisibility(INVISIBLE);
         }
     }
+
+    /**
+     * Set the tint color of the icon, useful for scrimming or dimming.
+     *
+     * @param color to blend in.
+     * @param amount [0,1] 0 no tint, 1 full tint
+     */
+    public void setIconColorTint(int color, float amount) {
+        if (mDrawable != null) {
+            mDrawable.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index a0af68a..896d1ae 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -19,11 +19,13 @@
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
+import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
 import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
 
 import android.annotation.TargetApi;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.os.Build;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -35,6 +37,7 @@
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.StateManager.StateListener;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.quickstep.LauncherActivityInterface;
 import com.android.quickstep.util.OverviewToHomeAnim;
 import com.android.systemui.plugins.PluginListener;
@@ -44,7 +47,7 @@
  * {@link RecentsView} used in Launcher activity
  */
 @TargetApi(Build.VERSION_CODES.O)
-public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
+public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher, LauncherState>
         implements StateListener<LauncherState> {
 
     private RecentsExtraCard mRecentsExtraCardPlugin;
@@ -234,4 +237,33 @@
             }
         }
     }
+
+    @Override
+    protected void onDismissAnimationEnds() {
+        super.onDismissAnimationEnds();
+        if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
+            // We want to keep the tasks translations in this temporary state
+            // after resetting the rest above
+            setTaskViewsResistanceTranslation(mTaskViewsSecondaryTranslation);
+            setTaskViewsPrimaryTranslation(mTaskViewsPrimaryTranslation);
+        }
+    }
+
+    @Override
+    public void initiateSplitSelect(TaskView taskView,
+            SplitConfigurationOptions.SplitPositionOption splitPositionOption) {
+        super.initiateSplitSelect(taskView, splitPositionOption);
+        mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        // 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();
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 6fcd54c..9adeea4 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -16,6 +16,7 @@
 
 package com.android.quickstep.views;
 
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SHARE;
 
 import android.content.Context;
@@ -32,6 +33,7 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.quickstep.SysUINavigationMode;
@@ -76,6 +78,7 @@
     private static final int INDEX_VISIBILITY_ALPHA = 1;
     private static final int INDEX_FULLSCREEN_ALPHA = 2;
     private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
+    private static final int INDEX_SCROLL_ALPHA = 4;
 
     private final MultiValueAlpha mMultiValueAlpha;
 
@@ -87,6 +90,9 @@
 
     protected T mCallbacks;
 
+    private float mModalness;
+    private float mModalTransformY;
+
     public OverviewActionsView(Context context) {
         this(context, null);
     }
@@ -97,7 +103,7 @@
 
     public OverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr, 0);
-        mMultiValueAlpha = new MultiValueAlpha(this, 4);
+        mMultiValueAlpha = new MultiValueAlpha(this, 5);
         mMultiValueAlpha.setUpdateVisibility(true);
     }
 
@@ -189,6 +195,10 @@
         return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
     }
 
+    public AlphaProperty getScrollAlpha() {
+        return mMultiValueAlpha.getProperty(INDEX_SCROLL_ALPHA);
+    }
+
     private void updateHorizontalPadding() {
         setPadding(mInsets.left, 0, mInsets.right, 0);
     }
@@ -224,4 +234,27 @@
         bottomMargin += mInsets.bottom;
         return bottomMargin;
     }
+
+    /**
+     * The current task is fully modal (modalness = 1) when it is shown on its own in a modal
+     * way. Modalness 0 means the task is shown in context with all the other tasks.
+     */
+    public void setTaskModalness(float modalness) {
+        mModalness = modalness;
+        applyTranslationY();
+    }
+
+    public void setModalTransformY(float modalTransformY) {
+        mModalTransformY = modalTransformY;
+        applyTranslationY();
+    }
+
+    private void applyTranslationY() {
+        setTranslationY(getModalTrans(mModalTransformY));
+    }
+
+    private float getModalTrans(float endTranslation) {
+        float progress = ACCEL_DEACCEL.getInterpolation(mModalness);
+        return Utilities.mapRange(progress, 0, endTranslation);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index a35580f..3c171fe 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -25,8 +25,6 @@
 import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
 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.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
 import static com.android.launcher3.Utilities.mapToRange;
@@ -81,6 +79,7 @@
 import android.util.FloatProperty;
 import android.util.Log;
 import android.util.SparseBooleanArray;
+import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -91,6 +90,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
 import android.widget.ListView;
 
 import androidx.annotation.Nullable;
@@ -100,7 +100,6 @@
 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;
@@ -111,6 +110,7 @@
 import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statemanager.BaseState;
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.touch.PagedOrientationHandler;
@@ -161,8 +161,9 @@
  * A list of recent tasks.
  */
 @TargetApi(Build.VERSION_CODES.R)
-public abstract class RecentsView<T extends StatefulActivity> extends PagedView implements
-        Insettable, TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
+public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>,
+        STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
+        TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
         InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener,
         SplitScreenBounds.OnChangeListener {
 
@@ -295,7 +296,7 @@
             };
 
     protected final RecentsOrientedState mOrientationState;
-    protected final BaseActivityInterface mSizeStrategy;
+    protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
     protected RecentsAnimationController mRecentsAnimationController;
     protected SurfaceTransactionApplier mSyncTransactionApplier;
     protected int mTaskWidth;
@@ -304,6 +305,7 @@
     protected final TaskViewSimulator mLiveTileTaskViewSimulator;
     protected final Rect mLastComputedTaskSize = new Rect();
     protected final Rect mLastComputedGridSize = new Rect();
+    protected final Rect mLastComputedGridTaskSize = new Rect();
     // How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
     protected Float mLastComputedTaskPushOutDistance = null;
     protected boolean mEnableDrawingLiveTile = false;
@@ -317,10 +319,11 @@
     // The threshold at which we update the SystemUI flags when animating from the task into the app
     public static final float UPDATE_SYSUI_FLAGS_THRESHOLD = 0.85f;
 
-    protected final T mActivity;
+    protected final ACTIVITY_TYPE mActivity;
     private final float mFastFlingVelocity;
     private final RecentsModel mModel;
     private final int mRowSpacing;
+    private final int mGridSideMargin;
     private final ClearAllButton mClearAllButton;
     private final Rect mClearAllButtonDeadZoneRect = new Rect();
     private final Rect mTaskViewDeadZoneRect = new Rect();
@@ -347,8 +350,8 @@
     private boolean mOverviewFullscreenEnabled;
 
     private float mAdjacentPageOffset = 0;
-    private float mTaskViewsSecondaryTranslation = 0;
-    private float mTaskViewsPrimaryTranslation = 0;
+    protected float mTaskViewsSecondaryTranslation = 0;
+    protected float mTaskViewsPrimaryTranslation = 0;
     // Progress from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
     private float mGridProgress = 0;
 
@@ -436,9 +439,12 @@
     protected int mRunningTaskId = -1;
     protected boolean mRunningTaskTileHidden;
     private Task mTmpRunningTask;
+    protected int mFocusedTaskId = -1;
+    private float mFocusedTaskRatio;
 
     private boolean mRunningTaskIconScaledDown = false;
 
+    private final boolean mHasLightBackground;
     private boolean mOverviewStateEnabled;
     private boolean mHandleTaskStackChanges;
     private boolean mSwipeDownShouldLaunchApp;
@@ -541,6 +547,7 @@
         mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
         setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
         mRowSpacing = getResources().getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
+        mGridSideMargin = getResources().getDimensionPixelSize(R.dimen.overview_grid_side_margin);
         mSquaredTouchSlop = squaredTouchSlop(context);
 
         mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
@@ -552,6 +559,7 @@
                 .getDimension(R.dimen.recents_empty_message_text_size));
         mEmptyMessagePaint.setTypeface(Typeface.create(Themes.getDefaultBodyFont(context),
                 Typeface.NORMAL));
+        mEmptyMessagePaint.setAntiAlias(true);
         mEmptyMessagePadding = getResources()
                 .getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
         setWillNotDraw(false);
@@ -570,6 +578,8 @@
         mLiveTileTaskViewSimulator.recentsViewScale.value = 1;
         mLiveTileTaskViewSimulator.setOrientationState(mOrientationState);
         mLiveTileTaskViewSimulator.setDrawsBelowRecents(true);
+
+        mHasLightBackground = Themes.getAttrBoolean(mActivity, android.R.attr.isLightTheme);
     }
 
     public OverScroller getScroller() {
@@ -645,7 +655,6 @@
         mActionsView = actionsView;
         mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
         mSplitPlaceholderView = splitPlaceholderView;
-
     }
 
     public SplitPlaceholderView getSplitPlaceholder() {
@@ -847,6 +856,13 @@
                 cancelSplitSelect(false);
             }
         }
+
+        if (enabled) {
+            mActivity.getSystemUiController().updateUiState(
+                    UI_STATE_OVERVIEW, hasLightBackground());
+        } else {
+            mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
+        }
     }
 
     public void onDigitalWellbeingToastShown() {
@@ -1119,6 +1135,7 @@
         for (int i = 0; i < taskCount; i++) {
             getTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
         }
+        mClearAllButton.setFullscreenProgress(fullscreenProgress);
 
         // Fade out the actions view quickly (0.1 range)
         mActionsView.getFullscreenAlpha().setValue(
@@ -1158,9 +1175,31 @@
 
         mSizeStrategy.calculateGridSize(mActivity, mActivity.getDeviceProfile(),
                 mLastComputedGridSize);
+        mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
+                mLastComputedGridTaskSize, mOrientationHandler);
 
         // Force TaskView to update size from thumbnail
         updateTaskSize();
+
+        // Update ActionsView position
+        FrameLayout.LayoutParams layoutParams =
+                (FrameLayout.LayoutParams) mActionsView.getLayoutParams();
+        if (dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+            layoutParams.gravity = Gravity.BOTTOM;
+            layoutParams.bottomMargin =
+                    dp.heightPx - mInsets.bottom - mLastComputedGridSize.bottom;
+            layoutParams.leftMargin = mLastComputedTaskSize.left;
+            layoutParams.rightMargin = dp.widthPx - mLastComputedTaskSize.right;
+            // When in modal state, remove bottom margin to avoid covering content.
+            mActionsView.setModalTransformY(layoutParams.bottomMargin);
+        } else {
+            layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+            layoutParams.bottomMargin = 0;
+            layoutParams.leftMargin = 0;
+            layoutParams.rightMargin = 0;
+            mActionsView.setModalTransformY(0);
+        }
+        mActionsView.setLayoutParams(layoutParams);
     }
 
     /**
@@ -1192,7 +1231,6 @@
             // Compensate page spacing widening caused by RecentsView scaling.
             widthDiff += mPageSpacing * (1 - 1 / mFullscreenScale);
             float fullscreenTranslationX = mIsRtl ? widthDiff : -widthDiff;
-            fullscreenTranslations[i] += fullscreenTranslationX;
             accumulatedTranslationX += fullscreenTranslationX;
         }
 
@@ -1202,6 +1240,13 @@
             getTaskViewAt(i).setFullscreenTranslationX(
                     fullscreenTranslations[i] - fullscreenTranslations[firstNonHomeTaskIndex]);
         }
+        mClearAllButton.setFullscreenTranslationPrimary(
+                accumulatedTranslationX - fullscreenTranslations[firstNonHomeTaskIndex]);
+
+        // Align ClearAllButton to the left (RTL) or right (non-RTL), which is different from other
+        // TaskViews.
+        int clearAllWidthDiff = mTaskWidth - mClearAllButton.getWidth();
+        mClearAllButton.setScrollOffsetPrimary(mIsRtl ? clearAllWidthDiff : -clearAllWidthDiff);
 
         updateGridProperties(false);
     }
@@ -1212,11 +1257,36 @@
         mLastComputedTaskSize.set(outRect);
     }
 
+    /**
+     * Returns the size of task selected to enter modal state.
+     */
+    public Point getSelectedTaskSize() {
+        mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), mTempRect,
+                mOrientationHandler);
+        int taskWidth = mTempRect.width();
+        int taskHeight = mTempRect.height();
+        if (mRunningTaskId != -1) {
+            int boxLength = Math.max(taskWidth, taskHeight);
+            if (mFocusedTaskRatio > 1) {
+                taskWidth = boxLength;
+                taskHeight = (int) (boxLength / mFocusedTaskRatio);
+            } else {
+                taskWidth = (int) (boxLength * mFocusedTaskRatio);
+                taskHeight = boxLength;
+            }
+        }
+        return new Point(taskWidth, taskHeight);
+    }
+
     /** Gets the last computed task size */
     public Rect getLastComputedTaskSize() {
         return mLastComputedTaskSize;
     }
 
+    public Rect getLastComputedGridTaskSize() {
+        return mLastComputedGridTaskSize;
+    }
+
     /** Gets the task size for modal state. */
     public void getModalTaskSize(Rect outRect) {
         mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
@@ -1235,6 +1305,15 @@
 
             // After scrolling, update the visible task's data
             loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
+
+            // After scrolling, update ActionsView's visibility.
+            TaskView focusedTaskView = getFocusedTaskView();
+            if (focusedTaskView != null) {
+                float scrollDiff = Math.abs(getScrollForPage(indexOfChild(focusedTaskView))
+                        - mOrientationHandler.getPrimaryScroll(this));
+                float delta = (mGridSideMargin - scrollDiff) / (float) mGridSideMargin;
+                mActionsView.getScrollAlpha().setValue(Utilities.boundToRange(delta, 0, 1));
+            }
         }
 
         // Update the high res thumbnail loader state
@@ -1399,6 +1478,7 @@
         setCurrentTask(-1);
         mIgnoreResetTaskId = -1;
         mTaskListChangeId = -1;
+        mFocusedTaskId = -1;
 
         mRecentsAnimationController = null;
         mLiveTileParams.setTargetSet(null);
@@ -1425,6 +1505,17 @@
         return getTaskIndexForId(mRunningTaskId);
     }
 
+    public @Nullable TaskView getFocusedTaskView() {
+        return getTaskView(mFocusedTaskId);
+    }
+
+    /**
+     * Returns the width to height ratio of the focused {@link TaskView}.
+     */
+    public float getFocusedTaskRatio() {
+        return mFocusedTaskRatio;
+    }
+
     /**
      * Get the index of the task view whose id matches {@param taskId}.
      * @return -1 if there is no task view for the task id, else the index of the task view.
@@ -1516,6 +1607,11 @@
      */
     public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
         mCurrentGestureEndTarget = endTarget;
+        if (showAsGrid()) {
+            mFocusedTaskId = mRunningTaskId;
+            mFocusedTaskRatio =
+                    mLastComputedTaskSize.width() / (float) mLastComputedTaskSize.height();
+        }
     }
 
     /**
@@ -1536,8 +1632,7 @@
         setRunningTaskHidden(false);
         animateUpRunningTaskIconScale();
 
-        // TODO: This should be tied to whether there is a focus app on overview.
-        if (!showAsGrid()) {
+        if (!showAsGrid() || getFocusedTaskView() != null) {
             animateActionsViewIn();
         }
 
@@ -1657,6 +1752,13 @@
         anim.start();
     }
 
+    private void animateActionsViewOut() {
+        ObjectAnimator anim = ObjectAnimator.ofFloat(
+                mActionsView.getVisibilityAlpha(), MultiValueAlpha.VALUE, 1, 0);
+        anim.setDuration(TaskView.SCALE_ICON_DURATION);
+        anim.start();
+    }
+
     public void animateUpRunningTaskIconScale() {
         animateUpRunningTaskIconScale(0);
     }
@@ -1682,8 +1784,12 @@
             return;
         }
 
-        final int boxLength = Math.max(mTaskWidth, mTaskHeight);
+        final int boxLength = Math.max(mLastComputedGridTaskSize.width(),
+                mLastComputedGridTaskSize.height());
         int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+        float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
+        float taskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
+
         int topRowWidth = 0;
         int bottomRowWidth = 0;
         float topAccumulatedTranslationX = 0;
@@ -1706,15 +1812,23 @@
             }
 
             // Evenly distribute tasks between rows unless rearranging due to task dismissal, in
-            // which case keep tasks in their respective rows.
-            if ((!isTaskDismissal && topRowWidth <= bottomRowWidth) || (isTaskDismissal && mTopIdSet
-                    .contains(taskView.getTask().key.id))) {
+            // which case keep tasks in their respective rows. For the running task, don't join
+            // the grid.
+            if (taskView.isRunningTask()) {
+                topRowWidth += taskView.getLayoutParams().width + mPageSpacing;
+                bottomRowWidth += taskView.getLayoutParams().width + mPageSpacing;
+
+                // Center view vertically in case it's from different orientation.
+                taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin
+                        - taskView.getLayoutParams().height) / 2f);
+            } else if ((!isTaskDismissal && topRowWidth <= bottomRowWidth) || (isTaskDismissal
+                        && mTopIdSet.contains(taskView.getTask().key.id))) {
                 gridTranslations[i] += topAccumulatedTranslationX;
                 topRowWidth += taskView.getLayoutParams().width + mPageSpacing;
                 topSet.add(i);
                 mTopIdSet.add(taskView.getTask().key.id);
 
-                taskView.setGridTranslationY(0);
+                taskView.setGridTranslationY(taskGridVerticalDiff);
 
                 // Move horizontally into empty space.
                 float widthOffset = 0;
@@ -1731,8 +1845,7 @@
                 bottomSet.add(i);
 
                 // Move into bottom row.
-                float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
-                taskView.setGridTranslationY(heightOffset);
+                taskView.setGridTranslationY(heightOffset + taskGridVerticalDiff);
 
                 // Move horizontally into empty space.
                 float widthOffset = 0;
@@ -1746,20 +1859,12 @@
             }
         }
 
-        // If the first non-home task does not take full width of task Rect, shift all tasks
-        // accordingly without affecting scrolls.
-        int firstTaskWidth = getTaskViewAt(firstNonHomeTaskIndex).getLayoutParams().width;
-        float firstNonHomeTaskOffset = firstTaskWidth == ViewGroup.LayoutParams.MATCH_PARENT ? 0
-                : mTaskWidth - firstTaskWidth;
-        float offsetTranslation = mIsRtl ? firstNonHomeTaskOffset : -firstNonHomeTaskOffset;
-
         // We need to maintain first non-home task's grid translation at 0, now shift translation
         // of all the TaskViews to achieve that.
         for (int i = firstNonHomeTaskIndex; i < taskCount; i++) {
             TaskView taskView = getTaskViewAt(i);
             taskView.setGridTranslationX(
                     gridTranslations[i] - gridTranslations[firstNonHomeTaskIndex]);
-            taskView.setGridOffsetTranslationX(offsetTranslation);
         }
 
         // Use the accumulated translation of the longer row.
@@ -1798,12 +1903,9 @@
 
         mClearAllButton.setGridTranslationPrimary(
                 clearAllTotalTranslationX - gridTranslations[firstNonHomeTaskIndex]);
-        mClearAllButton.setGridTranslationSecondary(
-                boxLength - mTaskHeight / 2f + mRowSpacing / 2f);
         mClearAllButton.setGridScrollOffset(
                 mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left
                         : mLastComputedTaskSize.right - mLastComputedGridSize.right);
-        mClearAllButton.setOffsetTranslationPrimary(offsetTranslation);
 
         setGridProgress(mGridProgress);
     }
@@ -2077,24 +2179,25 @@
                         snapToPageImmediately(pageToSnapTo);
                         // Grid got messed up, reapply.
                         updateGridProperties(true);
+                        if (showAsGrid() && getFocusedTaskView() == null) {
+                            animateActionsViewOut();
+                        }
                     }
                     // Update the layout synchronously so that the position of next view is
                     // immediately available.
                     onLayout(false /*  changed */, getLeft(), getTop(), getRight(), getBottom());
                 }
                 resetTaskVisuals();
-                if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
-                    // We want to keep the tasks translations in this temporary state
-                    // after resetting the rest above
-                    setTaskViewsResistanceTranslation(mTaskViewsSecondaryTranslation);
-                    setTaskViewsPrimaryTranslation(mTaskViewsPrimaryTranslation);
-                }
+                onDismissAnimationEnds();
                 mPendingAnimation = null;
             }
         });
         return anim;
     }
 
+    protected void onDismissAnimationEnds() {
+    }
+
     public PendingAnimation createAllTasksDismissAnimation(long duration) {
         if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) {
             throw new IllegalStateException("Another pending animation is still running");
@@ -2262,13 +2365,6 @@
         if (mOrientationState.setRecentsRotation(rotation)) {
             updateOrientationHandler();
         }
-
-        // 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) {
@@ -2480,7 +2576,7 @@
         return distanceToOffscreen * offsetProgress;
     }
 
-    private void setTaskViewsResistanceTranslation(float translation) {
+    protected void setTaskViewsResistanceTranslation(float translation) {
         mTaskViewsSecondaryTranslation = translation;
         for (int i = 0; i < getTaskViewCount(); i++) {
             TaskView task = getTaskViewAt(i);
@@ -2489,7 +2585,7 @@
         mLiveTileTaskViewSimulator.recentsViewSecondaryTranslation.value = translation;
     }
 
-    private void setTaskViewsPrimaryTranslation(float translation) {
+    protected void setTaskViewsPrimaryTranslation(float translation) {
         mTaskViewsPrimaryTranslation = translation;
         for (int i = 0; i < getTaskViewCount(); i++) {
             TaskView task = getTaskViewAt(i);
@@ -2515,12 +2611,19 @@
         }
     }
 
+    /**
+     * True if the background scrim of the recents view is light colored and the foreground elements
+     * should use dark colors.
+     */
+    public boolean hasLightBackground() {
+        return mHasLightBackground;
+    }
+
     public void initiateSplitSelect(TaskView taskView, SplitPositionOption splitPositionOption) {
         mSplitHiddenTaskView = taskView;
         mSplitPlaceholderView.getSplitController().setInitialTaskSelect(taskView,
                 splitPositionOption);
         mSplitHiddenTaskViewIndex = indexOfChild(taskView);
-        mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
     }
 
     public PendingAnimation createSplitSelectInitAnimation() {
@@ -2759,10 +2862,13 @@
         progressAnim.addUpdateListener(animator -> {
             // Once we pass a certain threshold, update the sysui flags to match the target
             // tasks' flags
-            mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW,
-                    animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD
-                            ? targetSysUiFlags
-                            : 0);
+            if (animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD) {
+                mActivity.getSystemUiController().updateUiState(
+                        UI_STATE_OVERVIEW, targetSysUiFlags);
+            } else {
+                mActivity.getSystemUiController().updateUiState(
+                        UI_STATE_OVERVIEW, hasLightBackground());
+            }
 
             // Passing the threshold from taskview to fullscreen app will vibrate
             final boolean passed = animator.getAnimatedFraction() >=
@@ -2948,10 +3054,7 @@
      * Returns page scroll of the left most child.
      */
     public int getLeftMostChildScroll() {
-        if (mIsRtl) {
-            return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
-        }
-        return getScrollForPage(mTaskViewStartIndex);
+        return getScrollForPage(mIsRtl ? indexOfChild(mClearAllButton) : mTaskViewStartIndex);
     }
 
     @Override
@@ -2962,10 +3065,7 @@
                 // so use the rightmost task as the min scroll.
                 return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
             }
-            if (mIsRtl) {
-                return getScrollForPage(mTaskViewStartIndex);
-            }
-            return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
+            return getScrollForPage(mIsRtl ? mTaskViewStartIndex : indexOfChild(mClearAllButton));
         }
         return super.computeMaxScroll();
     }
@@ -2984,7 +3084,8 @@
                 scrollDiff = ((TaskView) child).getScrollAdjustment(mOverviewFullscreenEnabled,
                         showAsGrid());
             } else if (child instanceof ClearAllButton) {
-                scrollDiff = ((ClearAllButton) child).getScrollAdjustment(showAsGrid());
+                scrollDiff = ((ClearAllButton) child).getScrollAdjustment(
+                        mOverviewFullscreenEnabled, showAsGrid());
             }
 
             if (scrollDiff != 0) {
@@ -3003,7 +3104,8 @@
             childOffset += ((TaskView) child).getOffsetAdjustment(mOverviewFullscreenEnabled,
                     showAsGrid());
         } else if (child instanceof ClearAllButton) {
-            childOffset += ((ClearAllButton) child).getOffsetAdjustment(showAsGrid());
+            childOffset += ((ClearAllButton) child).getOffsetAdjustment(mOverviewFullscreenEnabled,
+                    showAsGrid());
         }
         return childOffset;
     }
@@ -3179,6 +3281,7 @@
         boolean inPlaceLandscape = !mOrientationState.canRecentsActivityRotate()
                 && mOrientationState.getTouchRotation() != ROTATION_0;
         mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION, modalness < 1 && inPlaceLandscape);
+        mActionsView.setTaskModalness(modalness);
     }
 
     @Nullable
@@ -3207,12 +3310,27 @@
         return mSizeStrategy;
     }
 
+    /**
+     * Set all the task views to color tint scrim mode, dimming or tinting them all. Allows the
+     * tasks to be dimmed while other elements in the recents view are left alone.
+     */
+    public void showForegroundScrim(boolean show) {
+        for (int i = 0; i < getTaskViewCount(); i++) {
+            getTaskViewAt(i).showColorTint(show);
+        }
+    }
+
     private boolean showAsGrid() {
         return mOverviewGridEnabled || (mCurrentGestureEndTarget != null
                 && mSizeStrategy.stateFromGestureEndTarget(
                 mCurrentGestureEndTarget).displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
     }
 
+    public boolean shouldShowOverviewActionsForState(STATE_TYPE state) {
+        return !state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())
+                || getFocusedTaskView() != null;
+    }
+
     /**
      * Used to register callbacks for when our empty message state changes.
      *
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
deleted file mode 100644
index db04fc0..0000000
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * 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.quickstep.views;
-
-import static com.android.launcher3.LauncherState.OVERVIEW;
-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;
-import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
-import static com.android.launcher3.util.SystemUiController.UI_STATE_SCRIM_VIEW;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Path.Direction;
-import android.graphics.Path.Op;
-import android.util.AttributeSet;
-import android.view.animation.Interpolator;
-
-import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.uioverrides.states.OverviewState;
-import com.android.launcher3.util.Themes;
-import com.android.launcher3.views.ScrimView;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
-import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
-
-/**
- * Scrim used for all-apps and shelf in Overview
- * In transposed layout, it behaves as a simple color scrim.
- * In portrait layout, it draws a rounded rect such that
- *    From normal state to overview state, the shelf just fades in and does not move
- *    From overview state to all-apps state the shelf moves up and fades in to cover the screen
- */
-public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
-        implements NavigationModeChangeListener {
-
-    // If the progress is more than this, shelf follows the finger, otherwise it moves faster to
-    // cover the whole screen
-    private static final float SCRIM_CATCHUP_THRESHOLD = 0.2f;
-
-    // Temporarily needed until android.R.attr.bottomDialogCornerRadius becomes public
-    private static final float BOTTOM_CORNER_RADIUS_RATIO = 2f;
-
-    // In transposed layout, we simply draw a flat color.
-    private boolean mDrawingFlatColor;
-
-    // For shelf mode
-    private final int mEndAlpha;
-    private final float mRadius;
-    private final int mMaxScrimAlpha;
-    private final Paint mPaint;
-
-    // Mid point where the alpha changes
-    private int mMidAlpha;
-    private float mMidProgress;
-
-    private Interpolator mBeforeMidProgressColorInterpolator = ACCEL;
-    private Interpolator mAfterMidProgressColorInterpolator = ACCEL;
-
-    private float mShiftRange;
-
-    private float mTopOffset;
-    private float mShelfTop;
-    private float mShelfTopAtThreshold;
-
-    private int mShelfColor;
-    private int mRemainingScreenColor;
-
-    private final Path mTempPath = new Path();
-    private final Path mRemainingScreenPath = new Path();
-    private boolean mRemainingScreenPathValid = false;
-
-    private Mode mSysUINavigationMode;
-
-    public ShelfScrimView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mMaxScrimAlpha = Math.round(OVERVIEW.getOverviewScrimAlpha(mLauncher) * 255);
-
-        mEndAlpha = Color.alpha(mEndScrim);
-        mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context);
-        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
-        // Just assume the easiest UI for now, until we have the proper layout information.
-        mDrawingFlatColor = true;
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        mRemainingScreenPathValid = false;
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(getContext())
-                .addModeChangeListener(this));
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        SysUINavigationMode.INSTANCE.get(getContext()).removeModeChangeListener(this);
-    }
-
-    @Override
-    public void onNavigationModeChanged(Mode newMode) {
-        mSysUINavigationMode = newMode;
-        // Note that these interpolators are inverted because progress goes 1 to 0.
-        if (mSysUINavigationMode == Mode.NO_BUTTON) {
-            // Show the shelf more quickly before reaching overview progress.
-            mBeforeMidProgressColorInterpolator = ACCEL_2;
-            mAfterMidProgressColorInterpolator = ACCEL;
-        } else {
-            mBeforeMidProgressColorInterpolator = ACCEL;
-            mAfterMidProgressColorInterpolator = Interpolators.clampToProgress(ACCEL, 0.5f, 1f);
-        }
-    }
-
-    @Override
-    public void reInitUi() {
-        DeviceProfile dp = mLauncher.getDeviceProfile();
-        mDrawingFlatColor = dp.isVerticalBarLayout();
-
-        if (!mDrawingFlatColor) {
-            mRemainingScreenPathValid = false;
-            mShiftRange = mLauncher.getAllAppsController().getShiftRange();
-
-            // Fade in all apps background quickly to distinguish from swiping from nav bar.
-            mMidAlpha = Themes.getAttrInteger(getContext(), R.attr.allAppsInterimScrimAlpha);
-            mMidProgress = 1 - (OverviewState.getDefaultSwipeHeight(mLauncher)
-                    / mLauncher.getAllAppsController().getShiftRange());
-
-            mTopOffset = dp.getInsets().top;
-            mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset;
-        }
-        updateColors();
-        updateSysUiColors();
-        invalidate();
-    }
-
-    @Override
-    public void updateColors() {
-        super.updateColors();
-        if (mDrawingFlatColor) {
-            return;
-        }
-
-        if (mProgress >= SCRIM_CATCHUP_THRESHOLD) {
-            mShelfTop = mShiftRange * mProgress + mTopOffset;
-        } else {
-            mShelfTop = Utilities.mapRange(mProgress / SCRIM_CATCHUP_THRESHOLD, -mRadius,
-                    mShelfTopAtThreshold);
-        }
-
-        if (mProgress >= 1) {
-            mRemainingScreenColor = 0;
-            mShelfColor = 0;
-        } else if (mProgress >= mMidProgress) {
-            mRemainingScreenColor = 0;
-
-            int alpha = Math.round(Utilities.mapToRange(
-                    mProgress, mMidProgress, 1, mMidAlpha, 0, mBeforeMidProgressColorInterpolator));
-            mShelfColor = setColorAlphaBound(mEndScrim, alpha);
-        } else {
-            // Note that these ranges and interpolators are inverted because progress goes 1 to 0.
-            int alpha = Math.round(
-                    Utilities.mapToRange(mProgress, (float) 0, mMidProgress, (float) mEndAlpha,
-                            (float) mMidAlpha, mAfterMidProgressColorInterpolator));
-            mShelfColor = setColorAlphaBound(mEndScrim, alpha);
-
-            int remainingScrimAlpha = Math.round(
-                    Utilities.mapToRange(mProgress, (float) 0, mMidProgress, mMaxScrimAlpha,
-                            (float) 0, LINEAR));
-            mRemainingScreenColor = setColorAlphaBound(mScrimColor, remainingScrimAlpha);
-        }
-    }
-
-    @Override
-    protected void updateSysUiColors() {
-        if (mDrawingFlatColor) {
-            super.updateSysUiColors();
-        } else {
-            // Use a light system UI (dark icons) if all apps is behind at least half of the
-            // status bar.
-            boolean forceChange = mShelfTop <= mLauncher.getDeviceProfile().getInsets().top / 2f;
-            if (forceChange) {
-                mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark);
-            } else {
-                mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, 0);
-            }
-        }
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mDrawingFlatColor) {
-            if (mCurrentFlatColor != 0) {
-                canvas.drawColor(mCurrentFlatColor);
-            }
-            return;
-        }
-
-        if (Color.alpha(mShelfColor) == 0) {
-            return;
-        } else if (mProgress <= 0) {
-            canvas.drawColor(mShelfColor);
-            return;
-        }
-
-        int height = getHeight();
-        int width = getWidth();
-        // Draw the scrim over the remaining screen if needed.
-        if (mRemainingScreenColor != 0) {
-            if (!mRemainingScreenPathValid) {
-                mTempPath.reset();
-                // Using a arbitrary '+10' in the bottom to avoid any left-overs at the
-                // corners due to rounding issues.
-                mTempPath.addRoundRect(0, height - mRadius, width, height + mRadius + 10,
-                        mRadius, mRadius, Direction.CW);
-                mRemainingScreenPath.reset();
-                mRemainingScreenPath.addRect(0, 0, width, height, Direction.CW);
-                mRemainingScreenPath.op(mTempPath, Op.DIFFERENCE);
-            }
-
-            float offset = height - mRadius - mShelfTop;
-            canvas.translate(0, -offset);
-            mPaint.setColor(mRemainingScreenColor);
-            canvas.drawPath(mRemainingScreenPath, mPaint);
-            canvas.translate(0, offset);
-        }
-
-        mPaint.setColor(mShelfColor);
-        canvas.drawRoundRect(0, mShelfTop, width, height + mRadius, mRadius, mRadius, mPaint);
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index a46daf3..0b84bc9 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -249,9 +249,11 @@
         final Animator revealAnimator = createOpenCloseOutlineProvider()
                 .createRevealAnimator(this, closing);
         revealAnimator.setInterpolator(Interpolators.DEACCEL);
-        mOpenCloseAnimator.play(revealAnimator);
-        mOpenCloseAnimator.play(ObjectAnimator.ofFloat(mTaskView.getThumbnail(), DIM_ALPHA,
-                closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA));
+        mOpenCloseAnimator.playTogether(revealAnimator,
+                ObjectAnimator.ofFloat(
+                        mTaskView.getThumbnail(), DIM_ALPHA,
+                        closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA),
+                ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
         mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationStart(Animator animation) {
@@ -265,7 +267,6 @@
                 }
             }
         });
-        mOpenCloseAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
         mOpenCloseAnimator.setDuration(closing ? REVEAL_CLOSE_DURATION: REVEAL_OPEN_DURATION);
         mOpenCloseAnimator.start();
     }
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index af62582..685f725 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -28,8 +28,6 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Paint;
@@ -46,10 +44,10 @@
 import android.view.View;
 
 import androidx.annotation.RequiresApi;
+import androidx.core.graphics.ColorUtils;
 
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
@@ -67,10 +65,6 @@
  * A task in the Recents view.
  */
 public class TaskThumbnailView extends View implements PluginListener<OverviewScreenshotActions> {
-
-    private static final ColorMatrix COLOR_MATRIX = new ColorMatrix();
-    private static final ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix();
-
     private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
             new MainThreadInitializedObject<>(FullscreenDrawParams::new);
 
@@ -89,11 +83,11 @@
 
     private final BaseActivity mActivity;
     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);
     private final Paint mClearPaint = new Paint();
     private final Paint mDimmingPaintAfterClearing = new Paint();
+    private final int mDimColor;
 
     // Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
     private final Rect mPreviewRect = new Rect();
@@ -104,9 +98,8 @@
     private ThumbnailData mThumbnailData;
     protected BitmapShader mBitmapShader;
 
-    private float mDimAlpha = 1f;
-    private float mDimAlphaMultiplier = 1f;
-    private float mSaturation = 1f;
+    /** How much this thumbnail is dimmed, 0 not dimmed at all, 1 totally dimmed. */
+    private float mDimAlpha = 0f;
 
     private boolean mOverlayEnabled;
     private OverviewScreenshotActions mOverviewScreenshotActionsPlugin;
@@ -124,11 +117,12 @@
         mPaint.setFilterBitmap(true);
         mBackgroundPaint.setColor(Color.WHITE);
         mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
-        mDimmingPaintAfterClearing.setColor(Color.BLACK);
         mActivity = BaseActivity.fromContext(context);
-        mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
         // Initialize with placeholder value. It is overridden later by TaskView
         mFullscreenParams = TEMP_PARAMS.get(context);
+
+        mDimColor = Themes.getColorBackgroundFloating(context);
+        mDimmingPaintAfterClearing.setColor(mDimColor);
     }
 
     /**
@@ -186,15 +180,12 @@
         updateThumbnailPaintFilter();
     }
 
-    public void setDimAlphaMultipler(float dimAlphaMultipler) {
-        mDimAlphaMultiplier = dimAlphaMultipler;
-        setDimAlpha(mDimAlpha);
-    }
-
     /**
      * Sets the alpha of the dim layer on top of this view.
      * <p>
-     * If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be black.
+     * If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be the
+     * extracted background color.
+     *
      */
     public void setDimAlpha(float dimAlpha) {
         mDimAlpha = dimAlpha;
@@ -359,15 +350,15 @@
     }
 
     private void updateThumbnailPaintFilter() {
-        int mul = (int) ((1 - mDimAlpha * mDimAlphaMultiplier) * 255);
-        ColorFilter filter = getColorFilter(mul, mIsDarkTextTheme, mSaturation);
+        ColorFilter filter = getColorFilter(mDimAlpha);
         mBackgroundPaint.setColorFilter(filter);
-        mDimmingPaintAfterClearing.setAlpha(255 - mul);
+        int alpha = (int) (mDimAlpha * 255);
+        mDimmingPaintAfterClearing.setAlpha(alpha);
         if (mBitmapShader != null) {
             mPaint.setColorFilter(filter);
         } else {
             mPaint.setColorFilter(null);
-            mPaint.setColor(Color.argb(255, mul, mul, mul));
+            mPaint.setColor(ColorUtils.blendARGB(Color.BLACK, mDimColor, alpha));
         }
         invalidate();
     }
@@ -401,35 +392,8 @@
         updateThumbnailMatrix();
     }
 
-    /**
-     * @param intensity multiplier for color values. 0 - make black (white if shouldLighten), 255 -
-     *                  leave unchanged.
-     */
-    private static ColorFilter getColorFilter(int intensity, boolean shouldLighten,
-            float saturation) {
-        intensity = Utilities.boundToRange(intensity, 0, 255);
-
-        if (intensity == 255 && saturation == 1) {
-            return null;
-        }
-
-        final float intensityScale = intensity / 255f;
-        COLOR_MATRIX.setScale(intensityScale, intensityScale, intensityScale, 1);
-
-        if (saturation != 1) {
-            SATURATION_COLOR_MATRIX.setSaturation(saturation);
-            COLOR_MATRIX.postConcat(SATURATION_COLOR_MATRIX);
-        }
-
-        if (shouldLighten) {
-            final float[] colorArray = COLOR_MATRIX.getArray();
-            final int colorAdd = 255 - intensity;
-            colorArray[4] = colorAdd;
-            colorArray[9] = colorAdd;
-            colorArray[14] = colorAdd;
-        }
-
-        return new ColorMatrixColorFilter(COLOR_MATRIX);
+    private ColorFilter getColorFilter(float dimAmount) {
+        return Utilities.makeColorTintingColorFilter(mDimColor, dimAmount);
     }
 
     public Bitmap getThumbnail() {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index d497a96..e78406f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -89,6 +89,7 @@
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TransformingTouchDelegate;
 import com.android.launcher3.util.ViewPool.Reusable;
 import com.android.quickstep.RecentsModel;
@@ -134,10 +135,7 @@
     @IntDef({FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL})
     public @interface TaskDataChanges {}
 
-    /**
-     * The alpha of a black scrim on a page in the carousel as it leaves the screen.
-     * In the resting position of the carousel, the adjacent pages have about half this scrim.
-     */
+    /** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
     public static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
 
     /**
@@ -254,6 +252,19 @@
                 }
             };
 
+    private static final FloatProperty<TaskView> COLOR_TINT =
+            new FloatProperty<TaskView>("colorTint") {
+                @Override
+                public void setValue(TaskView taskView, float v) {
+                    taskView.setColorTint(v);
+                }
+
+                @Override
+                public Float get(TaskView taskView) {
+                    return taskView.getColorTint();
+                }
+            };
+
     private final OnAttachStateChangeListener mTaskMenuStateListener =
             new OnAttachStateChangeListener() {
                 @Override
@@ -295,8 +306,6 @@
     // The following grid translations scales with mGridProgress.
     private float mGridTranslationX;
     private float mGridTranslationY;
-    // Offset translation does not affect scroll calculation.
-    private float mGridOffsetTranslationX;
 
     private ObjectAnimator mIconAndDimAnimator;
     private float mIconScaleAnimStartProgress = 0;
@@ -316,6 +325,11 @@
     private final float[] mIconCenterCoords = new float[2];
     private final float[] mChipCenterCoords = new float[2];
 
+    // Colored tint for the task view and all its supplementary views (like the task icon and well
+    // being banner.
+    private final int mTintingColor;
+    private float mTintAmount;
+
     private boolean mIsClickableAsLiveTile = true;
 
     public TaskView(Context context) {
@@ -377,6 +391,8 @@
         mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams,
                 mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx);
         setOutlineProvider(mOutlineProvider);
+
+        mTintingColor = Themes.getColorBackgroundFloating(context);
     }
 
     /**
@@ -724,7 +740,6 @@
             progress = 1 - progress;
         }
         mFocusTransitionProgress = progress;
-        mSnapshotView.setDimAlphaMultipler(0);
         float iconScalePercentage = (float) SCALE_ICON_DURATION / DIM_ANIM_DURATION;
         float lowerClamp = invert ? 1f - iconScalePercentage : 0;
         float upperClamp = invert ? 1 : iconScalePercentage;
@@ -783,6 +798,7 @@
         setTranslationZ(0);
         setAlpha(mStableAlpha);
         setIconScaleAndDim(1);
+        setColorTint(0);
     }
 
     public void setStableAlpha(float parentAlpha) {
@@ -792,8 +808,7 @@
 
     @Override
     public void onRecycle() {
-        mFullscreenTranslationX = mGridTranslationX =
-                mGridTranslationY = mGridOffsetTranslationX = mBoxTranslationY = 0f;
+        mFullscreenTranslationX = mGridTranslationX = mGridTranslationY = mBoxTranslationY = 0f;
         resetViewTransforms();
         // Clear any references to the thumbnail (it will be re-read either from the cache or the
         // system on next bind)
@@ -874,7 +889,7 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
-            setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? (right - left) : 0);
+            setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
             setPivotY(mSnapshotView.getTop());
         } else {
             setPivotX((right - left) * 0.5f);
@@ -979,11 +994,6 @@
         return mGridTranslationY;
     }
 
-    public void setGridOffsetTranslationX(float gridOffsetTranslationX) {
-        mGridOffsetTranslationX = gridOffsetTranslationX;
-        applyTranslationX();
-    }
-
     public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
         float scrollAdjustment = 0;
         if (fullscreenEnabled) {
@@ -995,12 +1005,8 @@
         return scrollAdjustment;
     }
 
-    public float getOffsetAdjustment(boolean fullscreenEnabled,boolean gridEnabled) {
-        float offsetAdjustment = getScrollAdjustment(fullscreenEnabled, gridEnabled);
-        if (gridEnabled) {
-            offsetAdjustment += mGridOffsetTranslationX;
-        }
-        return offsetAdjustment;
+    public float getOffsetAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
+        return getScrollAdjustment(fullscreenEnabled, gridEnabled);
     }
 
     public float getSizeAdjustment(boolean fullscreenEnabled) {
@@ -1019,7 +1025,7 @@
     private void applyTranslationX() {
         setTranslationX(mDismissTranslationX + mTaskOffsetTranslationX + mTaskResistanceTranslationX
                 + getFullscreenTrans(mFullscreenTranslationX)
-                + getGridTrans(mGridTranslationX + mGridOffsetTranslationX));
+                + getGridTrans(mGridTranslationX));
     }
 
     private void applyTranslationY() {
@@ -1225,62 +1231,77 @@
      */
     void updateTaskSize() {
         ViewGroup.LayoutParams params = getLayoutParams();
+        float fullscreenScale;
+        float boxTranslationY;
+        int expectedWidth;
+        int expectedHeight;
         if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
             final int thumbnailPadding =
                     mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+            final Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
+            final int taskWidth = lastComputedTaskSize.width();
+            final int taskHeight = lastComputedTaskSize.height();
 
-            Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
-            int taskWidth = lastComputedTaskSize.width();
-            int taskHeight = lastComputedTaskSize.height();
-
-            int expectedWidth;
-            int expectedHeight;
-            float thumbnailRatio = mTask != null ? mTask.getVisibleThumbnailRatio(
-                    TaskView.CLIP_STATUS_AND_NAV_BARS) : 0f;
-            if (isRunningTask() || thumbnailRatio == 0f) {
-                expectedWidth = taskWidth;
-                expectedHeight = taskHeight + thumbnailPadding;
+            int boxWidth;
+            int boxHeight;
+            float thumbnailRatio;
+            boolean isFocusedTask = isFocusedTask();
+            if (isFocusedTask || isRunningTask()) {
+                // Task will be focused and should use focused task size. Use runningTaskRatio
+                // that is associated with the original orientation of the focused task if possible.
+                boxWidth = taskWidth;
+                boxHeight = taskHeight;
+                thumbnailRatio = isFocusedTask ? getRecentsView().getFocusedTaskRatio() : 0;
             } else {
-                int boxLength = Math.max(taskWidth, taskHeight);
-                if (thumbnailRatio > 1) {
-                    expectedWidth = boxLength;
-                    expectedHeight = (int) (boxLength / thumbnailRatio) + thumbnailPadding;
-                } else {
-                    expectedWidth = (int) (boxLength * thumbnailRatio);
-                    expectedHeight = boxLength + thumbnailPadding;
-                }
+                // Otherwise task is in grid, and should use lastComputedGridTaskSize.
+                Rect lastComputedGridTaskSize = getRecentsView().getLastComputedGridTaskSize();
+                boxWidth = lastComputedGridTaskSize.width();
+                boxHeight = lastComputedGridTaskSize.height();
+                thumbnailRatio = mTask != null ? mTask.getVisibleThumbnailRatio(
+                        TaskView.CLIP_STATUS_AND_NAV_BARS) : 0f;
+            }
+            int boxLength = Math.max(boxWidth, boxHeight);
+
+            // Bound width/height to the box size.
+            if (thumbnailRatio == 0f) {
+                expectedWidth = boxWidth;
+                expectedHeight = boxHeight + thumbnailPadding;
+            } else if (thumbnailRatio > 1) {
+                expectedWidth = boxLength;
+                expectedHeight = (int) (boxLength / thumbnailRatio) + thumbnailPadding;
+            } else {
+                expectedWidth = (int) (boxLength * thumbnailRatio);
+                expectedHeight = boxLength + thumbnailPadding;
             }
 
-            float heightDiff = (expectedHeight - thumbnailPadding - taskHeight) / 2.0f;
-            setBoxTranslationY(heightDiff);
+            // Scale to to fit task Rect.
+            fullscreenScale = taskWidth / (float) boxWidth;
 
-            float fullscreenScale = 1f;
-            if (expectedWidth > taskWidth) {
-                // In full screen, expectedWidth should not be larger than taskWidth.
-                fullscreenScale = taskWidth / (float) expectedWidth;
-            } else if (expectedHeight - thumbnailPadding > taskHeight) {
-                // In full screen, expectedHeight should not be larger than taskHeight.
-                fullscreenScale = taskHeight / (float) (expectedHeight - thumbnailPadding);
+            // In full screen, scale back TaskView to original size.
+            if (expectedWidth > boxWidth) {
+                fullscreenScale *= boxWidth / (float) expectedWidth;
+            } else if (expectedHeight - thumbnailPadding > boxHeight) {
+                fullscreenScale *= boxHeight / (float) (expectedHeight - thumbnailPadding);
             }
-            setFullscreenScale(fullscreenScale);
 
-            if (params.width != expectedWidth || params.height != expectedHeight) {
-                params.width = expectedWidth;
-                params.height = expectedHeight;
-                setLayoutParams(params);
-            }
+            // Align to top of task Rect.
+            boxTranslationY = (expectedHeight - thumbnailPadding - taskHeight) / 2.0f;
         } else {
-            setBoxTranslationY(0);
-            setFullscreenScale(1);
-            if (params.width != ViewGroup.LayoutParams.MATCH_PARENT) {
-                params.width = ViewGroup.LayoutParams.MATCH_PARENT;
-                params.height = ViewGroup.LayoutParams.MATCH_PARENT;
-                setLayoutParams(params);
-            }
+            fullscreenScale = 1f;
+            boxTranslationY = 0f;
+            expectedWidth = ViewGroup.LayoutParams.MATCH_PARENT;
+            expectedHeight = ViewGroup.LayoutParams.MATCH_PARENT;
+        }
+
+        setFullscreenScale(fullscreenScale);
+        setBoxTranslationY(boxTranslationY);
+        if (params.width != expectedWidth || params.height != expectedHeight) {
+            params.width = expectedWidth;
+            params.height = expectedHeight;
+            setLayoutParams(params);
         }
     }
 
-
     private float getFullscreenTrans(float endTranslation) {
         float progress = ACCEL_DEACCEL.getInterpolation(mFullscreenProgress);
         return Utilities.mapRange(progress, 0, endTranslation);
@@ -1293,6 +1314,13 @@
         return this == getRecentsView().getRunningTaskView();
     }
 
+    public boolean isFocusedTask() {
+        if (getRecentsView() == null) {
+            return false;
+        }
+        return this == getRecentsView().getFocusedTaskView();
+    }
+
     public void setShowScreenshot(boolean showScreenshot) {
         mShowScreenshot = showScreenshot;
     }
@@ -1314,6 +1342,26 @@
         rv.initiateSplitSelect(this, splitPositionOption);
     }
 
+    private void setColorTint(float amount) {
+        mSnapshotView.setDimAlpha(amount);
+        mIconView.setIconColorTint(mTintingColor, amount);
+        mDigitalWellBeingToast.setBannerColorTint(mTintingColor, amount);
+    }
+
+    private float getColorTint() {
+        return mTintAmount;
+    }
+
+    /**
+     * Show the task view with a color tint (animates value).
+     */
+    public void showColorTint(boolean enable) {
+        ObjectAnimator tintAnimator = ObjectAnimator.ofFloat(
+                this, COLOR_TINT, enable ? MAX_PAGE_SCRIM_ALPHA : 0);
+        tintAnimator.setAutoCancel(true);
+        tintAnimator.start();
+    }
+
     /**
      * We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
      */
diff --git a/res/color/overview_button.xml b/res/color/overview_button.xml
index 6ac36bf..aa48b78 100644
--- a/res/color/overview_button.xml
+++ b/res/color/overview_button.xml
@@ -2,10 +2,10 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:alpha="1"
-        android:color="?attr/workspaceTextColor"
+        android:color="?android:attr/textColorPrimary"
         android:state_enabled="true" />
     <item
         android:alpha="?android:disabledAlpha"
-        android:color="?attr/workspaceTextColor"
+        android:color="?android:attr/textColorPrimary"
         android:state_enabled="false" />
 </selector>
\ No newline at end of file
diff --git a/res/layout/overview_actions_container.xml b/res/layout/overview_actions_container.xml
index 5946bf6..f152c7c 100644
--- a/res/layout/overview_actions_container.xml
+++ b/res/layout/overview_actions_container.xml
@@ -14,6 +14,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<!-- NOTE! don't add dimensions for margins / gravity to root view in this file, they need to be
+     loaded at runtime. -->
 <Space
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="0dp"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 1fccdf3..51dddab 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -84,6 +84,7 @@
     <dimen name="fastscroll_end_margin">-26dp</dimen>
 
     <!-- All Apps -->
+    <dimen name="all_apps_open_vertical_translate">96dp</dimen>
     <dimen name="all_apps_search_bar_field_height">48dp</dimen>
     <dimen name="all_apps_search_bar_bottom_padding">30dp</dimen>
     <dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
diff --git a/res/xml/size_limits_80x104.xml b/res/xml/size_limits_80x104.xml
index e11bc5e..f375549 100644
--- a/res/xml/size_limits_80x104.xml
+++ b/res/xml/size_limits_80x104.xml
@@ -36,11 +36,11 @@
             launcher:a="0"
             launcher:b="16dp"/>
         <workspaceBottomPadding
-            launcher:a="0.50"
+            launcher:a="0.56"
             launcher:b="0"
             launcher:c="16dp"/>
         <hotseatBottomPadding
-            launcher:a="0.50"
+            launcher:a="0.44"
             launcher:b="0"
             launcher:c="16dp"/>
     </device-padding>
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 9b350a1..5ba03ed 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -28,6 +28,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Process;
 import android.os.StrictMode;
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 7ece72e..c16c44b 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -212,7 +212,10 @@
         mActivity = ActivityContext.lookupContext(context);
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
 
-        mBorderSpacing = deviceProfile.cellLayoutBorderSpacingPx;
+        mBorderSpacing = mContainerType == FOLDER
+                ? deviceProfile.folderCellLayoutBorderSpacingPx
+                : deviceProfile.cellLayoutBorderSpacingPx;
+
         mCellWidth = mCellHeight = -1;
         mFixedCellWidth = mFixedCellHeight = -1;
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 1ce5f4d..aea38a0 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -123,6 +123,7 @@
     public int folderIconOffsetYPx;
 
     // Folder content
+    public int folderCellLayoutBorderSpacingPx;
     public int folderContentPaddingLeftRight;
     public int folderContentPaddingTop;
 
@@ -146,6 +147,7 @@
     public final int hotseatBarSidePaddingEndPx;
 
     // All apps
+    public int allAppsOpenVerticalTranslate;
     public int allAppsCellHeightPx;
     public int allAppsCellWidthPx;
     public int allAppsIconSizePx;
@@ -247,6 +249,10 @@
                 : res.getDimensionPixelSize(R.dimen.dynamic_grid_left_right_margin);
         desiredWorkspaceLeftRightOriginalPx = desiredWorkspaceLeftRightMarginPx;
 
+
+        allAppsOpenVerticalTranslate = res.getDimensionPixelSize(
+                R.dimen.all_apps_open_vertical_translate);
+
         folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale);
         folderContentPaddingLeftRight =
                 res.getDimensionPixelSize(R.dimen.folder_content_padding_left_right);
@@ -254,6 +260,7 @@
 
         setCellLayoutBorderSpacing(pxFromDp(inv.borderSpacing, mInfo.metrics, 1f));
         cellLayoutBorderSpacingOriginalPx = cellLayoutBorderSpacingPx;
+        folderCellLayoutBorderSpacingPx = cellLayoutBorderSpacingPx;
 
         int cellLayoutPaddingLeftRightMultiplier = !isVerticalBarLayout() && isTablet
                 ? PORTRAIT_TABLET_LEFT_RIGHT_PADDING_MULTIPLIER : 1;
@@ -352,13 +359,7 @@
     }
 
     private void setCellLayoutBorderSpacing(int borderSpacing) {
-        if (isScalableGrid) {
-            cellLayoutBorderSpacingPx = borderSpacing;
-            folderContentPaddingLeftRight = borderSpacing;
-            folderContentPaddingTop = borderSpacing;
-        } else {
-            cellLayoutBorderSpacingPx = 0;
-        }
+        cellLayoutBorderSpacingPx = isScalableGrid ? borderSpacing : 0;
     }
 
     /**
@@ -404,12 +405,7 @@
                 .setMultiWindowMode(true)
                 .build();
 
-        // If there isn't enough vertical cell padding with the labels displayed, hide the labels.
-        float workspaceCellPaddingY = profile.getCellSize().y - profile.iconSizePx
-                - iconDrawablePaddingPx - profile.iconTextSizePx;
-        if (workspaceCellPaddingY < profile.iconDrawablePaddingPx * 2) {
-            profile.adjustToHideWorkspaceLabels();
-        }
+        profile.hideWorkspaceLabelsIfNotEnoughSpace();
 
         // We use these scales to measure and layout the widgets using their full invariant profile
         // sizes and then draw them scaled and centered to fit in their multi-window mode cellspans.
@@ -430,24 +426,32 @@
     }
 
     /**
-     * Adjusts the profile so that the labels on the Workspace are hidden.
+     * Checks if there is enough space for labels on the workspace.
+     * If there is not, labels on the Workspace are hidden.
      * It is important to call this method after the All Apps variables have been set.
      */
-    private void adjustToHideWorkspaceLabels() {
-        iconTextSizePx = 0;
-        iconDrawablePaddingPx = 0;
-        cellHeightPx = iconSizePx;
-        autoResizeAllAppsCells();
+    private void hideWorkspaceLabelsIfNotEnoughSpace() {
+        float iconTextHeight = Utilities.calculateTextHeight(iconTextSizePx);
+        float workspaceCellPaddingY = getCellSize().y - iconSizePx - iconDrawablePaddingPx
+                - iconTextHeight;
+
+        // We want enough space so that the text is closer to its corresponding icon.
+        if (workspaceCellPaddingY < iconTextHeight) {
+            iconTextSizePx = 0;
+            iconDrawablePaddingPx = 0;
+            cellHeightPx = iconSizePx;
+            autoResizeAllAppsCells();
+        }
     }
 
     /**
      * Re-computes the all-apps cell size to be independent of workspace
      */
     public void autoResizeAllAppsCells() {
-        int topBottomPadding = allAppsIconDrawablePaddingPx * (isVerticalBarLayout() ? 2 : 1);
+        int textHeight = Utilities.calculateTextHeight(allAppsIconTextSizePx);
+        int topBottomPadding = textHeight;
         allAppsCellHeightPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx
-                + Utilities.calculateTextHeight(allAppsIconTextSizePx)
-                + topBottomPadding * 2;
+                + textHeight + (topBottomPadding * 2);
     }
 
     /**
@@ -536,9 +540,7 @@
             allAppsIconSizePx = pxFromDp(inv.allAppsIconSize, mInfo.metrics);
             allAppsIconTextSizePx = Utilities.pxFromSp(inv.allAppsIconTextSize, mInfo.metrics);
             allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
-            // We use 4 below to ensure labels are closer to their corresponding icon.
-            allAppsCellHeightPx = Math.round(allAppsIconSizePx + allAppsIconTextSizePx
-                    + (4 * allAppsIconDrawablePaddingPx));
+            autoResizeAllAppsCells();
         } else {
             allAppsIconSizePx = iconSizePx;
             allAppsIconTextSizePx = iconTextSizePx;
@@ -547,9 +549,8 @@
         }
         allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx;
 
-        if (isVerticalBarLayout()) {
-            // Always hide the Workspace text with vertical bar layout.
-            adjustToHideWorkspaceLabels();
+        if (isVerticalLayout) {
+            hideWorkspaceLabelsIfNotEnoughSpace();
         }
 
         // Hotseat
@@ -587,14 +588,14 @@
 
         // Check if the icons fit within the available height.
         float contentUsedHeight = folderCellHeightPx * inv.numFolderRows
-                + ((inv.numFolderRows - 1) * cellLayoutBorderSpacingPx);
+                + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacingPx);
         int contentMaxHeight = availableHeightPx - totalWorkspacePadding.y - folderBottomPanelSize
                 - folderMargin - folderContentPaddingTop;
         float scaleY = contentMaxHeight / contentUsedHeight;
 
         // Check if the icons fit within the available width.
         float contentUsedWidth = folderCellWidthPx * inv.numFolderColumns
-                + ((inv.numFolderColumns - 1) * cellLayoutBorderSpacingPx);
+                + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacingPx);
         int contentMaxWidth = availableWidthPx - totalWorkspacePadding.x - folderMargin
                 - folderContentPaddingLeftRight * 2;
         float scaleX = contentMaxWidth / contentUsedWidth;
@@ -612,11 +613,25 @@
         folderLabelTextSizePx = (int) (folderChildTextSizePx * folderLabelTextScale);
 
         int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx);
-        int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding) * scale);
-        int cellPaddingY = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_y_padding) * scale);
 
-        folderCellWidthPx = folderChildIconSizePx + 2 * cellPaddingX;
-        folderCellHeightPx = folderChildIconSizePx + 2 * cellPaddingY + textHeight;
+        if (isScalableGrid) {
+            folderCellWidthPx = (int) (cellWidthPx * scale);
+            folderCellHeightPx = (int) (cellHeightPx * scale);
+
+            int borderSpacing = (int) (cellLayoutBorderSpacingOriginalPx * scale);
+            folderCellLayoutBorderSpacingPx = borderSpacing;
+            folderContentPaddingLeftRight = borderSpacing;
+            folderContentPaddingTop = borderSpacing;
+        } else {
+            int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding)
+                    * scale);
+            int cellPaddingY = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_y_padding)
+                    * scale);
+
+            folderCellWidthPx = folderChildIconSizePx + 2 * cellPaddingX;
+            folderCellHeightPx = folderChildIconSizePx + 2 * cellPaddingY + textHeight;
+        }
+
         folderChildDrawablePaddingPx = Math.max(0,
                 (folderCellHeightPx - folderChildIconSizePx - textHeight) / 3);
     }
@@ -868,6 +883,8 @@
         writer.println(prefix + pxToDpStr("folderChildTextSizePx", folderChildTextSizePx));
         writer.println(prefix + pxToDpStr("folderChildDrawablePaddingPx",
                 folderChildDrawablePaddingPx));
+        writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacingPx",
+                folderCellLayoutBorderSpacingPx));
 
         writer.println(prefix + pxToDpStr("cellLayoutBorderSpacingPx",
                 cellLayoutBorderSpacingPx));
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 4049ed6..5429806 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -96,7 +96,6 @@
         } else {
             setGridSize(idp.numHotseatIcons, 1);
         }
-        showInlineQsb();
     }
 
     @Override
@@ -181,10 +180,6 @@
         mOnVisibilityAggregatedCallback = callback;
     }
 
-    protected void showInlineQsb() {
-        //Does nothing
-    }
-
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -223,13 +218,6 @@
     }
 
     /**
-     * Returns the first View for which the given itemOperator returns true, or null.
-     */
-    public View getFirstItemMatch(Workspace.ItemOperator itemOperator) {
-        return mWorkspace.getFirstMatch(new CellLayout[] { this }, itemOperator);
-    }
-
-    /**
      * Sets the alpha value of just our ShortcutAndWidgetContainer.
      */
     public void setIconsAlpha(float alpha) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5eba399..df5f953 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -34,7 +34,6 @@
 import static com.android.launcher3.LauncherState.NORMAL;
 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.SPRING_LOADED;
 import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
@@ -61,6 +60,10 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
 import android.content.ActivityNotFoundException;
@@ -149,7 +152,6 @@
 import com.android.launcher3.qsb.QsbContainerView;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
-import com.android.launcher3.statemanager.StateManager.StateListener;
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.states.RotationHelper;
 import com.android.launcher3.testing.TestLogging;
@@ -269,9 +271,6 @@
     private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
     @Thunk @VisibleForTesting public static final int NEW_APPS_ANIMATION_DELAY = 500;
 
-    private static final int APPS_VIEW_ALPHA_CHANNEL_INDEX = 1;
-    private static final int SCRIM_VIEW_ALPHA_CHANNEL_INDEX = 0;
-
     private static final int THEME_CROSS_FADE_ANIMATION_DURATION = 375;
 
     private Configuration mOldConfig;
@@ -342,8 +341,6 @@
 
     private RotationHelper mRotationHelper;
 
-    private float mCurrentAssistantVisibility = 0f;
-
     protected LauncherOverlayManager mOverlayManager;
     // If true, overlay callbacks are deferred
     private boolean mDeferOverlayCallbacks;
@@ -380,6 +377,44 @@
                     .build());
         }
 
+        if (Utilities.IS_DEBUG_DEVICE && FeatureFlags.NOTIFY_CRASHES.get()) {
+            final String notificationChannelId = "com.android.launcher3.Debug";
+            final String notificationChannelName = "Debug";
+            final String notificationTag = "Debug";
+            final int notificationId = 0;
+
+            NotificationManager notificationManager = getSystemService(NotificationManager.class);
+            notificationManager.createNotificationChannel(new NotificationChannel(
+                    notificationChannelId, notificationChannelName,
+                    NotificationManager.IMPORTANCE_HIGH));
+
+            Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> {
+                String stackTrace = Log.getStackTraceString(throwable);
+
+                Intent shareIntent = new Intent(Intent.ACTION_SEND);
+                shareIntent.setType("text/plain");
+                shareIntent.putExtra(Intent.EXTRA_TEXT, stackTrace);
+                shareIntent = Intent.createChooser(shareIntent, null);
+                PendingIntent sharePendingIntent = PendingIntent.getActivity(
+                        this, 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT
+                );
+
+                Notification notification = new Notification.Builder(this, notificationChannelId)
+                        .setSmallIcon(android.R.drawable.ic_menu_close_clear_cancel)
+                        .setContentTitle("Launcher crash detected!")
+                        .setStyle(new Notification.BigTextStyle().bigText(stackTrace))
+                        .addAction(android.R.drawable.ic_menu_share, "Share", sharePendingIntent)
+                        .build();
+                notificationManager.notify(notificationTag, notificationId, notification);
+
+                Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler =
+                        Thread.getDefaultUncaughtExceptionHandler();
+                if (defaultUncaughtExceptionHandler != null) {
+                    defaultUncaughtExceptionHandler.uncaughtException(thread, throwable);
+                }
+            });
+        }
+
         super.onCreate(savedInstanceState);
 
         LauncherAppState app = LauncherAppState.getInstance(this);
@@ -457,24 +492,6 @@
                 OverlayPlugin.class, false /* allowedMultiple */);
 
         mRotationHelper.initialize();
-
-        mStateManager.addStateListener(new StateListener<LauncherState>() {
-
-            @Override
-            public void onStateTransitionComplete(LauncherState finalState) {
-                float alpha = 1f - mCurrentAssistantVisibility;
-                if (finalState == NORMAL) {
-                    mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
-                } else if (finalState == OVERVIEW) {
-                    mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
-                    mScrimView.setAlpha(alpha);
-                } else {
-                    mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(1f);
-                    mScrimView.setAlpha(1f);
-                }
-            }
-        });
-
         TraceHelper.INSTANCE.endSection(traceToken);
 
         mUserChangedCallbackCloseable = UserCache.INSTANCE.get(this).addUserChangeListener(
@@ -563,15 +580,7 @@
     }
 
     public void onAssistantVisibilityChanged(float visibility) {
-        mCurrentAssistantVisibility = visibility;
-        float alpha = 1f - visibility;
-        LauncherState state = mStateManager.getState();
-        if (state == NORMAL) {
-            mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
-        } else if (state == OVERVIEW) {
-            mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(alpha);
-            mScrimView.setAlpha(alpha);
-        }
+        mHotseat.getQsb().setAlpha(1f - visibility);
     }
 
     private void initDeviceProfile(InvariantDeviceProfile idp) {
@@ -1027,7 +1036,19 @@
         }
         // When multiple pages are visible, show persistent page indicator
         mWorkspace.getPageIndicator().setShouldAutoHide(!state.hasFlag(FLAG_MULTI_PAGE));
+
         mPrevLauncherState = mStateManager.getCurrentStableState();
+        if (mPrevLauncherState != state && ALL_APPS.equals(state)
+                // Making sure mAllAppsSessionLogId is null to avoid double logging.
+                && mAllAppsSessionLogId == null) {
+            // creates new instance ID since new all apps session is started.
+            mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId();
+            getStatsLogManager()
+                    .logger()
+                    .log(FeatureFlags.ENABLE_DEVICE_SEARCH.get()
+                            ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
+                            : LAUNCHER_ALLAPPS_ENTRY);
+        }
     }
 
     @Override
@@ -1052,16 +1073,8 @@
             getRotationHelper().setCurrentStateRequest(REQUEST_NONE);
         }
 
-        if (ALL_APPS.equals(state)) {
-            // creates new instance ID since new all apps session is started.
-            mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId();
-            getStatsLogManager()
-                    .logger()
-                    .log(FeatureFlags.ENABLE_DEVICE_SEARCH.get()
-                            ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
-                            : LAUNCHER_ALLAPPS_ENTRY);
-        } else if (ALL_APPS.equals(mPrevLauncherState)
-                // Check if mLogInstanceId is not null to make sure exit event is logged only once.
+        if (mPrevLauncherState != state && !ALL_APPS.equals(state)
+                // Making sure mAllAppsSessionLogId is not null to avoid double logging.
                 && mAllAppsSessionLogId != null) {
             getStatsLogManager().logger().log(LAUNCHER_ALLAPPS_EXIT);
             mAllAppsSessionLogId = null;
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index ccc023a..4754558 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -116,7 +116,7 @@
         mNotificationSettingsChangedListener = this::onNotificationSettingsChanged;
         mSettingsCache.register(NOTIFICATION_BADGING_URI,
                 mNotificationSettingsChangedListener);
-        mSettingsCache.dispatchOnChange(NOTIFICATION_BADGING_URI);
+        onNotificationSettingsChanged(mSettingsCache.getValue(NOTIFICATION_BADGING_URI));
     }
 
     public LauncherAppState(Context context, @Nullable String iconCacheFileName) {
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 46bce93..1003958 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -17,9 +17,11 @@
 
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
+import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
 import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
 import static com.android.launcher3.testing.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
 import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
+import static com.android.launcher3.testing.TestProtocol.HINT_STATE_TWO_BUTTON_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_SPLIT_SELECT_ORDINAL;
@@ -89,7 +91,7 @@
                 }
             };
 
-    private static final LauncherState[] sAllStates = new LauncherState[9];
+    private static final LauncherState[] sAllStates = new LauncherState[10];
 
     /**
      * TODO: Create a separate class for NORMAL state.
@@ -112,6 +114,8 @@
             SPRING_LOADED_STATE_ORDINAL);
     public static final LauncherState ALL_APPS = new AllAppsState(ALL_APPS_STATE_ORDINAL);
     public static final LauncherState HINT_STATE = new HintState(HINT_STATE_ORDINAL);
+    public static final LauncherState HINT_STATE_TWO_BUTTON = new HintState(
+            HINT_STATE_TWO_BUTTON_ORDINAL, LAUNCHER_STATE_OVERVIEW);
 
     public static final LauncherState OVERVIEW = new OverviewState(OVERVIEW_STATE_ORDINAL);
     public static final LauncherState OVERVIEW_MODAL_TASK = OverviewState.newModalTaskState(
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 76885cc..01f7c71 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -715,13 +715,10 @@
                 final int primaryDimension = bounds.primaryDimension;
                 final int childPrimaryEnd = bounds.childPrimaryEnd;
 
-                // In case the pages are of different width, align the page to left or right edge
-                // based on the orientation.
-                // In case we have multiple panels on the screen, scrollOffsetEnd is the scroll
-                // needed for the whole visible area, so we have to divide it by panelCount.
-                final int pageScroll = mIsRtl
-                        ? (childStart - scrollOffsetStart)
-                        : Math.max(0, childPrimaryEnd - scrollOffsetEnd / getPanelCount());
+                // In case the pages are of different width, align the page to left edge for non-RTL
+                // or right edge for RTL.
+                final int pageScroll =
+                        mIsRtl ? childPrimaryEnd - scrollOffsetEnd : childStart - scrollOffsetStart;
                 if (outPageScrolls[i] != pageScroll) {
                     pageScrollChanged = true;
                     outPageScrolls[i] = pageScroll;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 8825710..1776777 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -37,6 +37,8 @@
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.LightingColorFilter;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Point;
@@ -64,6 +66,7 @@
 import android.view.ViewConfiguration;
 import android.view.animation.Interpolator;
 
+import androidx.core.graphics.ColorUtils;
 import androidx.core.os.BuildCompat;
 
 import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
@@ -732,6 +735,23 @@
         }
     }
 
+    /**
+     * Make a color filter that blends a color into the destination based on a scalable amout.
+     *
+     * @param color to blend in.
+     * @param tintAmount [0-1] 0 no tinting, 1 full color.
+     * @return ColorFilter for tinting, or {@code null} if no filter is needed.
+     */
+    public static ColorFilter makeColorTintingColorFilter(int color, float tintAmount) {
+        if (tintAmount == 0f) {
+            return null;
+        }
+        return new LightingColorFilter(
+                // This isn't blending in white, its making a multiplication mask for the base color
+                ColorUtils.blendARGB(Color.WHITE, 0, tintAmount),
+                ColorUtils.blendARGB(0, color, tintAmount));
+    }
+
     private static class FixedSizeEmptyDrawable extends ColorDrawable {
 
         private final int mSize;
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 2f9c96e..f43452c 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -541,20 +541,17 @@
             c.setBitmap(preview);
             c.drawColor(0, PorterDuff.Mode.CLEAR);
         }
-        RectF boxRect = drawBoxWithShadow(c, size, size);
+
+        drawBoxWithShadow(c, size, size);
 
         LauncherIcons li = LauncherIcons.obtain(mContext);
-        Bitmap icon = li.createBadgedIconBitmap(
+        Drawable icon = li.createBadgedIconBitmap(
                 mutateOnMainThread(info.getFullResIcon(mIconCache)),
-                Process.myUserHandle(), 0).icon;
+                Process.myUserHandle(), 0).newIcon(launcher);
         li.recycle();
 
-        Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
-
-        boxRect.set(0, 0, iconSize, iconSize);
-        boxRect.offset(padding, padding);
-        c.drawBitmap(icon, src, boxRect,
-                new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
+        icon.setBounds(padding, padding, padding + iconSize, padding + iconSize);
+        icon.draw(c);
         c.setBitmap(null);
         return preview;
     }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 48638f5..981cf89 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2978,8 +2978,10 @@
      * @param user The user of the app to match.
      */
     public View getFirstMatchForAppClose(String packageName, UserHandle user) {
-        final int curPage = getCurrentPage();
-        final CellLayout currentPage = (CellLayout) getPageAt(curPage);
+        List<CellLayout> cellLayouts = new ArrayList<>(getPanelCount() + 1);
+        cellLayouts.add(getHotseat());
+        getVisiblePages().forEach(page -> cellLayouts.add((CellLayout) page));
+
         final Workspace.ItemOperator packageAndUser = (ItemInfo info, View view) -> info != null
                 && info.getTargetComponent() != null
                 && TextUtils.equals(info.getTargetComponent().getPackageName(), packageName)
@@ -3000,13 +3002,11 @@
 
         // Order: App icons, app in folder. Items in hotseat get returned first.
         if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
-            return getFirstMatch(new CellLayout[] { getHotseat(), currentPage },
-                    packageAndUserAndApp, packageAndUserAndAppInFolder);
+            return getFirstMatch(cellLayouts, packageAndUserAndApp, packageAndUserAndAppInFolder);
         } else {
             // Do not use Folder as a criteria, since it'll cause a crash when trying to draw
             // FolderAdaptiveIcon as the background.
-            return getFirstMatch(new CellLayout[] { getHotseat(), currentPage },
-                    packageAndUserAndApp);
+            return getFirstMatch(cellLayouts, packageAndUserAndApp);
         }
     }
 
@@ -3040,7 +3040,7 @@
      * @param operators List of operators, in order starting from best matching operator.
      * @return
      */
-    View getFirstMatch(CellLayout[] cellLayouts, final ItemOperator... operators) {
+    View getFirstMatch(Iterable<CellLayout> cellLayouts, final ItemOperator... operators) {
         // This array is filled with the first match for each operator.
         final View[] matches = new View[operators.length];
         // For efficiency, the outer loop should be CellLayout.
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 16e022c..e0a4d4a 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -105,47 +105,39 @@
         int elements = state.getVisibleElements(mLauncher);
         Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
                 pageAlphaProvider.interpolator);
-        boolean playAtomicComponent = config.playAtomicOverviewScaleComponent();
         Hotseat hotseat = mWorkspace.getHotseat();
-        if (playAtomicComponent) {
-            Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
-            LauncherState fromState = mLauncher.getStateManager().getState();
-            boolean shouldSpring = propertySetter instanceof PendingAnimation
-                    && fromState == HINT_STATE && state == NORMAL;
-            if (shouldSpring) {
-                ((PendingAnimation) propertySetter).add(getSpringScaleAnimator(mLauncher,
-                        mWorkspace, mNewScale));
-            } else {
-                propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
-            }
+        Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
+        LauncherState fromState = mLauncher.getStateManager().getState();
 
-            setPivotToScaleWithWorkspace(hotseat);
-            float hotseatScale = hotseatScaleAndTranslation.scale;
-            if (shouldSpring) {
-                PendingAnimation pa = (PendingAnimation) propertySetter;
-                pa.add(getSpringScaleAnimator(mLauncher, hotseat, hotseatScale));
-            } else {
-                Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
-                        scaleInterpolator);
-                propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
-                        hotseatScaleInterpolator);
-            }
-
-            float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
-            propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
-            float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
-            propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
-                    workspacePageIndicatorAlpha, fadeInterpolator);
+        boolean shouldSpring = propertySetter instanceof PendingAnimation
+                && fromState == HINT_STATE && state == NORMAL;
+        if (shouldSpring) {
+            ((PendingAnimation) propertySetter).add(getSpringScaleAnimator(mLauncher,
+                    mWorkspace, mNewScale));
+        } else {
+            propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
         }
 
-        if (config.onlyPlayAtomicComponent()) {
-            // Only the alpha and scale, handled above, are included in the atomic animation.
-            return;
+        setPivotToScaleWithWorkspace(hotseat);
+        float hotseatScale = hotseatScaleAndTranslation.scale;
+        if (shouldSpring) {
+            PendingAnimation pa = (PendingAnimation) propertySetter;
+            pa.add(getSpringScaleAnimator(mLauncher, hotseat, hotseatScale));
+        } else {
+            Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
+                    scaleInterpolator);
+            propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
+                    hotseatScaleInterpolator);
         }
 
-        Interpolator translationInterpolator = !playAtomicComponent
-                ? LINEAR
-                : config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
+        float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
+        propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
+        float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
+        propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
+                workspacePageIndicatorAlpha, fadeInterpolator);
+
+        Interpolator translationInterpolator =
+                config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
         propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_X,
                 scaleAndTranslation.translationX, translationInterpolator);
         propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_Y,
@@ -195,17 +187,12 @@
         int drawableAlpha = state.hasFlag(FLAG_WORKSPACE_HAS_BACKGROUNDS)
                 ? Math.round(pageAlpha * 255) : 0;
 
-        if (!config.onlyPlayAtomicComponent()) {
-            // Don't update the scrim during the atomic animation.
-            propertySetter.setInt(cl.getScrimBackground(),
-                    DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
-        }
-        if (config.playAtomicOverviewScaleComponent()) {
-            Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
-                    pageAlphaProvider.interpolator);
-            propertySetter.setFloat(cl.getShortcutsAndWidgets(), VIEW_ALPHA,
-                    pageAlpha, fadeInterpolator);
-        }
+        propertySetter.setInt(cl.getScrimBackground(),
+                DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
+        Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
+                pageAlphaProvider.interpolator);
+        propertySetter.setFloat(cl.getShortcutsAndWidgets(), VIEW_ALPHA,
+                pageAlpha, fadeInterpolator);
     }
 
     /**
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index db7fd3f..a5852ba 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -265,7 +265,7 @@
             List<OptionItem> actions = getSupportedResizeActions(host, info);
             Rect pos = new Rect();
             mLauncher.getDragLayer().getDescendantRectRelativeToSelf(host, pos);
-            ArrowPopup popup = OptionsPopupView.show(mLauncher, new RectF(pos), actions);
+            ArrowPopup popup = OptionsPopupView.show(mLauncher, new RectF(pos), actions, false);
             popup.requestFocus();
             popup.setOnCloseCallback(host::requestFocus);
             return true;
@@ -294,15 +294,17 @@
         if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) {
             if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) ||
                     layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) {
-                actions.add(new OptionItem(
-                        R.string.action_increase_width, R.drawable.ic_widget_width_increase,
+                actions.add(new OptionItem(mLauncher,
+                        R.string.action_increase_width,
+                        R.drawable.ic_widget_width_increase,
                         IGNORE,
                         v -> performResizeAction(R.string.action_increase_width, host, info)));
             }
 
             if (info.spanX > info.minSpanX && info.spanX > 1) {
-                actions.add(new OptionItem(
-                        R.string.action_decrease_width, R.drawable.ic_widget_width_decrease,
+                actions.add(new OptionItem(mLauncher,
+                        R.string.action_decrease_width,
+                        R.drawable.ic_widget_width_decrease,
                         IGNORE,
                         v -> performResizeAction(R.string.action_decrease_width, host, info)));
             }
@@ -311,15 +313,17 @@
         if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
             if (layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1) ||
                     layout.isRegionVacant(info.cellX, info.cellY - 1, info.spanX, 1)) {
-                actions.add(new OptionItem(
-                        R.string.action_increase_height, R.drawable.ic_widget_height_increase,
+                actions.add(new OptionItem(mLauncher,
+                        R.string.action_increase_height,
+                        R.drawable.ic_widget_height_increase,
                         IGNORE,
                         v -> performResizeAction(R.string.action_increase_height, host, info)));
             }
 
             if (info.spanY > info.minSpanY && info.spanY > 1) {
-                actions.add(new OptionItem(
-                        R.string.action_decrease_height, R.drawable.ic_widget_height_decrease,
+                actions.add(new OptionItem(mLauncher,
+                        R.string.action_decrease_height,
+                        R.drawable.ic_widget_height_decrease,
                         IGNORE,
                         v -> performResizeAction(R.string.action_decrease_height, host, info)));
             }
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 225e1c1..406e785 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -64,8 +64,6 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.RecyclerViewFastScroller;
 import com.android.launcher3.views.SpringRelativeLayout;
@@ -80,7 +78,6 @@
     private static final float FLING_VELOCITY_MULTIPLIER = 1000 * .8f;
     // Starts the springs after at least 55% of the animation has passed.
     private static final float FLING_ANIMATION_THRESHOLD = 0.55f;
-    private static final int ALPHA_CHANNEL_COUNT = 2;
 
     protected final BaseDraggingActivity mLauncher;
     protected final AdapterHolder[] mAH;
@@ -107,8 +104,6 @@
     protected RecyclerViewFastScroller mTouchHandler;
     protected final Point mFastScrollerOffset = new Point();
 
-    private final MultiValueAlpha mMultiValueAlpha;
-
     private Rect mInsets = new Rect();
 
     SearchAdapterProvider mSearchAdapterProvider;
@@ -139,8 +134,6 @@
         mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
 
         mAllAppsStore.addUpdateListener(this::onAppsUpdated);
-
-        mMultiValueAlpha = new MultiValueAlpha(this, ALPHA_CHANNEL_COUNT);
     }
 
     /**
@@ -156,10 +149,6 @@
         return mAllAppsStore;
     }
 
-    public AlphaProperty getAlphaProperty(int index) {
-        return mMultiValueAlpha.getProperty(index);
-    }
-
     public WorkModeSwitch getWorkModeSwitch() {
         return mWorkModeSwitch;
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 16ecd58..c21d774 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -110,7 +110,6 @@
         setScrollRangeDelta(mScrollRangeDelta);
 
         if (mIsVerticalLayout) {
-            mAppsView.getAlphaProperty(APPS_VIEW_ALPHA_CHANNEL_INDEX).setValue(1);
             mLauncher.getHotseat().setTranslationY(0);
             mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
         }
@@ -128,7 +127,7 @@
         mProgress = progress;
 
         mScrimView.setProgress(progress);
-        mAppsView.setTranslationY(progress * mShiftRange);
+        mAppsView.setTranslationY(mProgress * mShiftRange);
     }
 
     public float getProgress() {
@@ -155,19 +154,12 @@
             StateAnimationConfig config, PendingAnimation builder) {
         float targetProgress = toState.getVerticalProgress(mLauncher);
         if (Float.compare(mProgress, targetProgress) == 0) {
-            if (!config.onlyPlayAtomicComponent()) {
-                setAlphas(toState, config, builder);
-            }
+            setAlphas(toState, config, builder);
             // Fail fast
             onProgressAnimationEnd();
             return;
         }
 
-        if (config.onlyPlayAtomicComponent()) {
-            // There is no atomic component for the all apps transition, so just return early.
-            return;
-        }
-
         Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW
                 ? config.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
                 : FAST_OUT_SLOW_IN;
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index 13ddc12..16ae250 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -72,8 +72,9 @@
     @Override
     public void setInsets(Rect insets) {
         super.setInsets(insets);
-        mLauncher.getAllAppsController()
-                .setScrollRangeDelta(mSearchUiManager.getScrollRangeDelta(insets));
+        int allAppsStartingPositionY = mLauncher.getDeviceProfile().availableHeightPx
+                - mLauncher.getDeviceProfile().allAppsOpenVerticalTranslate;
+        mLauncher.getAllAppsController().setScrollRangeDelta(allAppsStartingPositionY);
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index 941d3af..924a392 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.allapps;
 
-import android.graphics.Rect;
 import android.view.KeyEvent;
 
 import androidx.annotation.Nullable;
@@ -44,11 +43,6 @@
     default void preDispatchKeyEvent(KeyEvent keyEvent) { };
 
     /**
-     * Returns the vertical shift for the all-apps view, so that it aligns with the hotseat.
-     */
-    float getScrollRangeDelta(Rect insets);
-
-    /**
      * @return the edit text object
      */
     @Nullable
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index c51bcf5..a8185d6 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -42,7 +42,6 @@
 import com.android.launcher3.allapps.AllAppsStore;
 import com.android.launcher3.allapps.AlphabeticalAppsList;
 import com.android.launcher3.allapps.SearchUiManager;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.search.SearchCallback;
 
 import java.util.ArrayList;
@@ -210,16 +209,6 @@
     }
 
     @Override
-    public float getScrollRangeDelta(Rect insets) {
-        if (mLauncher.getDeviceProfile().isVerticalBarLayout()
-                || FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
-            return 0;
-        } else {
-            return insets.bottom + insets.top;
-        }
-    }
-
-    @Override
     public ExtendedEditText getEditText() {
         return this;
     }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 22a64c9..6331ef2 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -93,7 +93,11 @@
 
 
     public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag(
-            "ENABLE_DEVICE_SEARCH", false, "Allows on device search in all apps");
+            "ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
+
+    public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(
+            "ENABLE_PEOPLE_TILE_PREVIEW", false,
+            "Experimental: Shows conversation shortcuts on home screen as search results");
 
     public static final BooleanFlag FOLDER_NAME_SUGGEST = new DeviceFlag(
             "FOLDER_NAME_SUGGEST", true,
@@ -218,6 +222,9 @@
     public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = new DeviceFlag(
             "ENABLE_ENFORCED_ROUNDED_CORNERS", true, "Enforce rounded corners on all App Widgets");
 
+    public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag("NOTIFY_CRASHES", false,
+            "Sends a notification whenever launcher encounters an uncaught exception.");
+
     public static void initialize(Context context) {
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
index 5cd95dc..7b32bbf 100644
--- a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
+++ b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
@@ -27,15 +27,21 @@
 
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
-/** A drawable which renders {@link LauncherAppWidgetHostView} to a canvas. */
+/**
+ * A drawable which renders {@link LauncherAppWidgetHostView} to a canvas.
+ *
+ * TODO(b/183609936) Stop using that class and remove it.
+ */
 public final class AppWidgetHostViewDrawable extends Drawable {
 
     private final LauncherAppWidgetHostView mAppWidgetHostView;
     private Paint mPaint = new Paint();
     private final Path mClipPath;
+    private final boolean mWasAttached;
 
     public AppWidgetHostViewDrawable(LauncherAppWidgetHostView appWidgetHostView) {
         mAppWidgetHostView = appWidgetHostView;
+        mWasAttached = appWidgetHostView.isAttachedToWindow();
         Path clipPath = null;
         if (appWidgetHostView.getClipToOutline()) {
             Outline outline = new Outline();
@@ -56,7 +62,12 @@
         if (mClipPath != null) {
             canvas.clipPath(mClipPath);
         }
-        mAppWidgetHostView.draw(canvas);
+        // If the view was never attached, or is current attached, then draw. Otherwise do not try
+        // to draw, or we might trigger bugs with items that get drawn while requiring the view to
+        // be attached.
+        if (!mWasAttached || mAppWidgetHostView.isAttachedToWindow()) {
+            mAppWidgetHostView.draw(canvas);
+        }
         canvas.restoreToCount(saveCount);
     }
 
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index ec7155c..a1b7997 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -745,6 +745,10 @@
         if (mIsAnimatingClosed) {
             return;
         }
+
+        mContent.completePendingPageChanges();
+        mContent.snapToPageImmediately(mContent.getDestinationPage());
+
         if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
             mCurrentAnimator.cancel();
         }
diff --git a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
deleted file mode 100644
index 5872689..0000000
--- a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.
- */
-package com.android.launcher3.graphics;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.RectF;
-
-/**
- * Utility class which draws a bitmap by dissecting it into 3 segments and stretching
- * the middle segment.
- */
-public class NinePatchDrawHelper {
-
-    // The extra width used for the bitmap. This portion of the bitmap is stretched to match the
-    // width of the draw region. Randomly chosen, any value > 4 will be sufficient.
-    public static final int EXTENSION_PX = 20;
-
-    private final Rect mSrc = new Rect();
-    private final RectF mDst = new RectF();
-    // Enable filtering to always get a nice edge. This avoids jagged line, when bitmap is
-    // translated by half pixel.
-    public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
-
-    /**
-     * Draws the bitmap split into three parts horizontally, with the middle part having width
-     * as {@link #EXTENSION_PX} in the center of the bitmap.
-     */
-    public void draw(Bitmap bitmap, Canvas canvas, float left, float top, float right) {
-        int height = bitmap.getHeight();
-
-        mSrc.top = 0;
-        mSrc.bottom = height;
-        mDst.top = top;
-        mDst.bottom = top + height;
-        draw3Patch(bitmap, canvas, left, right);
-    }
-
-
-    /**
-     * Draws the bitmap split horizontally into 3 parts (same as {@link #draw}) and split
-     * vertically into two parts, bottom part of size {@link #EXTENSION_PX} / 2 which is
-     * stretched vertically.
-     */
-    public void drawVerticallyStretched(Bitmap bitmap, Canvas canvas, float left, float top,
-            float right, float bottom) {
-        draw(bitmap, canvas, left, top, right);
-
-        // Draw bottom stretched region.
-        int height = bitmap.getHeight();
-        mSrc.top = height - EXTENSION_PX / 4;
-        mSrc.bottom = height;
-        mDst.top = top + height;
-        mDst.bottom = bottom;
-        draw3Patch(bitmap, canvas, left, right);
-    }
-
-
-
-    private void draw3Patch(Bitmap bitmap, Canvas canvas, float left, float right) {
-        int width = bitmap.getWidth();
-        int halfWidth = width / 2;
-
-        // Draw left edge
-        drawRegion(bitmap, canvas, 0, halfWidth, left, left + halfWidth);
-
-        // Draw right edge
-        drawRegion(bitmap, canvas, halfWidth, width, right - halfWidth, right);
-
-        // Draw middle stretched region
-        int halfExt = EXTENSION_PX / 4;
-        drawRegion(bitmap, canvas, halfWidth - halfExt, halfWidth + halfExt,
-                left + halfWidth, right - halfWidth);
-    }
-
-    private void drawRegion(Bitmap bitmap, Canvas c,
-            int srcLeft, int srcRight, float dstLeft, float dstRight) {
-        mSrc.left = srcLeft;
-        mSrc.right = srcRight;
-
-        mDst.left = dstLeft;
-        mDst.right = dstRight;
-        c.drawBitmap(bitmap, mSrc, mDst, paint);
-    }
-}
diff --git a/src/com/android/launcher3/graphics/OverviewScrim.java b/src/com/android/launcher3/graphics/OverviewScrim.java
index 53303db..7aadb96 100644
--- a/src/com/android/launcher3/graphics/OverviewScrim.java
+++ b/src/com/android/launcher3/graphics/OverviewScrim.java
@@ -25,6 +25,10 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.R;
+import com.android.launcher3.uioverrides.WallpaperColorInfo;
+import com.android.launcher3.util.Themes;
+
 /**
  * View scrim which draws behind overview (recent apps).
  */
@@ -52,7 +56,7 @@
     public OverviewScrim(View view) {
         super(view);
 
-        onExtractedColorsChanged(mWallpaperColorInfo);
+        mScrimColor = Themes.getAttrColor(view.getContext(), R.attr.allAppsScrimColor);
     }
 
     /**
@@ -62,6 +66,13 @@
         mStableScrimmedView = mCurrentScrimmedView = mLauncher.getOverviewPanel();
     }
 
+    /**
+     * @param view The view we want the scrim to be behind
+     */
+    public void updateStableScrimmedView(View view) {
+        mStableScrimmedView = view;
+    }
+
     public void updateCurrentScrimmedView(ViewGroup root) {
         // Find the lowest view that is at or above the view we want to show the scrim behind.
         mCurrentScrimmedView = mStableScrimmedView;
@@ -74,6 +85,11 @@
         }
     }
 
+    @Override
+    public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
+        // No super, don't respond to wallpaper colors, follow device ones instead
+    }
+
     /**
      * @return The view to draw the scrim behind, or null if all visible views should be scrimmed.
      */
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java
index 70d1b48..e391d37 100644
--- a/src/com/android/launcher3/model/FirstScreenBroadcast.java
+++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.model;
 
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
 import static android.os.Process.myUserHandle;
 
 import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle;
@@ -140,7 +142,7 @@
                 .putStringArrayListExtra(HOTSEAT_ITEM_EXTRA, new ArrayList<>(hotseatItems))
                 .putStringArrayListExtra(WIDGET_ITEM_EXTRA, new ArrayList<>(widgetItems))
                 .putExtra(VERIFICATION_TOKEN_EXTRA, PendingIntent.getActivity(context, 0,
-                        new Intent(), PendingIntent.FLAG_ONE_SHOT)));
+                        new Intent(), FLAG_ONE_SHOT | FLAG_IMMUTABLE)));
     }
 
     private static String getPackageName(ItemInfo info) {
diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java
index 80eeb22..d27d8c7 100644
--- a/src/com/android/launcher3/notification/NotificationInfo.java
+++ b/src/com/android/launcher3/notification/NotificationInfo.java
@@ -22,7 +22,6 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
@@ -86,9 +85,8 @@
             mIsIconLarge = true;
         }
         if (mIconDrawable == null) {
-            mIconDrawable = new BitmapDrawable(context.getResources(), LauncherAppState
-                    .getInstance(context).getIconCache()
-                    .getDefaultIcon(statusBarNotification.getUser()).icon);
+            mIconDrawable = LauncherAppState.getInstance(context).getIconCache()
+                    .getDefaultIcon(statusBarNotification.getUser()).newIcon(context);
         }
         intent = notification.contentIntent;
         autoCancel = (notification.flags & Notification.FLAG_AUTO_CANCEL) != 0;
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 2905dc3..e58f5fa 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -16,9 +16,9 @@
 
 package com.android.launcher3.notification;
 
-import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
 
 import android.annotation.TargetApi;
 import android.app.Notification;
@@ -37,8 +37,8 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
-import com.android.launcher3.util.SettingsCache;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.SettingsCache;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -213,7 +213,7 @@
         mNotificationSettingsChangedListener = this::onNotificationSettingsChanged;
         mSettingsCache.register(NOTIFICATION_BADGING_URI,
                 mNotificationSettingsChangedListener);
-        mSettingsCache.dispatchOnChange(NOTIFICATION_BADGING_URI);
+        onNotificationSettingsChanged(mSettingsCache.getValue(NOTIFICATION_BADGING_URI));
 
         onNotificationFullRefresh();
     }
diff --git a/src/com/android/launcher3/settings/NotificationDotsPreference.java b/src/com/android/launcher3/settings/NotificationDotsPreference.java
index a354169..afcf882 100644
--- a/src/com/android/launcher3/settings/NotificationDotsPreference.java
+++ b/src/com/android/launcher3/settings/NotificationDotsPreference.java
@@ -17,6 +17,8 @@
 
 import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
 import static com.android.launcher3.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGS;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -24,6 +26,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.database.ContentObserver;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.util.AttributeSet;
@@ -49,6 +52,14 @@
     /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
     private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
 
+    private final ContentObserver mListenerListObserver =
+            new ContentObserver(MAIN_EXECUTOR.getHandler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            updateUI();
+        }
+    };
+
     public NotificationDotsPreference(
             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
@@ -66,6 +77,29 @@
         super(context);
     }
 
+    @Override
+    public void onAttached() {
+        super.onAttached();
+        SettingsCache.INSTANCE.get(getContext()).register(NOTIFICATION_BADGING_URI, this);
+        getContext().getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(NOTIFICATION_ENABLED_LISTENERS),
+                false, mListenerListObserver);
+        updateUI();
+    }
+
+    private void updateUI() {
+        onSettingsChanged(SettingsCache.INSTANCE.get(getContext())
+                .getValue(NOTIFICATION_BADGING_URI));
+    }
+
+    @Override
+    public void onDetached() {
+        super.onDetached();
+        SettingsCache.INSTANCE.get(getContext()).unregister(NOTIFICATION_BADGING_URI, this);
+        getContext().getContentResolver().unregisterContentObserver(mListenerListObserver);
+
+    }
+
     private void setWidgetFrameVisible(boolean isVisible) {
         if (mWidgetFrameVisible != isVisible) {
             mWidgetFrameVisible = isVisible;
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index f03065c..5b42ac7 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -18,8 +18,6 @@
 
 import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
 
-import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
-import static com.android.launcher3.util.SettingsCache.NOTIFICATION_ENABLED_LISTENERS;
 import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
 import static com.android.launcher3.states.RotationHelper.getAllowRotationDefaultValue;
 
@@ -45,7 +43,6 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.WidgetsModel;
-import com.android.launcher3.util.SettingsCache;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 
 /**
@@ -124,11 +121,8 @@
      */
     public static class LauncherSettingsFragment extends PreferenceFragmentCompat {
 
-        private SettingsCache mSettingsCache;
-
         private String mHighLightKey;
         private boolean mPreferenceHighlighted = false;
-        private NotificationDotsPreference mNotificationSettingsChangedListener;
         private Preference mDeveloperOptionPref;
 
         @Override
@@ -172,22 +166,7 @@
         protected boolean initPreference(Preference preference) {
             switch (preference.getKey()) {
                 case NOTIFICATION_DOTS_PREFERENCE_KEY:
-                    if (WidgetsModel.GO_DISABLE_NOTIFICATION_DOTS) {
-                        return false;
-                    }
-
-                    // Listen to system notification dot settings while this UI is active.
-                    mSettingsCache = SettingsCache.INSTANCE.get(getActivity());
-                    mNotificationSettingsChangedListener =
-                            ((NotificationDotsPreference) preference);
-                    mSettingsCache.register(NOTIFICATION_BADGING_URI,
-                            (NotificationDotsPreference) mNotificationSettingsChangedListener);
-                    // Also listen if notification permission changes
-                    mSettingsCache.register(NOTIFICATION_ENABLED_LISTENERS,
-                            mNotificationSettingsChangedListener);
-                    mSettingsCache.dispatchOnChange(NOTIFICATION_BADGING_URI);
-                    mSettingsCache.dispatchOnChange(NOTIFICATION_ENABLED_LISTENERS);
-                    return true;
+                    return !WidgetsModel.GO_DISABLE_NOTIFICATION_DOTS;
 
                 case ALLOW_ROTATION_PREFERENCE_KEY:
                     if (getResources().getBoolean(R.bool.allow_rotation)) {
@@ -269,16 +248,5 @@
                 }
             });
         }
-
-        @Override
-        public void onDestroy() {
-            if (mSettingsCache != null) {
-                mSettingsCache.unregister(NOTIFICATION_BADGING_URI,
-                        mNotificationSettingsChangedListener);
-                mSettingsCache.unregister(NOTIFICATION_ENABLED_LISTENERS,
-                        mNotificationSettingsChangedListener);
-            }
-            super.onDestroy();
-        }
     }
 }
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 51767e7..14ef2dc 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -18,7 +18,7 @@
 
 import static android.animation.ValueAnimator.areAnimatorsEnabled;
 
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
 
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
@@ -289,14 +289,14 @@
      */
     public AnimatorPlaybackController createAnimationToNewWorkspace(
             STATE_TYPE state, long duration) {
-        return createAnimationToNewWorkspace(state, duration, ANIM_ALL_COMPONENTS);
+        return createAnimationToNewWorkspace(state, duration, 0 /* animFlags */);
     }
 
     public AnimatorPlaybackController createAnimationToNewWorkspace(
-            STATE_TYPE state, long duration, @AnimationFlags int animComponents) {
+            STATE_TYPE state, long duration, @AnimationFlags int animFlags) {
         StateAnimationConfig config = new StateAnimationConfig();
         config.duration = duration;
-        config.animFlags = animComponents;
+        config.animFlags = animFlags;
         return createAnimationToNewWorkspace(state, config);
     }
 
@@ -312,7 +312,7 @@
 
     private PendingAnimation createAnimationToNewWorkspaceInternal(final STATE_TYPE state) {
         PendingAnimation builder = new PendingAnimation(mConfig.duration);
-        if (mConfig.getAnimComponents() != 0) {
+        if (!mConfig.hasAnimationFlag(SKIP_ALL_ANIMATIONS)) {
             for (StateHandler handler : getStateHandlers()) {
                 handler.setStateWithAnimation(state, mConfig, builder);
             }
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index eb2c551..76f89bc 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -31,7 +31,11 @@
             | FLAG_HAS_SYS_UI_SCRIM;
 
     public HintState(int id) {
-        super(id, LAUNCHER_STATE_HOME, STATE_FLAGS);
+        this(id, LAUNCHER_STATE_HOME);
+    }
+
+    public HintState(int id, int statsLogOrdinal) {
+        super(id, statsLogOrdinal, STATE_FLAGS);
     }
 
     @Override
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index cd74390..8e7dcc0 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -27,32 +27,21 @@
  */
 public class StateAnimationConfig {
 
-    // We separate the state animations into "atomic" and "non-atomic" components. The atomic
-    // components may be run atomically - that is, all at once, instead of user-controlled. However,
-    // atomic components are not restricted to this purpose; they can be user-controlled alongside
-    // non atomic components as well. Note that each gesture model has exactly one atomic component,
-    // PLAY_ATOMIC_OVERVIEW_SCALE *or* PLAY_ATOMIC_OVERVIEW_PEEK.
     @IntDef(flag = true, value = {
-            PLAY_NON_ATOMIC,
-            PLAY_ATOMIC_OVERVIEW_SCALE,
-            PLAY_ATOMIC_OVERVIEW_PEEK,
+            SKIP_ALL_ANIMATIONS,
             SKIP_OVERVIEW,
             SKIP_DEPTH_CONTROLLER,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AnimationFlags {}
-    public static final int PLAY_NON_ATOMIC = 1 << 0;
-    public static final int PLAY_ATOMIC_OVERVIEW_SCALE = 1 << 1;
-    public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2;
-    public static final int SKIP_OVERVIEW = 1 << 3;
-    public static final int SKIP_DEPTH_CONTROLLER = 1 << 4;
+    public static final int SKIP_ALL_ANIMATIONS = 1 << 0;
+    public static final int SKIP_OVERVIEW = 1 << 1;
+    public static final int SKIP_DEPTH_CONTROLLER = 1 << 2;
 
     public long duration;
     public boolean userControlled;
-    public @AnimationFlags int animFlags = ANIM_ALL_COMPONENTS;
+    public @AnimationFlags int animFlags = 0;
 
-    public static final int ANIM_ALL_COMPONENTS = PLAY_NON_ATOMIC | PLAY_ATOMIC_OVERVIEW_SCALE
-            | PLAY_ATOMIC_OVERVIEW_PEEK;
 
     // Various types of animation state transition
     @IntDef(value = {
@@ -127,37 +116,9 @@
     }
 
     /**
-     * @return Whether Overview is scaling as part of this animation. If this is the only
-     * component (i.e. NON_ATOMIC_COMPONENT isn't included), then this scaling is happening
-     * atomically, rather than being part of a normal state animation. StateHandlers can use
-     * this to designate part of their animation that should scale with Overview.
-     */
-    public boolean playAtomicOverviewScaleComponent() {
-        return hasAnimationFlag(StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE);
-    }
-
-    /**
-     * @return Whether this animation will play atomically at the same time as a different,
-     * user-controlled state transition. StateHandlers, which contribute to both animations, can
-     * use this to avoid animating the same properties in both animations, since they'd conflict
-     * with one another.
-     */
-    public boolean onlyPlayAtomicComponent() {
-        return getAnimComponents() == StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE
-                || getAnimComponents() == StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
-    }
-
-    /**
      * Returns true if the config and any of the provided component flags
      */
     public boolean hasAnimationFlag(@AnimationFlags int a) {
         return (animFlags & a) != 0;
     }
-
-    /**
-     * @return Only the flags that determine which animation components to play.
-     */
-    public @AnimationFlags int getAnimComponents() {
-        return animFlags & StateAnimationConfig.ANIM_ALL_COMPONENTS;
-    }
 }
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index f34bff6..943d129 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -32,7 +32,8 @@
     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 int OVERVIEW_SPLIT_SELECT_ORDINAL = 8;
+    public static final int HINT_STATE_TWO_BUTTON_ORDINAL = 8;
+    public static final int OVERVIEW_SPLIT_SELECT_ORDINAL = 9;
     public static final String TAPL_EVENTS_TAG = "TaplEvents";
     public static final String SEQUENCE_MAIN = "Main";
     public static final String SEQUENCE_TIS = "TIS";
@@ -56,6 +57,8 @@
                 return "Background";
             case HINT_STATE_ORDINAL:
                 return "Hint";
+            case HINT_STATE_TWO_BUTTON_ORDINAL:
+                return "Hint2Button";
             case OVERVIEW_SPLIT_SELECT_ORDINAL:
                 return "OverviewSplitSelect";
             default:
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 516fc74..a437293 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -27,30 +27,20 @@
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEDOWN;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEUP;
-import static com.android.launcher3.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.DisplayController.getSingleFrameMs;
 
-import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
-import android.os.SystemClock;
-import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
 import com.android.launcher3.util.FlingBlockCheck;
 import com.android.launcher3.util.TouchController;
 
@@ -60,13 +50,6 @@
 public abstract class AbstractStateChangeTouchController
         implements TouchController, SingleAxisSwipeDetector.Listener {
 
-    /**
-     * Play an atomic recents animation when the progress from NORMAL to OVERVIEW reaches this.
-     * TODO: Remove the atomic animation altogether and just go to OVERVIEW directly (b/175137718).
-     */
-    public static final float ATOMIC_OVERVIEW_ANIM_THRESHOLD = 1f;
-    protected final long ATOMIC_DURATION = getAtomicDuration();
-
     protected final Launcher mLauncher;
     protected final SingleAxisSwipeDetector mDetector;
     protected final SingleAxisSwipeDetector.Direction mSwipeDirection;
@@ -89,23 +72,7 @@
     private float mProgressMultiplier;
     private float mDisplacementShift;
     private boolean mCanBlockFling;
-    private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
-
-    protected AnimatorSet mAtomicAnim;
-    // True if we want to resume playing atomic components when mAtomicAnim completes.
-    private boolean mScheduleResumeAtomicComponent;
-    private AutoPlayAtomicAnimationInfo mAtomicAnimAutoPlayInfo;
-
-    private boolean mPassedOverviewAtomicThreshold;
-    // mAtomicAnim plays the atomic components of the state animations when we pass the threshold.
-    // However, if we reinit to transition to a new state (e.g. OVERVIEW -> ALL_APPS) before the
-    // atomic animation finishes, we only control the non-atomic components so that we don't
-    // interfere with the atomic animation. When the atomic animation ends, we start controlling
-    // the atomic components as well, using this controller.
-    private AnimatorPlaybackController mAtomicComponentsController;
-    private LauncherState mAtomicComponentsTargetState = NORMAL;
-
-    private float mAtomicComponentsStartProgress;
+    private final FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
 
     public AbstractStateChangeTouchController(Launcher l, SingleAxisSwipeDetector.Direction dir) {
         mLauncher = l;
@@ -113,10 +80,6 @@
         mSwipeDirection = dir;
     }
 
-    protected long getAtomicDuration() {
-        return 200;
-    }
-
     protected abstract boolean canInterceptTouch(MotionEvent ev);
 
     @Override
@@ -182,7 +145,7 @@
     protected abstract LauncherState getTargetState(LauncherState fromState,
             boolean isDragTowardPositive);
 
-    protected abstract float initCurrentAnimation(@AnimationFlags int animComponents);
+    protected abstract float initCurrentAnimation();
 
     private boolean reinitCurrentAnimation(boolean reachedToState, boolean isDragTowardPositive) {
         LauncherState newFromState = mFromState == null ? mLauncher.getStateManager().getState()
@@ -199,28 +162,10 @@
         mToState = newToState;
 
         mStartProgress = 0;
-        mPassedOverviewAtomicThreshold = false;
         if (mCurrentAnimation != null) {
             mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
         }
-        int animComponents = goingBetweenNormalAndOverview(mFromState, mToState)
-                ? PLAY_NON_ATOMIC : ANIM_ALL_COMPONENTS;
-        mScheduleResumeAtomicComponent = false;
-        if (mAtomicAnim != null) {
-            animComponents = PLAY_NON_ATOMIC;
-            // Control the non-atomic components until the atomic animation finishes, then control
-            // the atomic components as well.
-            mScheduleResumeAtomicComponent = true;
-        }
-        if (goingBetweenNormalAndOverview(mFromState, mToState)
-                || mAtomicComponentsTargetState != mToState) {
-            cancelAtomicComponentsController();
-        }
-
-        if (mAtomicComponentsController != null) {
-            animComponents &= ~PLAY_ATOMIC_OVERVIEW_SCALE;
-        }
-        mProgressMultiplier = initCurrentAnimation(animComponents);
+        mProgressMultiplier = initCurrentAnimation();
         mCurrentAnimation.dispatchOnStart();
         return true;
     }
@@ -231,13 +176,6 @@
     protected void onReachedFinalState(LauncherState newToState) {
     }
 
-    protected boolean goingBetweenNormalAndOverview(LauncherState fromState,
-            LauncherState toState) {
-        return (fromState == NORMAL || fromState == OVERVIEW)
-                && (toState == NORMAL || toState == OVERVIEW)
-                && mGoingBetweenStates;
-    }
-
     @Override
     public void onDragStart(boolean start, float startDisplacement) {
         mStartState = mLauncher.getStateManager().getState();
@@ -252,11 +190,6 @@
         } else {
             mCurrentAnimation.pause();
             mStartProgress = mCurrentAnimation.getProgressFraction();
-
-            mAtomicAnimAutoPlayInfo = null;
-            if (mAtomicComponentsController != null) {
-                mAtomicComponentsController.pause();
-            }
         }
         mCanBlockFling = mFromState == NORMAL;
         mFlingBlockCheck.unblockFling();
@@ -310,69 +243,6 @@
             return;
         }
         mCurrentAnimation.setPlayFraction(fraction);
-        if (mAtomicComponentsController != null) {
-            // Make sure we don't divide by 0, and have at least a small runway.
-            float start = Math.min(mAtomicComponentsStartProgress, 0.9f);
-            mAtomicComponentsController.setPlayFraction((fraction - start) / (1 - start));
-        }
-        maybeUpdateAtomicAnim(mFromState, mToState, fraction);
-    }
-
-    /**
-     * When going between normal and overview states, see if we passed the overview threshold and
-     * play the appropriate atomic animation if so.
-     */
-    private void maybeUpdateAtomicAnim(LauncherState fromState, LauncherState toState,
-            float progress) {
-        if (!goingBetweenNormalAndOverview(fromState, toState)) {
-            return;
-        }
-        boolean passedThreshold = progress >= ATOMIC_OVERVIEW_ANIM_THRESHOLD;
-        if (passedThreshold != mPassedOverviewAtomicThreshold) {
-            LauncherState atomicFromState = passedThreshold ? fromState: toState;
-            LauncherState atomicToState = passedThreshold ? toState : fromState;
-            mPassedOverviewAtomicThreshold = passedThreshold;
-            if (mAtomicAnim != null) {
-                mAtomicAnim.cancel();
-            }
-            mAtomicAnim = createAtomicAnimForState(atomicFromState, atomicToState, ATOMIC_DURATION);
-            mAtomicAnim.addListener(new AnimationSuccessListener() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    super.onAnimationEnd(animation);
-                    mAtomicAnim = null;
-                    mScheduleResumeAtomicComponent = false;
-                }
-
-                @Override
-                public void onAnimationSuccess(Animator animator) {
-                    if (!mScheduleResumeAtomicComponent) {
-                        return;
-                    }
-                    cancelAtomicComponentsController();
-
-                    if (mCurrentAnimation != null) {
-                        mAtomicComponentsStartProgress = mCurrentAnimation.getProgressFraction();
-                        long duration = (long) (getShiftRange() * 2);
-                        mAtomicComponentsController = AnimatorPlaybackController.wrap(
-                                createAtomicAnimForState(mFromState, mToState, duration), duration);
-                        mAtomicComponentsController.dispatchOnStart();
-                        mAtomicComponentsTargetState = mToState;
-                        maybeAutoPlayAtomicComponentsAnim();
-                    }
-                }
-            });
-            mAtomicAnim.start();
-            mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
-        }
-    }
-
-    private AnimatorSet createAtomicAnimForState(LauncherState fromState, LauncherState targetState,
-            long duration) {
-        StateAnimationConfig config = getConfigForStates(fromState, targetState);
-        config.animFlags = PLAY_ATOMIC_OVERVIEW_SCALE;
-        config.duration = duration;
-        return mLauncher.getStateManager().createAtomicAnimation(fromState, targetState, config);
     }
 
     /**
@@ -447,63 +317,18 @@
                         Math.min(progress, 1) - endProgress) * durationMultiplier;
             }
         }
-
+        if (targetState != mStartState) {
+            logReachedState(targetState);
+        }
         mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState));
         ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
         anim.setFloatValues(startProgress, endProgress);
-        maybeUpdateAtomicAnim(mFromState, targetState, targetState == mToState ? 1f : 0f);
-        updateSwipeCompleteAnimation(anim, Math.max(duration, getRemainingAtomicDuration()),
-                targetState, velocity, fling);
+        updateSwipeCompleteAnimation(anim, duration, targetState, velocity, fling);
         mCurrentAnimation.dispatchOnStart();
         if (fling && targetState == LauncherState.ALL_APPS && !UNSTABLE_SPRINGS.get()) {
             mLauncher.getAppsView().addSpringFromFlingUpdateListener(anim, velocity);
         }
         anim.start();
-        mAtomicAnimAutoPlayInfo = new AutoPlayAtomicAnimationInfo(endProgress, anim.getDuration());
-        maybeAutoPlayAtomicComponentsAnim();
-    }
-
-    /**
-     * Animates the atomic components from the current progress to the final progress.
-     *
-     * Note that this only applies when we are controlling the atomic components separately from
-     * the non-atomic components, which only happens if we reinit before the atomic animation
-     * finishes.
-     */
-    private void maybeAutoPlayAtomicComponentsAnim() {
-        if (mAtomicComponentsController == null || mAtomicAnimAutoPlayInfo == null) {
-            return;
-        }
-
-        final AnimatorPlaybackController controller = mAtomicComponentsController;
-        ValueAnimator atomicAnim = controller.getAnimationPlayer();
-        atomicAnim.setFloatValues(controller.getProgressFraction(),
-                mAtomicAnimAutoPlayInfo.toProgress);
-        long duration = mAtomicAnimAutoPlayInfo.endTime - SystemClock.elapsedRealtime();
-        mAtomicAnimAutoPlayInfo = null;
-        if (duration <= 0) {
-            atomicAnim.start();
-            atomicAnim.end();
-            mAtomicComponentsController = null;
-        } else {
-            atomicAnim.setDuration(duration);
-            atomicAnim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (mAtomicComponentsController == controller) {
-                        mAtomicComponentsController = null;
-                    }
-                }
-            });
-            atomicAnim.start();
-        }
-    }
-
-    private long getRemainingAtomicDuration() {
-        if (mAtomicAnim == null) {
-            return 0;
-        }
-        return mAtomicAnim.getTotalDuration() - mAtomicAnim.getCurrentPlayTime();
     }
 
     protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
@@ -513,10 +338,6 @@
     }
 
     protected void onSwipeInteractionCompleted(LauncherState targetState) {
-        if (mAtomicComponentsController != null) {
-            mAtomicComponentsController.getAnimationPlayer().end();
-            mAtomicComponentsController = null;
-        }
         onReachedFinalState(mToState);
         clearState();
         boolean shouldGoToTargetState = mGoingBetweenStates || (mToState != targetState);
@@ -526,9 +347,6 @@
     }
 
     protected void goToTargetState(LauncherState targetState) {
-        if (targetState != mStartState) {
-            logReachedState(targetState);
-        }
         if (!mLauncher.isInState(targetState)) {
             // If we're already in the target state, don't jump to it at the end of the animation in
             // case the user started interacting with it before the animation finished.
@@ -556,37 +374,12 @@
 
     protected void clearState() {
         cancelAnimationControllers();
-        if (mAtomicAnim != null) {
-            mAtomicAnim.cancel();
-            mAtomicAnim = null;
-        }
         mGoingBetweenStates = true;
-        mScheduleResumeAtomicComponent = false;
         mDetector.finishedScrolling();
         mDetector.setDetectableScrollConditions(0, false);
     }
 
     private void cancelAnimationControllers() {
         mCurrentAnimation = null;
-        cancelAtomicComponentsController();
-    }
-
-    private void cancelAtomicComponentsController() {
-        if (mAtomicComponentsController != null) {
-            mAtomicComponentsController.getAnimationPlayer().cancel();
-            mAtomicComponentsController = null;
-        }
-        mAtomicAnimAutoPlayInfo = null;
-    }
-
-    private static class AutoPlayAtomicAnimationInfo {
-
-        public final float toProgress;
-        public final long endTime;
-
-        AutoPlayAtomicAnimationInfo(float toProgress, long duration) {
-            this.toProgress = toProgress;
-            this.endTime = duration + SystemClock.elapsedRealtime();
-        }
     }
 }
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index f9dcf2d..ab2652a 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -23,24 +23,18 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
 
 /**
  * TouchController to switch between NORMAL and ALL_APPS state.
  */
 public class AllAppsSwipeController extends AbstractStateChangeTouchController {
 
-    private MotionEvent mTouchDownEvent;
-
     public AllAppsSwipeController(Launcher l) {
         super(l, SingleAxisSwipeDetector.VERTICAL);
     }
 
     @Override
     protected boolean canInterceptTouch(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            mTouchDownEvent = ev;
-        }
         if (mCurrentAnimation != null) {
             // If we are already animating from a previous state, we can intercept.
             return true;
@@ -69,11 +63,11 @@
     }
 
     @Override
-    protected float initCurrentAnimation(@AnimationFlags int animComponents) {
+    protected float initCurrentAnimation() {
         float range = getShiftRange();
         long maxAccuracy = (long) (2 * range);
         mCurrentAnimation = mLauncher.getStateManager()
-                .createAnimationToNewWorkspace(mToState, maxAccuracy, animComponents);
+                .createAnimationToNewWorkspace(mToState, maxAccuracy);
         float startVerticalShift = mFromState.getVerticalProgress(mLauncher) * range;
         float endVerticalShift = mToState.getVerticalProgress(mLauncher) * range;
         float totalShift = endVerticalShift - startVerticalShift;
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 19dfe15..dd5611e 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -24,7 +24,6 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_SIDE;
 
 import android.content.res.Resources;
 import android.graphics.PointF;
@@ -45,7 +44,7 @@
 import com.android.launcher3.util.OverScroller;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 
-import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 public class LandscapePagedViewHandler implements PagedOrientationHandler {
@@ -308,15 +307,10 @@
 
     @Override
     public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
-        List<SplitPositionOption> options = new ArrayList<>(2);
-        // Add left/right options where left => position top, right => position bottom
-        options.add(new SplitPositionOption(
+        // Add "left" side of phone which is actually the top
+        return Collections.singletonList(new SplitPositionOption(
                 R.drawable.ic_split_screen, R.string.split_screen_position_left,
                 STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
-        options.add(new SplitPositionOption(
-                R.drawable.ic_split_screen, R.string.split_screen_position_right,
-                STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_SIDE));
-        return options;
     }
 
     @Override
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 29be627..2ca0340 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -306,16 +306,17 @@
 
     @Override
     public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
-        List<SplitPositionOption> options = new ArrayList<>(2);
+        List<SplitPositionOption> options = new ArrayList<>(1);
         // TODO: Add in correct icons
-        if (dp.isLandscape) { // or seascape
+        if (dp.isSeascape()) { // or seascape
             // Add left/right options
             options.add(new SplitPositionOption(
+                    R.drawable.ic_split_screen, R.string.split_screen_position_right,
+                    STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
+        } else if (dp.isLandscape) {
+            options.add(new SplitPositionOption(
                     R.drawable.ic_split_screen, R.string.split_screen_position_left,
                     STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
-            options.add(new SplitPositionOption(
-                    R.drawable.ic_split_screen, R.string.split_screen_position_right,
-                    STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_SIDE));
         } else {
             // Only add top option
             options.add(new SplitPositionOption(
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index b5252f7..bd6e31b 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -20,7 +20,6 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_SIDE;
 
 import android.content.res.Resources;
 import android.graphics.PointF;
@@ -33,7 +32,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 
-import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
@@ -96,15 +95,10 @@
 
     @Override
     public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
-        List<SplitPositionOption> options = new ArrayList<>(2);
-        // Add left/right options where left => position bottom, right => position top
-        options.add(new SplitPositionOption(
-                R.drawable.ic_split_screen, R.string.split_screen_position_left,
-                STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_SIDE));
-        options.add(new SplitPositionOption(
+        // Add "right" option which is actually the top
+        return Collections.singletonList(new SplitPositionOption(
                 R.drawable.ic_split_screen, R.string.split_screen_position_right,
                 STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
-        return options;
     }
 
     /* ---------- The following are only used by TaskViewTouchHandler. ---------- */
diff --git a/src/com/android/launcher3/util/SettingsCache.java b/src/com/android/launcher3/util/SettingsCache.java
index 22b4d38..10611c7 100644
--- a/src/com/android/launcher3/util/SettingsCache.java
+++ b/src/com/android/launcher3/util/SettingsCache.java
@@ -39,12 +39,11 @@
  * {@link #unregister(Uri, OnChangeListener)} methods.
  *
  * This can be used as a normal cache without any listeners as well via the
- * {@link #getValue(Uri, int)} and {@link #dispatchOnChange(Uri)} to update (and subsequently call
+ * {@link #getValue(Uri, int)} and {@link #onChange)} to update (and subsequently call
  * get)
  *
  * The cache will be invalidated/updated through the normal
  * {@link ContentObserver#onChange(boolean)} calls
- * or can be force updated by calling {@link #dispatchOnChange(Uri)}.
  *
  * Cache will also be updated if a key queried is missing (even if it has no listeners registered).
  */
@@ -58,9 +57,6 @@
     /** Hidden field Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED */
     public static final String ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED =
             "swipe_bottom_to_notification_enabled";
-    /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
-    public static final Uri NOTIFICATION_ENABLED_LISTENERS =
-            Settings.Secure.getUriFor("enabled_notification_listeners");
     public static final Uri ROTATION_SETTING_URI =
             Settings.System.getUriFor(ACCELEROMETER_ROTATION);
 
@@ -103,6 +99,14 @@
      * Returns the value for this classes key from the cache. If not in cache, will call
      * {@link #updateValue(Uri, int)} to fetch.
      */
+    public boolean getValue(Uri keySetting) {
+        return getValue(keySetting, 1);
+    }
+
+    /**
+     * Returns the value for this classes key from the cache. If not in cache, will call
+     * {@link #updateValue(Uri, int)} to fetch.
+     */
     public boolean getValue(Uri keySetting, int defaultValue) {
         if (mKeyCache.containsKey(keySetting)) {
             return mKeyCache.get(keySetting);
@@ -140,14 +144,6 @@
     }
 
     /**
-     * Force update a change for a given URI and have all listeners for that URI receive callbacks
-     * even if the value is unchanged.
-     */
-    public void dispatchOnChange(Uri uri) {
-        onChange(true, uri);
-    }
-
-    /**
      * Call to stop receiving updates on the given {@param listener}.
      * This Uri/Listener pair must correspond to the same pair called with for
      * {@link #register(Uri, OnChangeListener)}
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index e08f881..f79313f 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -216,7 +216,7 @@
         return mLauncher.getDragLayer();
     }
 
-    protected static View createColorScrim(Context context, int bgColor) {
+    protected View createColorScrim(Context context, int bgColor) {
         View view = new View(context);
         view.forceHasOverlappingRendering(false);
         view.setBackgroundColor(bgColor);
diff --git a/src/com/android/launcher3/views/AccessibilityActionsView.java b/src/com/android/launcher3/views/AccessibilityActionsView.java
index 0eacaa3..1d136c3 100644
--- a/src/com/android/launcher3/views/AccessibilityActionsView.java
+++ b/src/com/android/launcher3/views/AccessibilityActionsView.java
@@ -67,7 +67,7 @@
         info.addAction(new AccessibilityAction(
                 R.string.all_apps_button_label, l.getText(R.string.all_apps_button_label)));
         for (OptionItem item : OptionsPopupView.getOptions(l)) {
-            info.addAction(new AccessibilityAction(item.labelRes, l.getText(item.labelRes)));
+            info.addAction(new AccessibilityAction(item.labelRes, item.label));
         }
         return info;
     }
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 9a2db10..98cc876 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -26,6 +26,7 @@
 import android.content.Intent;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
@@ -37,6 +38,7 @@
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.core.content.ContextCompat;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherSettings;
@@ -62,6 +64,7 @@
 
     private final ArrayMap<View, OptionItem> mItemMap = new ArrayMap<>();
     private RectF mTargetRect;
+    private boolean mShouldAddArrow;
 
     public OptionsPopupView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -113,9 +116,13 @@
         return (type & TYPE_OPTIONS_POPUP) != 0;
     }
 
+    public void setShouldAddArrow(boolean shouldAddArrow) {
+        mShouldAddArrow = shouldAddArrow;
+    }
+
     @Override
     protected boolean shouldAddArrow() {
-        return false;
+        return mShouldAddArrow;
     }
 
     @Override
@@ -124,16 +131,17 @@
     }
 
     public static OptionsPopupView show(
-            Launcher launcher, RectF targetRect, List<OptionItem> items) {
+            Launcher launcher, RectF targetRect, List<OptionItem> items, boolean shouldAddArrow) {
         OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater()
                 .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false);
         popup.mTargetRect = targetRect;
+        popup.setShouldAddArrow(shouldAddArrow);
 
         for (OptionItem item : items) {
             DeepShortcutView view =
                     (DeepShortcutView) popup.inflateAndAdd(R.layout.system_shortcut, popup);
-            view.getIconView().setBackgroundResource(item.iconRes);
-            view.getBubbleText().setText(item.labelRes);
+            view.getIconView().setBackgroundDrawable(item.icon);
+            view.getBubbleText().setText(item.label);
             view.setOnClickListener(popup);
             view.setOnLongClickListener(popup);
             popup.mItemMap.put(view, item);
@@ -154,7 +162,7 @@
             y = launcher.getDragLayer().getHeight() / 2;
         }
         RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
-        show(launcher, target, getOptions(launcher));
+        show(launcher, target, getOptions(launcher), false);
     }
 
     /**
@@ -162,11 +170,15 @@
      */
     public static ArrayList<OptionItem> getOptions(Launcher launcher) {
         ArrayList<OptionItem> options = new ArrayList<>();
-        options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting,
+        options.add(new OptionItem(launcher,
+                R.string.settings_button_text,
+                R.drawable.ic_setting,
                 LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS,
                 OptionsPopupView::startSettings));
         if (!WidgetsModel.GO_DISABLE_WIDGETS) {
-            options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
+            options.add(new OptionItem(launcher,
+                    R.string.widget_button_text,
+                    R.drawable.ic_widget,
                     LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS,
                     OptionsPopupView::onWidgetsClicked));
         }
@@ -174,7 +186,9 @@
                 R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text;
         int resDrawable = Utilities.existsStyleWallpapers(launcher) ?
                 R.drawable.ic_palette : R.drawable.ic_wallpaper;
-        options.add(new OptionItem(resString, resDrawable,
+        options.add(new OptionItem(launcher,
+                resString,
+                resDrawable,
                 IGNORE,
                 OptionsPopupView::startWallpaperPicker));
         return options;
@@ -241,15 +255,28 @@
 
     public static class OptionItem {
 
+        // Used to create AccessibilityNodeInfo in AccessibilityActionsView.java.
         public final int labelRes;
-        public final int iconRes;
+
+        public final CharSequence label;
+        public final Drawable icon;
         public final EventEnum eventId;
         public final OnLongClickListener clickListener;
 
-        public OptionItem(int labelRes, int iconRes, EventEnum eventId,
-                OnLongClickListener clickListener) {
+        public OptionItem(Context context, int labelRes, int iconRes, EventEnum eventId,
+                          OnLongClickListener clickListener) {
             this.labelRes = labelRes;
-            this.iconRes = iconRes;
+            this.label = context.getText(labelRes);
+            this.icon = ContextCompat.getDrawable(context, iconRes);
+            this.eventId = eventId;
+            this.clickListener = clickListener;
+        }
+
+        public OptionItem(CharSequence label, Drawable icon, EventEnum eventId,
+                          OnLongClickListener clickListener) {
+            this.labelRes = 0;
+            this.label = label;
+            this.icon = icon;
             this.eventId = eventId;
             this.clickListener = clickListener;
         }
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 7f0765b..72926dd 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -40,6 +40,7 @@
  * Simple scrim which draws a flat color
  */
 public class ScrimView<T extends Launcher> extends View implements Insettable, OnChangeListener {
+    private static final float STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD = .1f;
 
     protected final T mLauncher;
     private final WallpaperColorInfo mWallpaperColorInfo;
@@ -117,7 +118,7 @@
     protected void updateSysUiColors() {
         // Use a light system UI (dark icons) if all apps is behind at least half of the
         // status bar.
-        boolean forceChange = mProgress <= 0.1f;
+        boolean forceChange = mProgress <= STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD;
         if (forceChange) {
             mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark);
         } else {
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index ad0a401..3e61e56 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -39,6 +39,7 @@
 import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.icons.RoundDrawableWrapper;
 import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
 
 /**
@@ -118,12 +119,12 @@
                         .addDragListener(new AppWidgetHostViewDragListener(launcher));
             }
             if (preview == null) {
-                FastBitmapDrawable p = new FastBitmapDrawable(
+                Drawable p = new FastBitmapDrawable(
                         app.getWidgetCache().generateWidgetPreview(launcher,
                                 createWidgetInfo.info, maxWidth, null,
                                 previewSizeBeforeScale).first);
                 if (RoundedCornerEnforcement.isRoundedCornerEnabled()) {
-                    p.setRoundedCornersRadius(mEnforcedRoundedCornersForWidget);
+                    p = new RoundDrawableWrapper(p, mEnforcedRoundedCornersForWidget);
                 }
                 preview = p;
             }
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index c11b68e..40b256b 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -46,6 +46,7 @@
 import com.android.launcher3.icons.BaseIconFactory;
 import com.android.launcher3.icons.BitmapRenderer;
 import com.android.launcher3.icons.FastBitmapDrawable;
+import com.android.launcher3.icons.RoundDrawableWrapper;
 import com.android.launcher3.model.WidgetItem;
 
 /**
@@ -248,8 +249,7 @@
 
     public void applyPreview(Bitmap bitmap) {
         FastBitmapDrawable drawable = new FastBitmapDrawable(bitmap);
-        drawable.setRoundedCornersRadius(mEnforcedCornerRadius);
-        applyPreview(drawable);
+        applyPreview(new RoundDrawableWrapper(drawable, mEnforcedCornerRadius));
     }
 
     private void applyPreview(Drawable drawable) {
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 72b1d22..d4e8f1f 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -512,7 +512,7 @@
     }
 
     protected boolean isInBackground(Launcher launcher) {
-        return !launcher.hasBeenResumed();
+        return launcher == null || !launcher.hasBeenResumed();
     }
 
     protected boolean isInState(Supplier<LauncherState> state) {
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src_disabled/WorkTabTest.java
similarity index 97%
rename from tests/src/com/android/launcher3/ui/WorkTabTest.java
rename to tests/src_disabled/WorkTabTest.java
index 919c89f..bfacc74 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src_disabled/WorkTabTest.java
@@ -42,6 +42,8 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.List;
@@ -89,7 +91,8 @@
         });
     }
 
-//    @Test
+    @Ignore("b/182844465")
+    @Test
     public void workTabExists() {
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -101,7 +104,8 @@
                 launcher -> launcher.getAppsView().isWorkTabVisible(), 60000);
     }
 
-//    @Test
+    @Ignore("b/182844465")
+    @Test
     public void toggleWorks() {
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -132,7 +136,8 @@
                 l -> l.getSystemService(UserManager.class).isQuietModeEnabled(workProfile));
     }
 
-//    @Test
+    @Ignore("b/182844465")
+    @Test
     public void testWorkEduFlow() {
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -175,7 +180,8 @@
         });
     }
 
-//    @Test
+    @Ignore("b/182844465")
+    @Test
     public void testWorkEduIntermittent() {
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index d317783..4a666b1 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -122,7 +122,9 @@
                     endY = startY - swipeLength;
                 } else {
                     startX = getSwipeStartX();
-                    endX = startX - swipeLength;
+                    // TODO(b/184059820) make horizontal swipe use swipe width not height, for the
+                    // moment just double the swipe length.
+                    endX = startX - swipeLength * 2;
                     startY = endY = mLauncher.getDevice().getDisplayHeight() / 2;
                 }