Merge "Overview - add the ability to color scrim task views." 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/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/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index e1456b1..6929b5d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -103,12 +103,11 @@
 
     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));
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 b269901..95a855a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -99,8 +99,7 @@
 
     @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
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index e70450d..65bbeea 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;
@@ -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/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 1af9685..b8f9452 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -49,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.
@@ -116,14 +122,14 @@
     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;
     }
 
@@ -135,7 +141,7 @@
             config = getNormalToAllAppsAnimation();
         } else if (fromState == ALL_APPS && toState == NORMAL) {
             config = getAllAppsToNormalAnimation();
-        }  else {
+        } else {
             config = new StateAnimationConfig();
         }
         return config;
@@ -198,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) {
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 0415009..3afffc1 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) {
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/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 03a0b4e..8962ec9 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -76,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/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 ff78995..d616f7c 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -45,12 +45,13 @@
     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 mScrollOffsetPrimary;
 
@@ -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();
     }
 
@@ -148,8 +149,11 @@
         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;
         }
@@ -157,8 +161,18 @@
         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();
     }
 
     /**
@@ -180,7 +194,8 @@
         PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
         orientationHandler.getPrimaryViewTranslate().set(this,
                 orientationHandler.getPrimaryValue(0f, getOriginalTranslationY())
-                        + mNormalTranslationPrimary + getGridTrans(mGridTranslationPrimary));
+                        + mNormalTranslationPrimary + getFullscreenTrans(
+                        mFullscreenTranslationPrimary) + getGridTrans(mGridTranslationPrimary));
     }
 
     private void applySecondaryTranslation() {
@@ -191,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/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 5ea3dea..b62a029 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,6 +439,8 @@
     protected int mRunningTaskId = -1;
     protected boolean mRunningTaskTileHidden;
     private Task mTmpRunningTask;
+    protected int mFocusedTaskId = -1;
+    private float mFocusedTaskRatio;
 
     private boolean mRunningTaskIconScaledDown = false;
 
@@ -542,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);
@@ -648,7 +654,6 @@
         mActionsView = actionsView;
         mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
         mSplitPlaceholderView = splitPlaceholderView;
-
     }
 
     public SplitPlaceholderView getSplitPlaceholder() {
@@ -1129,6 +1134,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(
@@ -1168,9 +1174,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);
     }
 
     /**
@@ -1211,6 +1239,8 @@
             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.
@@ -1226,11 +1256,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);
@@ -1249,6 +1304,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
@@ -1413,6 +1477,7 @@
         setCurrentTask(-1);
         mIgnoreResetTaskId = -1;
         mTaskListChangeId = -1;
+        mFocusedTaskId = -1;
 
         mRecentsAnimationController = null;
         mLiveTileParams.setTargetSet(null);
@@ -1439,6 +1504,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.
@@ -1530,6 +1606,11 @@
      */
     public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
         mCurrentGestureEndTarget = endTarget;
+        if (showAsGrid()) {
+            mFocusedTaskId = mRunningTaskId;
+            mFocusedTaskRatio =
+                    mLastComputedTaskSize.width() / (float) mLastComputedTaskSize.height();
+        }
     }
 
     /**
@@ -1550,8 +1631,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();
         }
 
@@ -1671,6 +1751,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);
     }
@@ -1696,8 +1783,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;
@@ -1720,15 +1811,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;
@@ -1745,8 +1844,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;
@@ -1804,8 +1902,6 @@
 
         mClearAllButton.setGridTranslationPrimary(
                 clearAllTotalTranslationX - gridTranslations[firstNonHomeTaskIndex]);
-        mClearAllButton.setGridTranslationSecondary(
-                boxLength - mTaskHeight / 2f + mRowSpacing / 2f);
         mClearAllButton.setGridScrollOffset(
                 mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left
                         : mLastComputedTaskSize.right - mLastComputedGridSize.right);
@@ -2082,24 +2178,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");
@@ -2267,13 +2364,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) {
@@ -2485,7 +2575,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);
@@ -2494,7 +2584,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);
@@ -2533,7 +2623,6 @@
         mSplitPlaceholderView.getSplitController().setInitialTaskSelect(taskView,
                 splitPositionOption);
         mSplitHiddenTaskViewIndex = indexOfChild(taskView);
-        mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
     }
 
     public PendingAnimation createSplitSelectInitAnimation() {
@@ -2964,10 +3053,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
@@ -2978,10 +3064,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();
     }
@@ -3000,7 +3083,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) {
@@ -3019,7 +3103,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;
     }
@@ -3195,6 +3280,7 @@
         boolean inPlaceLandscape = !mOrientationState.canRecentsActivityRotate()
                 && mOrientationState.getTouchRotation() != ROTATION_0;
         mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION, modalness < 1 && inPlaceLandscape);
+        mActionsView.setTaskModalness(modalness);
     }
 
     @Nullable
@@ -3239,6 +3325,11 @@
                 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/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 207e3b4..e78406f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -1005,7 +1005,7 @@
         return scrollAdjustment;
     }
 
-    public float getOffsetAdjustment(boolean fullscreenEnabled,boolean gridEnabled) {
+    public float getOffsetAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
         return getScrollAdjustment(fullscreenEnabled, gridEnabled);
     }
 
@@ -1231,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);
@@ -1299,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;
     }
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/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index a29eab7..aea38a0 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -147,6 +147,7 @@
     public final int hotseatBarSidePaddingEndPx;
 
     // All apps
+    public int allAppsOpenVerticalTranslate;
     public int allAppsCellHeightPx;
     public int allAppsCellWidthPx;
     public int allAppsIconSizePx;
@@ -248,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);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index f7cf66b..ecaff7a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -994,7 +994,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
@@ -1019,16 +1031,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/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index f031136..c21d774 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -127,7 +127,7 @@
         mProgress = progress;
 
         mScrimView.setProgress(progress);
-        mAppsView.setTranslationY(progress * mShiftRange);
+        mAppsView.setTranslationY(mProgress * mShiftRange);
     }
 
     public float getProgress() {
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/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/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/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/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 2889801..a437293 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -317,7 +317,9 @@
                         Math.min(progress, 1) - endProgress) * durationMultiplier;
             }
         }
-
+        if (targetState != mStartState) {
+            logReachedState(targetState);
+        }
         mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState));
         ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
         anim.setFloatValues(startProgress, endProgress);
@@ -345,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.
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/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 {