Updating the scrim and landscpae ui

> Instead of views, using a custom class to draw the color scrims
> All-apps has full screen UI
> Quickstep does not have search box in landscape

Bug: 73085356
Change-Id: I360a78a2ade0134daad29fe712796cd39a381fbb
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 9b6c053..cf86176 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -24,6 +24,7 @@
     <dimen name="task_corner_radius">2dp</dimen>
     <dimen name="task_fade_length">20dp</dimen>
     <dimen name="recents_page_spacing">10dp</dimen>
+    <dimen name="recents_page_fade_length">100dp</dimen>
 
     <!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
              loading full resolution screenshots. -->
@@ -34,9 +35,6 @@
 
     <dimen name="workspace_overview_offset_x">-24dp</dimen>
 
-    <!-- TODO: This can be calculated using other resource values -->
-    <dimen name="all_apps_search_box_full_height">90dp</dimen>
-
     <!-- Launcher app transition -->
     <dimen name="content_trans_y">25dp</dimen>
     <dimen name="workspace_trans_y">80dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index 426fe35..ea03a76 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -32,7 +32,8 @@
  */
 public class AllAppsState extends LauncherState {
 
-    private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
+    private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY
+            | FLAG_SHOW_SCRIM | FLAG_ALL_APPS_SCRIM;
 
     private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) {
         @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java b/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java
index c089d06..ccdcbed 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java
@@ -42,7 +42,7 @@
 import com.android.launcher3.anim.RevealOutlineAnimation;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.graphics.GradientView;
+import com.android.launcher3.graphics.ColorScrim;
 import com.android.launcher3.widget.WidgetsFullSheet;
 
 /**
@@ -54,7 +54,7 @@
     private final Launcher mLauncher;
     private final PointF mTouchPoint = new PointF();
 
-    private final GradientView mGradientView;
+    private final ColorScrim mScrim;
 
     protected Animator mOpenCloseAnimator;
 
@@ -75,11 +75,7 @@
         });
 
         mLauncher = Launcher.getLauncher(context);
-
-        mGradientView = (GradientView) mLauncher.getLayoutInflater().inflate(
-                R.layout.widgets_bottom_sheet_scrim, mLauncher.getDragLayer(), false);
-        mGradientView.setProgress(1, false);
-        mGradientView.setAlpha(0);
+        mScrim = ColorScrim.createExtractedColorScrim(this);
     }
 
     @Override
@@ -149,7 +145,7 @@
         fadeOut.setInterpolator(Interpolators.DEACCEL);
         closeAnim.play(fadeOut);
 
-        Animator gradientAlpha = ObjectAnimator.ofFloat(mGradientView, ALPHA, 0);
+        Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 0);
         gradientAlpha.setInterpolator(Interpolators.DEACCEL);
         closeAnim.play(gradientAlpha);
 
@@ -177,7 +173,6 @@
         }
         mIsOpen = false;
         mLauncher.getDragLayer().removeView(this);
-        mLauncher.getDragLayer().removeView(mGradientView);
     }
 
     @Override
@@ -213,7 +208,7 @@
                 .createRevealAnimator(this, false);
         openAnim.play(revealAnim);
 
-        Animator gradientAlpha = ObjectAnimator.ofFloat(mGradientView, ALPHA, 1);
+        Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 1);
         gradientAlpha.setInterpolator(Interpolators.ACCEL);
         openAnim.play(gradientAlpha);
 
@@ -269,7 +264,6 @@
         lp.y = Utilities.boundToRange((int) (y - height / 2), insets.top + margin,
                 maxHeight - insets.bottom - height - margin);
 
-        launcher.getDragLayer().addView(view.mGradientView);
         launcher.getDragLayer().addView(view);
         view.animateOpen();
     }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 613968e..77fb842 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -18,11 +18,9 @@
 import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 
-import android.content.Context;
 import android.graphics.Rect;
 import android.view.View;
 
-import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
@@ -36,7 +34,7 @@
 public class OverviewState extends LauncherState {
 
     private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
-            | FLAG_DISABLE_RESTORE;
+            | FLAG_DISABLE_RESTORE | FLAG_PAGE_BACKGROUNDS;
 
     public OverviewState(int id) {
         super(id, ContainerType.TASKSWITCHER, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
@@ -72,11 +70,6 @@
     }
 
     @Override
-    public float getVerticalProgress(Launcher launcher) {
-        return getVerticalProgress(launcher.getDeviceProfile(), launcher);
-    }
-
-    @Override
     public View getFinalFocus(Launcher launcher) {
         return launcher.getOverviewPanel();
     }
@@ -118,15 +111,4 @@
 
         return new float[] {scale, translationX, translationY};
     }
-
-    public static float getVerticalProgress(DeviceProfile grid, Context context) {
-        if (!grid.isVerticalBarLayout()) {
-            return 1f;
-        }
-
-        float total = grid.heightPx;
-        float searchHeight = total - grid.availableHeightPx +
-                context.getResources().getDimension(R.dimen.all_apps_search_box_full_height);
-        return 1 - (searchHeight / total);
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 42677c1..0d9e2a7 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -383,11 +383,14 @@
 
         float overviewHeight, overviewWidth;
         if (profile.isVerticalBarLayout()) {
+            float scrimLength = context.getResources()
+                    .getDimension(R.dimen.recents_page_fade_length);
+            float maxPadding = Math.max(padding.left, padding.right);
+
             // Use the same padding on both sides for symmetry.
-            float availableWidth = taskWidth - 2 * Math.max(padding.left, padding.right);
-            float availableHeight = profile.availableHeightPx - padding.top
-                    - sTempStableInsets.top - Math.max(padding.bottom,
-                    profile.heightPx * (1 - OverviewState.getVerticalProgress(profile, context)));
+            float availableWidth = taskWidth - 2 * Math.max(maxPadding, scrimLength);
+            float availableHeight = profile.availableHeightPx - padding.top - padding.bottom
+                    - sTempStableInsets.top;
             float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
             overviewHeight = taskHeight * scaledRatio;
             overviewWidth = taskWidth * scaledRatio;
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 314359b..d07ff81 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -44,11 +44,6 @@
             layout="@layout/overview_panel"
             android:visibility="gone" />
 
-        <com.android.launcher3.views.AllAppsScrim
-            android:id="@+id/all_apps_scrim"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-
         <!-- DO NOT CHANGE THE ID -->
         <include
             android:id="@+id/hotseat"
diff --git a/res/layout/widgets_bottom_sheet_scrim.xml b/res/layout/widgets_bottom_sheet_scrim.xml
deleted file mode 100644
index 6c6626c..0000000
--- a/res/layout/widgets_bottom_sheet_scrim.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<com.android.launcher3.graphics.GradientView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/gradient_bg"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    launcher:layout_ignoreInsets="true" />
\ No newline at end of file
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index 20eca9f..ca397bd 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -20,11 +20,6 @@
     android:orientation="vertical"
     android:theme="?attr/widgetsTheme" >
 
-    <com.android.launcher3.graphics.GradientView
-        android:id="@+id/gradient_bg"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
     <com.android.launcher3.views.TopRoundedCornerView
         android:id="@+id/container"
         android:layout_width="match_parent"
diff --git a/res/values/config.xml b/res/values/config.xml
index 065ad36..6821b59 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -116,6 +116,9 @@
     <!-- View ID used by cell layout to jail its content -->
     <item type="id" name="cell_layout_jail_id" />
 
+    <!-- Tag id used for view scrim -->
+    <item type="id" name="view_scrim" />
+
 <!-- Popup items -->
     <integer name="config_popupOpenCloseDuration">150</integer>
     <integer name="config_popupArrowOpenDuration">80</integer>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 38b0140..38235f4 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1003,7 +1003,7 @@
         mDragController.setMoveTarget(mWorkspace);
         mDropTargetBar.setup(mDragController);
 
-        mAllAppsController.setupViews(mAppsView, mHotseat, mWorkspace);
+        mAllAppsController.setupViews(mAppsView, mHotseat);
     }
 
     /**
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 472a5a9..402d73d 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -44,6 +44,8 @@
     protected static final int FLAG_DISABLE_RESTORE = 1 << 3;
     protected static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 4;
     protected static final int FLAG_DISABLE_PAGE_CLIPPING = 1 << 5;
+    protected static final int FLAG_PAGE_BACKGROUNDS = 1 << 6;
+    protected static final int FLAG_ALL_APPS_SCRIM = 1 << 7;
 
     protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER =
             new PageAlphaProvider(ACCEL_2) {
@@ -96,6 +98,9 @@
      * @see WorkspaceStateTransitionAnimation
      */
     public final boolean hasScrim;
+    public final boolean hasWorkspacePageBackground;
+    public final boolean hasAllAppsScrim;
+
     public final int transitionDuration;
 
     /**
@@ -114,6 +119,9 @@
         this.transitionDuration = transitionDuration;
 
         this.hasScrim = (flags & FLAG_SHOW_SCRIM) != 0;
+        this.hasWorkspacePageBackground = (flags & FLAG_PAGE_BACKGROUNDS) != 0;
+        this.hasAllAppsScrim = (flags & FLAG_ALL_APPS_SCRIM) != 0;
+
         this.hasMultipleVisiblePages = (flags & FLAG_MULTI_PAGE) != 0;
         this.workspaceAccessibilityFlag = (flags & FLAG_DISABLE_ACCESSIBILITY) != 0
                 ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 1414946..7c42b48 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -76,6 +76,8 @@
 import com.android.launcher3.folder.PreviewBackground;
 import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.graphics.PreloadIconDrawable;
+import com.android.launcher3.graphics.ViewScrim;
+import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
 import com.android.launcher3.pageindicators.WorkspacePageIndicator;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
@@ -280,6 +282,9 @@
 
         // Disable multitouch across the workspace/all apps/customize tray
         setMotionEventSplittingEnabled(true);
+
+        // Attach a scrim
+        new WorkspaceAndHotseatScrim(this).attach();
     }
 
     @Override
@@ -2229,7 +2234,7 @@
         }
         // Invalidating the scrim will also force this CellLayout
         // to be invalidated so that it is highlighted if necessary.
-        mLauncher.getDragLayer().invalidateScrim();
+        ViewScrim.get(this).invalidate();
     }
 
     public CellLayout getCurrentDragOverlappingLayout() {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 21f5d67..77ac9de 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -32,6 +32,7 @@
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.graphics.ViewScrim;
 
 /**
  * A convenience class to update a view's visibility state after an alpha animation.
@@ -90,8 +91,6 @@
 
     public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter();
 
-    public final int mWorkspaceScrimAlpha;
-
     private final Launcher mLauncher;
     private final Workspace mWorkspace;
 
@@ -100,8 +99,6 @@
     public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) {
         mLauncher = launcher;
         mWorkspace = workspace;
-        mWorkspaceScrimAlpha = launcher.getResources()
-                .getInteger(R.integer.config_workspaceScrimAlpha);
     }
 
     public void setState(LauncherState toState) {
@@ -142,8 +139,10 @@
                 pageAlphaProvider.interpolator);
 
         // Set scrim
-        propertySetter.setInt(mLauncher.getDragLayer().getScrim(), DRAWABLE_ALPHA,
-                state.hasScrim ? mWorkspaceScrimAlpha : 0, Interpolators.DEACCEL_1_5);
+        propertySetter.setFloat(ViewScrim.get(mWorkspace), ViewScrim.PROGRESS,
+                state.hasScrim ? 1 : 0, Interpolators.LINEAR);
+        propertySetter.setFloat(ViewScrim.get(mLauncher.getAppsView()), ViewScrim.PROGRESS,
+                state.hasAllAppsScrim ? 1 : 0, Interpolators.LINEAR);
     }
 
     public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
@@ -154,7 +153,7 @@
     private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
             PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter) {
         float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
-        int drawableAlpha = Math.round(pageAlpha * (state.hasScrim ? 255 : 0));
+        int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0));
 
         propertySetter.setInt(cl.getScrimBackground(),
                 DRAWABLE_ALPHA, drawableAlpha, Interpolators.ZOOM_IN);
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index a7eae39..82bdef9 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.allapps;
 
+import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
+
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
@@ -53,9 +55,11 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.graphics.ColorScrim;
 import com.android.launcher3.keyboard.FocusedItemDecorator;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BottomUserEducationView;
 
 /**
@@ -110,6 +114,10 @@
         mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
 
         mAllAppsStore.addUpdateListener(this::onAppsUpdated);
+
+        // Attach a scrim to be drawn behind all-apps and hotseat
+        new ColorScrim(this, Themes.getAttrColor(context, R.attr.allAppsScrimColor), DEACCEL_2)
+                .attach();
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index c859347..13a42f1 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -16,17 +16,14 @@
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.LauncherStateManager.StateHandler;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
 import com.android.launcher3.allapps.SearchUiManager.OnScrollRangeChangeListener;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.util.Themes;
-import com.android.launcher3.views.AllAppsScrim;
 
 /**
  * Handles AllApps view transition.
@@ -58,7 +55,6 @@
     public static final float PARALLAX_COEFFICIENT = .125f;
 
     private AllAppsContainerView mAppsView;
-    private Workspace mWorkspace;
     private Hotseat mHotseat;
 
     private final Launcher mLauncher;
@@ -76,8 +72,6 @@
 
     private static final float DEFAULT_SHIFT_RANGE = 10;
 
-    private AllAppsScrim mAllAppsScrim;
-
     public AllAppsTransitionController(Launcher l) {
         mLauncher = l;
         mShiftRange = DEFAULT_SHIFT_RANGE;
@@ -106,7 +100,6 @@
             mAppsView.setAlpha(1);
             mLauncher.getHotseat().setTranslationY(0);
             mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
-            mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
         }
     }
 
@@ -127,25 +120,21 @@
         float alpha = 1 - workspaceHotseatAlpha;
 
         mAppsView.setTranslationY(shiftCurrent);
-        if (mAllAppsScrim == null) {
-            mAllAppsScrim = mLauncher.findViewById(R.id.all_apps_scrim);
-        }
         float hotseatTranslation = -mShiftRange + shiftCurrent;
-        mAllAppsScrim.setProgress(hotseatTranslation, alpha);
 
         if (!mIsVerticalLayout) {
             mAppsView.setAlpha(alpha);
             mLauncher.getHotseat().setTranslationY(hotseatTranslation);
             mLauncher.getWorkspace().getPageIndicator().setTranslationY(hotseatTranslation);
+        }
 
-            // Use a light system UI (dark icons) if all apps is behind at least half of the
-            // status bar.
-            boolean forceChange = shiftCurrent <= mShiftRange / 4;
-            if (forceChange) {
-                mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, !mIsDarkTheme);
-            } else {
-                mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
-            }
+        // Use a light system UI (dark icons) if all apps is behind at least half of the
+        // status bar.
+        boolean forceChange = shiftCurrent <= mShiftRange / 4;
+        if (forceChange) {
+            mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, !mIsDarkTheme);
+        } else {
+            mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
         }
     }
 
@@ -201,10 +190,9 @@
         };
     }
 
-    public void setupViews(AllAppsContainerView appsView, Hotseat hotseat, Workspace workspace) {
+    public void setupViews(AllAppsContainerView appsView, Hotseat hotseat) {
         mAppsView = appsView;
         mHotseat = hotseat;
-        mWorkspace = workspace;
         mHotseat.bringToFront();
         mAppsView.getSearchUiManager().addOnScrollRangeChangeListener(this);
     }
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 1cf407e..7e3335a 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -27,7 +27,6 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -50,6 +49,7 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.ViewScrim;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.util.Thunk;
@@ -88,7 +88,6 @@
 
     // Related to adjacent page hints
     private final ViewGroupFocusHelper mFocusIndicatorHelper;
-    private final PageCutOutScrimDrawable mPageCutOutScrim;
 
     protected TouchController[] mControllers;
     private TouchController mActiveController;
@@ -106,8 +105,6 @@
         setChildrenDrawingOrderEnabled(true);
 
         mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
-        mPageCutOutScrim = new PageCutOutScrimDrawable(this);
-        mPageCutOutScrim.setCallback(this);
     }
 
     public void setup(Launcher launcher, DragController dragController) {
@@ -125,11 +122,6 @@
         return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
     }
 
-    @Override
-    protected boolean verifyDrawable(Drawable who) {
-        return super.verifyDrawable(who) || who == mPageCutOutScrim;
-    }
-
     public boolean isEventOverHotseat(MotionEvent ev) {
         return isEventOverView(mLauncher.getHotseat(), ev);
     }
@@ -148,6 +140,15 @@
     }
 
     @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        ViewScrim scrim = ViewScrim.get(child);
+        if (scrim != null) {
+            scrim.draw(canvas, getWidth(), getHeight());
+        }
+        return super.drawChild(canvas, child, drawingTime);
+    }
+
+    @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         int action = ev.getAction();
 
@@ -536,11 +537,7 @@
         final int fromX = r.left;
         final int fromY = r.top;
         child.setVisibility(INVISIBLE);
-        Runnable onCompleteRunnable = new Runnable() {
-            public void run() {
-                child.setVisibility(VISIBLE);
-            }
-        };
+        Runnable onCompleteRunnable = () -> child.setVisibility(VISIBLE);
         animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
                 onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
     }
@@ -758,20 +755,9 @@
         }
     }
 
-    public void invalidateScrim() {
-        if (mPageCutOutScrim.getAlpha() > 0) {
-            invalidate();
-        }
-    }
-
-    public Drawable getScrim() {
-        return mPageCutOutScrim;
-    }
-
     @Override
     protected void dispatchDraw(Canvas canvas) {
         // Draw the background below children.
-        mPageCutOutScrim.draw(canvas);
         mFocusIndicatorHelper.draw(canvas);
         super.dispatchDraw(canvas);
     }
diff --git a/src/com/android/launcher3/dragndrop/PageCutOutScrimDrawable.java b/src/com/android/launcher3/dragndrop/PageCutOutScrimDrawable.java
deleted file mode 100644
index 367124b..0000000
--- a/src/com/android/launcher3/dragndrop/PageCutOutScrimDrawable.java
+++ /dev/null
@@ -1,90 +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.dragndrop;
-
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.drawable.Drawable;
-import android.support.v4.graphics.ColorUtils;
-
-import com.android.launcher3.CellLayout;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.dynamicui.WallpaperColorInfo;
-
-/**
- * Scrim drawable which draws a hole for the current drop target page.
- */
-public class PageCutOutScrimDrawable extends Drawable {
-
-    private final Rect mHighlightRect = new Rect();
-    private final DragLayer mDragLayer;
-    private final Launcher mLauncher;
-    private final WallpaperColorInfo mWallpaperColorInfo;
-
-    private int mAlpha = 0;
-
-    public PageCutOutScrimDrawable(DragLayer dragLayer) {
-        mDragLayer = dragLayer;
-        mLauncher = Launcher.getLauncher(mDragLayer.getContext());
-        mWallpaperColorInfo = WallpaperColorInfo.getInstance(mLauncher);
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        // Draw the background below children.
-        if (mAlpha > 0) {
-            // Update the scroll position first to ensure scrim cutout is in the right place.
-            mLauncher.getWorkspace().computeScrollWithoutInvalidation();
-            CellLayout currCellLayout = mLauncher.getWorkspace().getCurrentDragOverlappingLayout();
-            canvas.save();
-            if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) {
-                // Cut a hole in the darkening scrim on the page that should be highlighted, if any.
-                mDragLayer.getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
-                canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE);
-            }
-            // for super light wallpaper it needs to be darken for contrast to workspace
-            // for dark wallpapers the text is white so darkening works as well
-            int color = ColorUtils.compositeColors(0x66000000, mWallpaperColorInfo.getMainColor());
-            canvas.drawColor(ColorUtils.setAlphaComponent(color, mAlpha));
-            canvas.restore();
-        }
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        if (mAlpha != alpha) {
-            mAlpha = alpha;
-            invalidateSelf();
-        }
-    }
-
-    @Override
-    public int getAlpha() {
-        return mAlpha;
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter colorFilter) { }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
-    }
-}
diff --git a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
index 80a89e3..267e930 100644
--- a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
+++ b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
@@ -2,7 +2,6 @@
 
 import android.content.Context;
 import android.graphics.Color;
-import android.support.v4.graphics.ColorUtils;
 import android.util.Pair;
 
 import com.android.launcher3.compat.WallpaperColorsCompat;
diff --git a/src/com/android/launcher3/graphics/ColorScrim.java b/src/com/android/launcher3/graphics/ColorScrim.java
new file mode 100644
index 0000000..1ffce18
--- /dev/null
+++ b/src/com/android/launcher3/graphics/ColorScrim.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.graphics;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.support.v4.graphics.ColorUtils;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.R;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.dynamicui.WallpaperColorInfo;
+
+/**
+ * Simple scrim which draws a color
+ */
+public class ColorScrim extends ViewScrim {
+
+    private final int mColor;
+    private final Interpolator mInterpolator;
+    private int mCurrentColor;
+
+    public ColorScrim(View view, int color, Interpolator interpolator) {
+        super(view);
+        mColor = color;
+        mInterpolator = interpolator;
+    }
+
+    @Override
+    protected void onProgressChanged() {
+        mCurrentColor = ColorUtils.setAlphaComponent(mColor,
+                Math.round(mInterpolator.getInterpolation(mProgress) * Color.alpha(mColor)));
+    }
+
+    @Override
+    public void draw(Canvas canvas, int width, int height) {
+        if (mProgress > 0) {
+            canvas.drawColor(mCurrentColor);
+        }
+    }
+
+    public static ColorScrim createExtractedColorScrim(View view) {
+        WallpaperColorInfo colors = WallpaperColorInfo.getInstance(view.getContext());
+        int alpha = view.getResources().getInteger(R.integer.extracted_color_gradient_alpha);
+        ColorScrim scrim = new ColorScrim(view, ColorUtils.setAlphaComponent(
+                colors.getSecondaryColor(), alpha), Interpolators.LINEAR);
+        scrim.attach();
+        return scrim;
+    }
+}
diff --git a/src/com/android/launcher3/graphics/GradientView.java b/src/com/android/launcher3/graphics/GradientView.java
deleted file mode 100644
index 6253e18..0000000
--- a/src/com/android/launcher3/graphics/GradientView.java
+++ /dev/null
@@ -1,198 +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.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.RadialGradient;
-import android.graphics.RectF;
-import android.graphics.Shader;
-import android.support.v4.graphics.ColorUtils;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.View;
-import android.view.animation.Interpolator;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.dynamicui.WallpaperColorInfo;
-import com.android.launcher3.util.Themes;
-
-/**
- * Draws a translucent radial gradient background from an initial state with progress 0.0 to a
- * final state with progress 1.0;
- */
-public class GradientView extends View implements WallpaperColorInfo.OnChangeListener {
-
-    private static final int DEFAULT_COLOR = Color.WHITE;
-    private static final int ALPHA_MASK_HEIGHT_DP = 500;
-    private static final int ALPHA_MASK_WIDTH_DP = 2;
-    private static final boolean DEBUG = false;
-
-    private final Bitmap mAlphaGradientMask;
-
-    private boolean mShowScrim = true;
-    private int mColor1 = DEFAULT_COLOR;
-    private int mColor2 = DEFAULT_COLOR;
-    private int mWidth;
-    private int mHeight;
-    private final RectF mAlphaMaskRect = new RectF();
-    private final RectF mFinalMaskRect = new RectF();
-    private final Paint mPaintWithScrim = new Paint();
-    private final Paint mPaintNoScrim = new Paint();
-    private float mProgress;
-    private final int mMaskHeight, mMaskWidth;
-    private final int mAlphaColors;
-    private final Paint mDebugPaint = DEBUG ? new Paint() : null;
-    private final Interpolator mAccelerator = Interpolators.ACCEL;
-    private final float mAlphaStart;
-    private final WallpaperColorInfo mWallpaperColorInfo;
-    private final int mScrimColor;
-
-    public GradientView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        DisplayMetrics dm = getResources().getDisplayMetrics();
-        this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm);
-        this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, dm);
-        Launcher launcher = Launcher.getLauncher(context);
-        this.mAlphaStart = 0;
-        this.mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
-        this.mWallpaperColorInfo = WallpaperColorInfo.getInstance(launcher);
-        mAlphaColors = getResources().getInteger(R.integer.extracted_color_gradient_alpha);
-        updateColors();
-        mAlphaGradientMask = createDitheredAlphaMask();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mWallpaperColorInfo.addOnChangeListener(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mWallpaperColorInfo.removeOnChangeListener(this);
-    }
-
-    @Override
-    public void onExtractedColorsChanged(WallpaperColorInfo info) {
-        updateColors();
-        invalidate();
-    }
-
-    private void updateColors() {
-        this.mColor1 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getMainColor(),
-                mAlphaColors);
-        this.mColor2 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getSecondaryColor(),
-                mAlphaColors);
-        if (mWidth + mHeight > 0) {
-            createRadialShader();
-        }
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        this.mWidth = getMeasuredWidth();
-        this.mHeight = getMeasuredHeight();
-        if (mWidth + mHeight > 0) {
-            createRadialShader();
-        }
-    }
-
-    // only being called when colors change
-    private void createRadialShader() {
-        final float gradientCenterY = 1.05f;
-        float radius = Math.max(mHeight, mWidth) * gradientCenterY;
-        float posScreenBottom = (radius - mHeight) / radius; // center lives below screen
-
-        RadialGradient shaderNoScrim = new RadialGradient(
-                mWidth * 0.5f,
-                mHeight * gradientCenterY,
-                radius,
-                new int[] {mColor1, mColor1, mColor2},
-                new float[] {0f, posScreenBottom, 1f},
-                Shader.TileMode.CLAMP);
-        mPaintNoScrim.setShader(shaderNoScrim);
-
-        int color1 = ColorUtils.compositeColors(mScrimColor,mColor1);
-        int color2 = ColorUtils.compositeColors(mScrimColor,mColor2);
-        RadialGradient shaderWithScrim = new RadialGradient(
-                mWidth * 0.5f,
-                mHeight * gradientCenterY,
-                radius,
-                new int[] { color1, color1, color2 },
-                new float[] {0f, posScreenBottom, 1f},
-                Shader.TileMode.CLAMP);
-        mPaintWithScrim.setShader(shaderWithScrim);
-    }
-
-    public void setProgress(float progress) {
-        setProgress(progress, true);
-    }
-
-    public void setProgress(float progress, boolean showScrim) {
-        this.mProgress = progress;
-        this.mShowScrim = showScrim;
-        invalidate();
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        Paint paint = mShowScrim ? mPaintWithScrim : mPaintNoScrim;
-
-        float head = 0.29f;
-        float linearProgress = head + (mProgress * (1f - head));
-        float startMaskY = (1f - linearProgress) * mHeight - mMaskHeight * linearProgress;
-        float interpolatedAlpha = (255 - mAlphaStart) * mAccelerator.getInterpolation(mProgress);
-        paint.setAlpha((int) (mAlphaStart + interpolatedAlpha));
-        float div = (float) Math.floor(startMaskY + mMaskHeight);
-        mAlphaMaskRect.set(0, startMaskY, mWidth, div);
-        mFinalMaskRect.set(0, div, mWidth, mHeight);
-        canvas.drawBitmap(mAlphaGradientMask, null, mAlphaMaskRect, paint);
-        canvas.drawRect(mFinalMaskRect, paint);
-
-        if (DEBUG) {
-            mDebugPaint.setColor(0xFF00FF00);
-            canvas.drawLine(0, startMaskY, mWidth, startMaskY, mDebugPaint);
-            canvas.drawLine(0, startMaskY + mMaskHeight, mWidth, startMaskY + mMaskHeight, mDebugPaint);
-        }
-    }
-
-    public Bitmap createDitheredAlphaMask() {
-        Bitmap dst = Bitmap.createBitmap(mMaskWidth, mMaskHeight, Bitmap.Config.ALPHA_8);
-        Canvas c = new Canvas(dst);
-        Paint paint = new Paint(Paint.DITHER_FLAG);
-        LinearGradient lg = new LinearGradient(0, 0, 0, mMaskHeight,
-                new int[]{
-                        0x00FFFFFF,
-                        ColorUtils.setAlphaComponent(Color.WHITE, (int) (0xFF * 0.95)),
-                        0xFFFFFFFF},
-                new float[]{0f, 0.8f, 1f},
-                Shader.TileMode.CLAMP);
-        paint.setShader(lg);
-        c.drawRect(0, 0, mMaskWidth, mMaskHeight, paint);
-        return dst;
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/graphics/ViewScrim.java b/src/com/android/launcher3/graphics/ViewScrim.java
new file mode 100644
index 0000000..e1727e0
--- /dev/null
+++ b/src/com/android/launcher3/graphics/ViewScrim.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.graphics;
+
+import android.graphics.Canvas;
+import android.util.Property;
+import android.view.View;
+import android.view.ViewParent;
+
+import com.android.launcher3.R;
+
+/**
+ * A utility class that can be used to draw a scrim behind a view
+ */
+public abstract class ViewScrim<T extends View> {
+
+    public static Property<ViewScrim, Float> PROGRESS =
+            new Property<ViewScrim, Float>(Float.TYPE, "progress") {
+                @Override
+                public Float get(ViewScrim viewScrim) {
+                    return viewScrim.mProgress;
+                }
+
+                @Override
+                public void set(ViewScrim object, Float value) {
+                    object.setProgress(value);
+                }
+            };
+
+    protected final T mView;
+    protected float mProgress = 0;
+
+    public ViewScrim(T view) {
+        mView = view;
+    }
+
+    public void attach() {
+        mView.setTag(R.id.view_scrim, this);
+    }
+
+    public void setProgress(float progress) {
+        if (mProgress != progress) {
+            mProgress = progress;
+            onProgressChanged();
+            invalidate();
+        }
+    }
+
+    public abstract void draw(Canvas canvas, int width, int height);
+
+    protected void onProgressChanged() { }
+
+    public void invalidate() {
+        ViewParent parent = mView.getParent();
+        if (parent != null) {
+            ((View) parent).invalidate();
+        }
+    }
+
+    public static ViewScrim get(View view) {
+        return (ViewScrim) view.getTag(R.id.view_scrim);
+    }
+}
diff --git a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
new file mode 100644
index 0000000..2318a77
--- /dev/null
+++ b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.graphics;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.graphics.Shader;
+import android.support.v4.graphics.ColorUtils;
+import android.util.DisplayMetrics;
+import android.view.View;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.dynamicui.WallpaperColorInfo;
+
+/**
+ * View scrim which draws behind hotseat and workspace
+ */
+public class WorkspaceAndHotseatScrim extends ViewScrim<Workspace> implements
+        View.OnAttachStateChangeListener, WallpaperColorInfo.OnChangeListener {
+
+    private static final int DARK_SCRIM_COLOR = 0x55000000;
+    private static final int MAX_HOTSEAT_SCRIM_ALPHA = 100;
+    private static final int ALPHA_MASK_HEIGHT_DP = 500;
+    private static final int ALPHA_MASK_BITMAP_DP = 200;
+    private static final int ALPHA_MASK_WIDTH_DP = 2;
+
+    private final Rect mHighlightRect = new Rect();
+    private final Launcher mLauncher;
+    private final WallpaperColorInfo mWallpaperColorInfo;
+
+    private final boolean mHasHotseatScrim;
+    private final RectF mFinalMaskRect = new RectF();
+    private final Paint mBottomMaskPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+
+    private final Bitmap mBottomMask;
+    private final int mMaskHeight;
+
+    private int mFullScrimColor;
+
+    private final int mMaxAlpha;
+    private int mAlpha = 0;
+
+    public WorkspaceAndHotseatScrim(Workspace view) {
+        super(view);
+        mLauncher = Launcher.getLauncher(view.getContext());
+        mWallpaperColorInfo = WallpaperColorInfo.getInstance(mLauncher);
+
+        mMaxAlpha = mLauncher.getResources().getInteger(R.integer.config_workspaceScrimAlpha);
+        mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_BITMAP_DP,
+                view.getResources().getDisplayMetrics());
+
+        mHasHotseatScrim = !mWallpaperColorInfo.supportsDarkText();
+        mBottomMask = mHasHotseatScrim ? createDitheredAlphaMask() : null;
+
+        view.addOnAttachStateChangeListener(this);
+        onExtractedColorsChanged(mWallpaperColorInfo);
+    }
+
+    @Override
+    public void draw(Canvas canvas, int width, int height) {
+        // Draw the background below children.
+        if (mAlpha > 0) {
+            // Update the scroll position first to ensure scrim cutout is in the right place.
+            mView.computeScrollWithoutInvalidation();
+            CellLayout currCellLayout = mView.getCurrentDragOverlappingLayout();
+            canvas.save();
+            if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) {
+                // Cut a hole in the darkening scrim on the page that should be highlighted, if any.
+                mLauncher.getDragLayer()
+                        .getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
+                canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE);
+            }
+
+            canvas.drawColor(ColorUtils.setAlphaComponent(mFullScrimColor, mAlpha));
+            canvas.restore();
+        }
+
+        if (mHasHotseatScrim && !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+            mFinalMaskRect.set(0, height - mMaskHeight, width, height);
+            mBottomMaskPaint.setAlpha(Math.round(MAX_HOTSEAT_SCRIM_ALPHA * (1 - mProgress)));
+            canvas.drawBitmap(mBottomMask, null, mFinalMaskRect, mBottomMaskPaint);
+        }
+    }
+
+    @Override
+    protected void onProgressChanged() {
+        mAlpha = Math.round(mMaxAlpha * mProgress);
+    }
+
+    @Override
+    public void onViewAttachedToWindow(View view) {
+        mWallpaperColorInfo.addOnChangeListener(this);
+        onExtractedColorsChanged(mWallpaperColorInfo);
+    }
+
+    @Override
+    public void onViewDetachedFromWindow(View view) {
+        mWallpaperColorInfo.removeOnChangeListener(this);
+    }
+
+    @Override
+    public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
+        // for super light wallpaper it needs to be darken for contrast to workspace
+        // for dark wallpapers the text is white so darkening works as well
+        mFullScrimColor = ColorUtils.compositeColors(DARK_SCRIM_COLOR,
+                wallpaperColorInfo.getMainColor());
+        mBottomMaskPaint.setColor(mFullScrimColor);
+    }
+
+    public Bitmap createDitheredAlphaMask() {
+        DisplayMetrics dm = mLauncher.getResources().getDisplayMetrics();
+        int width = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, dm);
+        int gradientHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm);
+        Bitmap dst = Bitmap.createBitmap(width, mMaskHeight, Bitmap.Config.ALPHA_8);
+        Canvas c = new Canvas(dst);
+        Paint paint = new Paint(Paint.DITHER_FLAG);
+        LinearGradient lg = new LinearGradient(0, 0, 0, gradientHeight,
+                new int[]{
+                        0x00FFFFFF,
+                        ColorUtils.setAlphaComponent(Color.WHITE, (int) (0xFF * 0.95)),
+                        0xFFFFFFFF},
+                new float[]{0f, 0.8f, 1f},
+                Shader.TileMode.CLAMP);
+        paint.setShader(lg);
+        c.drawRect(0, 0, width, gradientHeight, paint);
+        return dst;
+    }
+}
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 6d584cd..4f8456f 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -36,7 +36,7 @@
 
     private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
             FLAG_DISABLE_ACCESSIBILITY | FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED |
-            FLAG_DISABLE_PAGE_CLIPPING;
+            FLAG_DISABLE_PAGE_CLIPPING | FLAG_PAGE_BACKGROUNDS;
 
     // Determines how long to wait after a rotation before restoring the screen orientation to
     // match the sensor state.
diff --git a/src/com/android/launcher3/views/AllAppsScrim.java b/src/com/android/launcher3/views/AllAppsScrim.java
deleted file mode 100644
index 0ef9c8f..0000000
--- a/src/com/android/launcher3/views/AllAppsScrim.java
+++ /dev/null
@@ -1,233 +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.views;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.support.v4.graphics.ColorUtils;
-import android.util.AttributeSet;
-import android.util.Property;
-import android.view.View;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.dynamicui.WallpaperColorInfo;
-import com.android.launcher3.dynamicui.WallpaperColorInfo.OnChangeListener;
-import com.android.launcher3.graphics.NinePatchDrawHelper;
-import com.android.launcher3.graphics.ShadowGenerator;
-import com.android.launcher3.util.Themes;
-
-import static com.android.launcher3.graphics.NinePatchDrawHelper.EXTENSION_PX;
-
-public class AllAppsScrim extends View implements OnChangeListener, Insettable {
-
-    private static final int MAX_ALPHA = 235;
-    private static final int MIN_ALPHA_PORTRAIT = 100;
-    private static final int MIN_ALPHA_LANDSCAPE = MAX_ALPHA;
-
-    protected final WallpaperColorInfo mWallpaperColorInfo;
-    private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
-    private final Rect mDrawRect = new Rect();
-    private final Rect mPadding = new Rect();
-    private final Rect mInsets = new Rect();
-
-    private final float mRadius;
-    private final int mScrimColor;
-
-    private int mMinAlpha;
-    private int mAlphaRange;
-
-    private final float mShadowBlur;
-    private final Bitmap mShadowBitmap;
-
-    private final NinePatchDrawHelper mShadowHelper = new NinePatchDrawHelper();
-
-    private int mFillAlpha;
-
-    private float mDrawHeight;
-    private float mDrawOffsetY;
-
-    public AllAppsScrim(Context context) {
-        this(context, null);
-    }
-
-    public AllAppsScrim(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public AllAppsScrim(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        mWallpaperColorInfo = WallpaperColorInfo.getInstance(context);
-        mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
-        mRadius = getResources().getDimension(R.dimen.all_apps_scrim_radius);
-        mShadowBlur = getResources().getDimension(R.dimen.all_apps_scrim_blur);
-
-        initDefaults();
-        mFillAlpha = mMinAlpha;
-        mShadowBitmap = generateShadowBitmap();
-
-        updateColors(mWallpaperColorInfo);
-    }
-
-    private DeviceProfile initDefaults() {
-        DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
-        mMinAlpha = grid.isVerticalBarLayout()
-                ? MIN_ALPHA_LANDSCAPE : MIN_ALPHA_PORTRAIT;
-        mAlphaRange = MAX_ALPHA - mMinAlpha;
-        return grid;
-    }
-
-    private Bitmap generateShadowBitmap() {
-        float curveBot = mRadius + mShadowBlur;
-
-        ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT);
-        builder.radius = mRadius;
-        builder.shadowBlur = mShadowBlur;
-
-        // Create the bitmap such that only the top half is drawn in the bitmap.
-        int bitmapWidth = 2 * Math.round(curveBot) + EXTENSION_PX;
-        int bitmapHeight = bitmapWidth / 2;
-        Bitmap result = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
-
-        float fullSize = 2 * curveBot + EXTENSION_PX - mShadowBlur;
-        builder.bounds.set(mShadowBlur, mShadowBlur, fullSize, fullSize);
-        builder.drawShadow(new Canvas(result));
-        return result;
-    }
-
-    public Bitmap getShadowBitmap() {
-        return mShadowBitmap;
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mWallpaperColorInfo.addOnChangeListener(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mWallpaperColorInfo.removeOnChangeListener(this);
-    }
-
-    @Override
-    public void onExtractedColorsChanged(WallpaperColorInfo info) {
-        updateColors(info);
-        invalidate();
-    }
-
-    private void updateColors(WallpaperColorInfo info) {
-        mFillPaint.setColor(ColorUtils.compositeColors(mScrimColor,
-                ColorUtils.compositeColors(mScrimColor, info.getMainColor())));
-        mFillPaint.setAlpha(mFillAlpha);
-        invalidate();
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        float edgeTop = getHeight() + mDrawOffsetY - mDrawHeight + mPadding.top;
-        float edgeRight = getWidth() - mPadding.right;
-
-        if (mPadding.left > 0 || mPadding.right > 0) {
-            mShadowHelper.drawVerticallyStretched(mShadowBitmap, canvas,
-                    mPadding.left - mShadowBlur,
-                    edgeTop - mShadowBlur,
-                    edgeRight + mShadowBlur,
-                    getHeight());
-        } else {
-            mShadowHelper.draw(mShadowBitmap, canvas, mPadding.left - mShadowBlur,
-                    edgeTop - mShadowBlur, edgeRight + mShadowBlur);
-        }
-        canvas.drawRoundRect(mPadding.left, edgeTop, edgeRight,
-                getHeight() + mRadius, mRadius, mRadius, mFillPaint);
-    }
-
-    public void setProgress(float translateY, float alpha) {
-        int newAlpha = Math.round(alpha * mAlphaRange + mMinAlpha);
-        // Negative translation means the scrim is moving up. For negative translation, we change
-        // draw offset as it requires redraw (since more area of the scrim needs to be shown). For
-        // position translation, we simply translate the scrim down as it avoids invalidate and
-        // hence could be optimized by the platform.
-        float drawOffsetY = Math.min(translateY, 0);
-
-        if (newAlpha != mFillAlpha || drawOffsetY != mDrawOffsetY) {
-            invalidateDrawRect();
-
-            mFillAlpha = newAlpha;
-            mFillPaint.setAlpha(mFillAlpha);
-            mDrawOffsetY = drawOffsetY;
-            invalidateDrawRect();
-        }
-
-        setTranslationY(Math.max(translateY, 0));
-    }
-
-    private void invalidateDrawRect() {
-        mDrawRect.top = (int) (getHeight()
-                + mDrawOffsetY - mDrawHeight + mPadding.top - mShadowBlur - 0.5f);
-        invalidate(mDrawRect);
-    }
-
-    public void setDrawRegion(float height) {
-        mDrawHeight = height;
-    }
-
-    @Override
-    public void setInsets(Rect insets) {
-        mInsets.set(insets);
-        DeviceProfile grid = initDefaults();
-        if (grid.isVerticalBarLayout()) {
-            mPadding.set(grid.workspacePadding);
-            mPadding.bottom = 0;
-            mPadding.left += mInsets.left;
-            mPadding.top = mInsets.top;
-            mPadding.right += mInsets.right;
-            setDrawRegion(0);
-        } else {
-            mPadding.setEmpty();
-            float scrimMargin = getResources().getDimension(R.dimen.all_apps_scrim_margin);
-            setDrawRegion(grid.hotseatBarSizePx + insets.bottom + scrimMargin);
-        }
-        updateDrawRect(grid);
-        invalidate();
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        updateDrawRect(Launcher.getLauncher(getContext()).getDeviceProfile());
-    }
-
-    private void updateDrawRect(DeviceProfile grid) {
-        mDrawRect.bottom = getHeight();
-        if (grid.isVerticalBarLayout()) {
-            mDrawRect.left = (int) (mPadding.left - mShadowBlur - 0.5f);
-            mDrawRect.right = (int) (getWidth() - mPadding.right + 0.5f);
-        } else {
-            mDrawRect.left = 0;
-            mDrawRect.right = getWidth();
-        }
-    }
-}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index b22509c..c51842d 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -31,7 +31,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.graphics.GradientView;
+import com.android.launcher3.graphics.ColorScrim;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.SystemUiController;
@@ -48,10 +48,11 @@
     /* Touch handling related member variables. */
     private Toast mWidgetInstructionToast;
 
-    protected GradientView mGradientView;
+    protected final ColorScrim mColorScrim;
 
     public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
+        mColorScrim = ColorScrim.createExtractedColorScrim(this);
     }
 
     @Override
@@ -80,7 +81,7 @@
 
     protected void setTranslationShift(float translationShift) {
         super.setTranslationShift(translationShift);
-        mGradientView.setAlpha(1 - mTranslationShift);
+        mColorScrim.setProgress(1 - mTranslationShift);
     }
 
     private boolean beginDraggingWidget(WidgetCell v) {
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 6a9013d..a258485 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -32,7 +32,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.graphics.GradientView;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.util.PackageUserKey;
 
@@ -55,10 +54,6 @@
         super(context, attrs, defStyleAttr);
         setWillNotDraw(false);
         mInsets = new Rect();
-
-        mGradientView = (GradientView) mLauncher.getLayoutInflater().inflate(
-                R.layout.widgets_bottom_sheet_scrim, mLauncher.getDragLayer(), false);
-        mGradientView.setProgress(1, false);
         mContent = this;
     }
 
@@ -75,7 +70,6 @@
 
         onWidgetsBound();
 
-        mLauncher.getDragLayer().addView(mGradientView);
         mLauncher.getDragLayer().addView(this);
         mIsOpen = false;
         open(true);
@@ -157,12 +151,6 @@
     }
 
     @Override
-    protected void onCloseComplete() {
-        super.onCloseComplete();
-        mLauncher.getDragLayer().removeView(mGradientView);
-    }
-
-    @Override
     protected boolean isOfType(@FloatingViewType int type) {
         return (type & TYPE_WIDGETS_BOTTOM_SHEET) != 0;
     }
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index e461afc..48f8afe 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -71,9 +71,6 @@
         mRecyclerView.setAdapter(mAdapter);
         mAdapter.setApplyBitmapDeferred(true, mRecyclerView);
 
-        mGradientView = findViewById(R.id.gradient_bg);
-        mGradientView.setProgress(1, false);
-
         onWidgetsBound();
     }
 
@@ -110,12 +107,8 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int widthUsed;
         if (mInsets.bottom > 0) {
-            // If we have bottom insets, we do not show the scrim as it would overlap
-            // with the navbar scrim
-            mGradientView.setVisibility(View.INVISIBLE);
             widthUsed = 0;
         } else {
-            mGradientView.setVisibility(View.VISIBLE);
             Rect padding = mLauncher.getDeviceProfile().workspacePadding;
             widthUsed = Math.max(padding.left + padding.right,
                     2 * (mInsets.left + mInsets.right));
@@ -124,15 +117,14 @@
         int heightUsed = mInsets.top + mLauncher.getDeviceProfile().edgeMarginPx;
         measureChildWithMargins(mContent, widthMeasureSpec,
                 widthUsed, heightMeasureSpec, heightUsed);
-        measureChild(mGradientView, widthMeasureSpec, heightMeasureSpec);
-        setMeasuredDimension(mGradientView.getMeasuredWidth(), mGradientView.getMeasuredHeight());
+        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
+                MeasureSpec.getSize(heightMeasureSpec));
     }
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         int width = r - l;
         int height = b - t;
-        mGradientView.layout(0, 0, width, height);
 
         // Content is laid out as center bottom aligned
         int contentWidth = mContent.getMeasuredWidth();
@@ -177,13 +169,10 @@
                     mOpenCloseAnimator.removeListener(this);
                 }
             });
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    mRecyclerView.setLayoutFrozen(true);
-                    mOpenCloseAnimator.start();
-                    mContent.animate().alpha(1).setDuration(FADE_IN_DURATION);
-                }
+            post(() -> {
+                mRecyclerView.setLayoutFrozen(true);
+                mOpenCloseAnimator.start();
+                mContent.animate().alpha(1).setDuration(FADE_IN_DURATION);
             });
         } else {
             setTranslationShift(TRANSLATION_SHIFT_OPENED);
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
index fd33ee1..2acd29b 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
@@ -33,7 +33,8 @@
  */
 public class AllAppsState extends LauncherState {
 
-    private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
+    private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY
+            | FLAG_SHOW_SCRIM | FLAG_ALL_APPS_SCRIM;
 
     private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) {
         @Override
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
index d18901d..14806c0 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
@@ -37,7 +37,7 @@
     private static final float SCALE_FACTOR = 0.7f;
 
     private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
-            FLAG_DISABLE_PAGE_CLIPPING;
+            FLAG_DISABLE_PAGE_CLIPPING | FLAG_PAGE_BACKGROUNDS;
 
     public OverviewState(int id) {
         super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, STATE_FLAGS);