Merge "Bandage fix for bitmap fatal exception where width / height !> 0." into ub-launcher3-qt-r1-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
index 311db21..425fb13 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -31,6 +31,9 @@
 import android.view.View;
 import android.view.animation.Interpolator;
 
+import androidx.annotation.ColorInt;
+import androidx.core.content.ContextCompat;
+
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
@@ -41,9 +44,6 @@
 import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.util.Themes;
 
-import androidx.annotation.ColorInt;
-import androidx.core.content.ContextCompat;
-
 /**
  * A view which shows a horizontal divider
  */
@@ -288,10 +288,10 @@
     }
 
     @Override
-    public void setContentVisibility(boolean hasHeaderExtra, boolean hasContent,
-            PropertySetter setter, Interpolator fadeInterpolator) {
+    public void setContentVisibility(boolean hasHeaderExtra, boolean hasAllAppsContent,
+            PropertySetter setter, Interpolator headerFade, Interpolator allAppsFade) {
         // Don't use setViewAlpha as we want to control the visibility ourselves.
-        setter.setFloat(this, ALPHA, hasContent ? 1 : 0, fadeInterpolator);
+        setter.setFloat(this, ALPHA, hasAllAppsContent ? 1 : 0, allAppsFade);
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java
index cb5cbdd..0c7ba9c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -32,6 +32,9 @@
 import android.view.animation.Interpolator;
 import android.widget.LinearLayout;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
@@ -62,9 +65,6 @@
 import java.util.Collections;
 import java.util.List;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 @TargetApi(Build.VERSION_CODES.P)
 public class PredictionRowView extends LinearLayout implements
         LogContainerProvider, OnDeviceProfileChangeListener, FloatingHeaderRow {
@@ -80,7 +80,7 @@
 
                 @Override
                 public Integer get(PredictionRowView view) {
-                    return view.mIconCurrentTextAlpha;
+                    return view.mIconLastSetTextAlpha;
                 }
             };
 
@@ -103,6 +103,8 @@
 
     private final int mIconTextColor;
     private final int mIconFullTextAlpha;
+    private int mIconLastSetTextAlpha;
+    // Might use mIconFullTextAlpha instead of mIconLastSetTextAlpha if we are translucent.
     private int mIconCurrentTextAlpha;
 
     private FloatingHeaderView mParent;
@@ -315,8 +317,14 @@
         }
     }
 
-    public void setTextAlpha(int alpha) {
-        mIconCurrentTextAlpha = alpha;
+    public void setTextAlpha(int textAlpha) {
+        mIconLastSetTextAlpha = textAlpha;
+        if (getAlpha() < 1 && textAlpha > 0) {
+            // If the entire header is translucent, make sure the text is at full opacity so it's
+            // not double-translucent. However, we support keeping the text invisible (alpha == 0).
+            textAlpha = mIconFullTextAlpha;
+        }
+        mIconCurrentTextAlpha = textAlpha;
         int iconColor = setColorAlphaBound(mIconTextColor, mIconCurrentTextAlpha);
         for (int i = 0; i < getChildCount(); i++) {
             ((BubbleTextView) getChildAt(i)).setTextColor(iconColor);
@@ -324,6 +332,13 @@
     }
 
     @Override
+    public void setAlpha(float alpha) {
+        super.setAlpha(alpha);
+        // Reapply text alpha so that we update it to be full alpha if the row is now translucent.
+        setTextAlpha(mIconLastSetTextAlpha);
+    }
+
+    @Override
     public boolean hasOverlappingRendering() {
         return false;
     }
@@ -351,23 +366,15 @@
     }
 
     @Override
-    public void setContentVisibility(boolean hasHeaderExtra, boolean hasContent,
-            PropertySetter setter, Interpolator fadeInterpolator) {
-        boolean isDrawn = getAlpha() > 0;
-        int textAlpha = hasHeaderExtra
-                ? (hasContent ? mIconFullTextAlpha : 0) // Text follows the content visibility
-                : mIconCurrentTextAlpha; // Leave as before
-        if (!isDrawn) {
-            // If the header is not drawn, no need to animate the text alpha
-            setTextAlpha(textAlpha);
-        } else {
-            setter.setInt(this, TEXT_ALPHA, textAlpha, fadeInterpolator);
-        }
-
+    public void setContentVisibility(boolean hasHeaderExtra, boolean hasAllAppsContent,
+            PropertySetter setter, Interpolator headerFade, Interpolator allAppsFade) {
+        // Text follows all apps visibility
+        int textAlpha = hasHeaderExtra && hasAllAppsContent ? mIconFullTextAlpha : 0;
+        setter.setInt(this, TEXT_ALPHA, textAlpha, allAppsFade);
         setter.setFloat(mOverviewScrollFactor, AnimatedFloat.VALUE,
-                (hasHeaderExtra && !hasContent) ? 1 : 0, LINEAR);
+                (hasHeaderExtra && !hasAllAppsContent) ? 1 : 0, LINEAR);
         setter.setFloat(mContentAlphaFactor, AnimatedFloat.VALUE, hasHeaderExtra ? 1 : 0,
-                fadeInterpolator);
+                headerFade);
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
index c954762..427206a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
@@ -15,7 +15,9 @@
  */
 package com.android.launcher3.uioverrides.states;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCRIM_FADE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
 
@@ -43,6 +45,7 @@
         if (this == OVERVIEW_PEEK && fromState == NORMAL) {
             builder.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
             builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
+            builder.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN);
         }
     }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 5543860..151ceb8 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -43,7 +43,6 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.quickstep.SysUINavigationMode;
@@ -128,14 +127,15 @@
         if (launcher.getDeviceProfile().isVerticalBarLayout()) {
             return VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON;
         } else {
+            boolean hasAllAppsHeaderExtra = launcher.getAppsView() != null
+                    && launcher.getAppsView().getFloatingHeaderView().hasVisibleContent();
             return HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON |
-                    (launcher.getAppsView().getFloatingHeaderView().hasVisibleContent()
-                            ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS);
+                    (hasAllAppsHeaderExtra ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS);
         }
     }
 
     @Override
-    public float getWorkspaceScrimAlpha(Launcher launcher) {
+    public float getOverviewScrimAlpha(Launcher launcher) {
         return 0.5f;
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
index f06b8a9..ab346c0 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
@@ -23,13 +23,17 @@
 import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
 import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
 import static com.android.launcher3.LauncherStateManager.ATOMIC_OVERVIEW_PEEK_COMPONENT;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 
@@ -43,6 +47,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.quickstep.OverviewInteractionState;
 import com.android.quickstep.util.MotionPauseDetector;
@@ -102,6 +107,9 @@
                 mPeekAnim.start();
                 recentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                         HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+
+                mLauncher.getDragLayer().getScrim().animateToSysuiMultiplier(isPaused ? 0 : 1,
+                        peekDuration, 0);
             });
         }
     }
@@ -120,6 +128,13 @@
             LauncherState toState) {
         if (fromState == NORMAL && toState == ALL_APPS) {
             AnimatorSetBuilder builder = new AnimatorSetBuilder();
+            // Fade in prediction icons quickly, then rest of all apps after reaching overview.
+            float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher)
+                    - OVERVIEW.getVerticalProgress(mLauncher);
+            builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(ACCEL,
+                    0, ALL_APPS_CONTENT_FADE_THRESHOLD));
+            builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(LINEAR,
+                    progressToReachOverview, 1));
 
             // Get workspace out of the way quickly, to prepare for potential pause.
             builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index e3d622f..d627a7f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -411,15 +411,27 @@
         // FolderIconView can be seen morphing into the icon shape.
         final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
         anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
+
+            // Alpha interpolates between [1, 0] between progress values [start, end]
+            final float start = 0f;
+            final float end = 0.85f;
+
+            private float getWindowAlpha(float progress) {
+                if (progress <= start) {
+                    return 1f;
+                }
+                if (progress >= end) {
+                    return 0f;
+                }
+                return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5);
+            }
+
             @Override
             public void onUpdate(RectF currentRect, float progress) {
                 homeAnim.setPlayFraction(progress);
 
-                float alphaProgress = ACCEL_1_5.getInterpolation(progress);
-                float windowAlpha = Utilities.boundToRange(Utilities.mapToRange(alphaProgress, 0,
-                        windowAlphaThreshold, 1.5f, 0f, Interpolators.LINEAR), 0, 1);
                 mTransformParams.setProgress(progress)
-                        .setCurrentRectAndTargetAlpha(currentRect, windowAlpha);
+                        .setCurrentRectAndTargetAlpha(currentRect, getWindowAlpha(progress));
                 if (isFloatingIconView) {
                     mTransformParams.setCornerRadius(endRadius * progress + startRadius
                             * (1f - progress));
@@ -429,7 +441,8 @@
 
                 if (isFloatingIconView) {
                     ((FloatingIconView) floatingView).update(currentRect, 1f, progress,
-                            windowAlphaThreshold, mClipAnimationHelper.getCurrentCornerRadius(), false);
+                            windowAlphaThreshold, mClipAnimationHelper.getCurrentCornerRadius(),
+                            false);
                 }
             }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 11d1a24..7a67a2a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -943,17 +943,16 @@
         }
         if (start == end || duration <= 0) {
             mLauncherTransitionController.dispatchSetInterpolator(t -> end);
-            mLauncherTransitionController.getAnimationPlayer().end();
         } else {
             mLauncherTransitionController.dispatchSetInterpolator(adjustedInterpolator);
             mAnimationFactory.adjustActivityControllerInterpolators();
-            mLauncherTransitionController.getAnimationPlayer().setDuration(duration);
-
-            if (QUICKSTEP_SPRINGS.get()) {
-                mLauncherTransitionController.dispatchOnStartWithVelocity(end, velocityPxPerMs.y);
-            }
-            mLauncherTransitionController.getAnimationPlayer().start();
         }
+        mLauncherTransitionController.getAnimationPlayer().setDuration(Math.max(0, duration));
+
+        if (QUICKSTEP_SPRINGS.get()) {
+            mLauncherTransitionController.dispatchOnStartWithVelocity(end, velocityPxPerMs.y);
+        }
+        mLauncherTransitionController.getAnimationPlayer().start();
         mHasLauncherTransitionControllerStarted = true;
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 1705c97..1069bed 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -15,6 +15,11 @@
  */
 package com.android.quickstep.util;
 
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
@@ -35,15 +40,11 @@
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.anim.SpringObjectAnimator;
+import com.android.launcher3.graphics.OverviewScrim;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
-import static com.android.launcher3.LauncherState.BACKGROUND_APP;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
 /**
  * Creates an animation where all the workspace items are moved into their final location,
  * staggered row by row from the bottom up.
@@ -122,8 +123,8 @@
             addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows);
         }
 
-        addWorkspaceScrimAnimationForState(launcher, BACKGROUND_APP, 0);
-        addWorkspaceScrimAnimationForState(launcher, NORMAL, ALPHA_DURATION_MS);
+        addScrimAnimationForState(launcher, BACKGROUND_APP, 0);
+        addScrimAnimationForState(launcher, NORMAL, ALPHA_DURATION_MS);
 
         AnimatorListener resetClipListener = new AnimatorListenerAdapter() {
             int numAnimations = mAnimators.size();
@@ -191,13 +192,17 @@
         mAnimators.add(alpha);
     }
 
-    private void addWorkspaceScrimAnimationForState(Launcher launcher, LauncherState state,
-            long duration) {
+    private void addScrimAnimationForState(Launcher launcher, LauncherState state, long duration) {
         AnimatorSetBuilder scrimAnimBuilder = new AnimatorSetBuilder();
         AnimationConfig scrimAnimConfig = new AnimationConfig();
         scrimAnimConfig.duration = duration;
         PropertySetter scrimPropertySetter = scrimAnimConfig.getPropertySetter(scrimAnimBuilder);
         launcher.getWorkspace().getStateTransitionAnimation().setScrim(scrimPropertySetter, state);
         mAnimators.add(scrimAnimBuilder.build());
+        Animator fadeOverviewScrim = ObjectAnimator.ofFloat(
+                launcher.getDragLayer().getOverviewScrim(), OverviewScrim.SCRIM_PROGRESS,
+                state.getOverviewScrimAlpha(launcher));
+        fadeOverviewScrim.setDuration(duration);
+        mAnimators.add(fadeOverviewScrim);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index fc8d02a..991408c 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -32,6 +32,7 @@
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
 import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
+import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
 
@@ -495,6 +496,8 @@
             endCrop = windowTargetBounds.height();
         }
 
+        final float initialWindowRadius = supportsRoundedCornersOnWindows(mLauncher.getResources())
+                ? startCrop / 2f : 0f;
         final float windowRadius = mDeviceProfile.isMultiWindowMode
                 ? 0 : getWindowCornerRadius(mLauncher.getResources());
         appAnimator.addUpdateListener(new MultiValueUpdateListener() {
@@ -506,7 +509,7 @@
                     alphaDuration, LINEAR);
             FloatProp mCroppedSize = new FloatProp(startCrop, endCrop, 0, CROP_DURATION,
                     EXAGGERATED_EASE);
-            FloatProp mWindowRadius = new FloatProp(startCrop / 2f, windowRadius, 0,
+            FloatProp mWindowRadius = new FloatProp(initialWindowRadius, windowRadius, 0,
                     RADIUS_DURATION, EXAGGERATED_EASE);
 
             @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index f0204b9..174e49b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -19,16 +19,20 @@
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCRIM_FADE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_Y;
 import static com.android.launcher3.anim.AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW;
 import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
 
 import android.util.FloatProperty;
 import android.view.View;
 import android.view.animation.Interpolator;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.LauncherState.ScaleAndTranslation;
@@ -36,8 +40,7 @@
 import com.android.launcher3.LauncherStateManager.StateHandler;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.PropertySetter;
-
-import androidx.annotation.NonNull;
+import com.android.launcher3.graphics.OverviewScrim;
 
 /**
  * State handler for recents view. Manages UI changes and animations for recents view based off the
@@ -67,6 +70,8 @@
         mRecentsView.setTranslationX(translationX);
         mRecentsView.setTranslationY(scaleAndTranslation.translationY);
         getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
+        OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
+        SCRIM_PROGRESS.set(scrim, state.getOverviewScrimAlpha(mLauncher));
     }
 
     @Override
@@ -110,6 +115,9 @@
                 translateYInterpolator);
         setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
                 builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
+        OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
+        setter.setFloat(scrim, SCRIM_PROGRESS, toState.getOverviewScrimAlpha(mLauncher),
+                builder.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 109d751..a55f36b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -62,7 +62,7 @@
     /**
      * The progress at which all apps content will be fully visible when swiping up from overview.
      */
-    private static final float ALL_APPS_CONTENT_FADE_THRESHOLD = 0.08f;
+    protected static final float ALL_APPS_CONTENT_FADE_THRESHOLD = 0.08f;
 
     /**
      * The progress at which recents will begin fading out when swiping up from overview.
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index 5a2f5c1..3747f9a 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -98,7 +98,7 @@
 
     public ShelfScrimView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mMaxScrimAlpha = Math.round(OVERVIEW.getWorkspaceScrimAlpha(mLauncher) * 255);
+        mMaxScrimAlpha = Math.round(OVERVIEW.getOverviewScrimAlpha(mLauncher) * 255);
 
         mEndAlpha = Color.alpha(mEndScrim);
         mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context);
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index d949141..e3ef5d6 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -11,6 +11,7 @@
 import android.util.Log;
 
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.LoaderTask;
 import com.android.launcher3.provider.RestoreDbTask;
@@ -18,6 +19,8 @@
 
 import androidx.annotation.WorkerThread;
 
+import static android.os.Process.myUserHandle;
+
 public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
 
     private static final String TAG = "AWRestoredReceiver";
@@ -77,9 +80,14 @@
                 state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
             }
 
-            String[] widgetIdParams = new String[] { Integer.toString(oldWidgetIds[i]) };
+            // b/135926478: Work profile widget restore is broken in platform. This forces us to
+            // recreate the widget during loading with the correct host provider.
+            long mainProfileId = UserManagerCompat.getInstance(context)
+                    .getSerialNumberForUser(myUserHandle());
+            String oldWidgetId = Integer.toString(oldWidgetIds[i]);
             int result = new ContentWriter(context, new ContentWriter.CommitParams(
-                    "appWidgetId=? and (restored & 1) = 1", widgetIdParams))
+                    "appWidgetId=? and (restored & 1) = 1 and profileId=?",
+                    new String[] { oldWidgetId, Long.toString(mainProfileId) }))
                     .put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i])
                     .put(LauncherSettings.Favorites.RESTORED, state)
                     .commit();
@@ -87,7 +95,7 @@
             if (result == 0) {
                 Cursor cursor = cr.query(Favorites.CONTENT_URI,
                         new String[] {Favorites.APPWIDGET_ID},
-                        "appWidgetId=?", widgetIdParams, null);
+                        "appWidgetId=?", new String[] { oldWidgetId }, null);
                 try {
                     if (!cursor.moveToFirst()) {
                         // The widget no long exists.
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index dcfd272..6e2626b 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -243,6 +243,10 @@
         return 0;
     }
 
+    public float getOverviewScrimAlpha(Launcher launcher) {
+        return 0;
+    }
+
     public String getDescription(Launcher launcher) {
         return launcher.getWorkspace().getCurrentPageDescription();
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index a64374b..5b3beec 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -7,6 +7,7 @@
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
@@ -208,13 +209,14 @@
         PropertySetter setter = config == null ? NO_ANIM_PROPERTY_SETTER
                 : config.getPropertySetter(builder);
         boolean hasHeaderExtra = (visibleElements & ALL_APPS_HEADER_EXTRA) != 0;
-        boolean hasContent = (visibleElements & ALL_APPS_CONTENT) != 0;
+        boolean hasAllAppsContent = (visibleElements & ALL_APPS_CONTENT) != 0;
 
         Interpolator allAppsFade = builder.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
-        setter.setViewAlpha(mAppsView.getContentView(), hasContent ? 1 : 0, allAppsFade);
-        setter.setViewAlpha(mAppsView.getScrollBar(), hasContent ? 1 : 0, allAppsFade);
-        mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasContent, setter,
-                allAppsFade);
+        Interpolator headerFade = builder.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade);
+        setter.setViewAlpha(mAppsView.getContentView(), hasAllAppsContent ? 1 : 0, allAppsFade);
+        setter.setViewAlpha(mAppsView.getScrollBar(), hasAllAppsContent ? 1 : 0, allAppsFade);
+        mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasAllAppsContent,
+                setter, headerFade, allAppsFade);
         mAppsView.getSearchUiManager().setContentVisibility(visibleElements, setter, allAppsFade);
 
         setter.setInt(mScrimView, ScrimView.DRAG_HANDLE_ALPHA,
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderRow.java b/src/com/android/launcher3/allapps/FloatingHeaderRow.java
index 922e4f1..f899587 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderRow.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderRow.java
@@ -46,8 +46,8 @@
      */
     boolean hasVisibleContent();
 
-    void setContentVisibility(boolean hasHeaderExtra, boolean hasContent,
-            PropertySetter setter, Interpolator fadeInterpolator);
+    void setContentVisibility(boolean hasHeaderExtra, boolean hasAllAppsContent,
+            PropertySetter setter, Interpolator headerFade, Interpolator allAppsFade);
 
     /**
      * Scrolls the content vertically.
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 66dced9..42a0eee 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -27,6 +27,10 @@
 import android.view.animation.Interpolator;
 import android.widget.LinearLayout;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
@@ -40,10 +44,6 @@
 import java.util.ArrayList;
 import java.util.Map;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.RecyclerView;
-
 public class FloatingHeaderView extends LinearLayout implements
         ValueAnimator.AnimatorUpdateListener, PluginListener<AllAppsRow>, Insettable,
         OnHeightUpdatedListener {
@@ -363,14 +363,14 @@
         p.y = getTop() - mCurrentRV.getTop() - mParent.getTop();
     }
 
-    public void setContentVisibility(boolean hasHeader, boolean hasContent, PropertySetter setter,
-            Interpolator fadeInterpolator) {
+    public void setContentVisibility(boolean hasHeader, boolean hasAllAppsContent,
+            PropertySetter setter, Interpolator headerFade, Interpolator allAppsFade) {
         for (FloatingHeaderRow row : mAllRows) {
-            row.setContentVisibility(hasHeader, hasContent, setter, fadeInterpolator);
+            row.setContentVisibility(hasHeader, hasAllAppsContent, setter, headerFade, allAppsFade);
         }
 
-        allowTouchForwarding(hasContent);
-        setter.setFloat(mTabLayout, ALPHA, hasContent ? 1 : 0, fadeInterpolator);
+        allowTouchForwarding(hasAllAppsContent);
+        setter.setFloat(mTabLayout, ALPHA, hasAllAppsContent ? 1 : 0, headerFade);
     }
 
     protected void allowTouchForwarding(boolean allow) {
diff --git a/src/com/android/launcher3/allapps/PluginHeaderRow.java b/src/com/android/launcher3/allapps/PluginHeaderRow.java
index b283ff4..535ef54 100644
--- a/src/com/android/launcher3/allapps/PluginHeaderRow.java
+++ b/src/com/android/launcher3/allapps/PluginHeaderRow.java
@@ -64,10 +64,10 @@
     }
 
     @Override
-    public void setContentVisibility(boolean hasHeaderExtra, boolean hasContent,
-            PropertySetter setter, Interpolator fadeInterpolator) {
+    public void setContentVisibility(boolean hasHeaderExtra, boolean hasAllAppsContent,
+            PropertySetter setter, Interpolator headerFade, Interpolator allAppsFade) {
         // Don't use setViewAlpha as we want to control the visibility ourselves.
-        setter.setFloat(mView, ALPHA, hasContent ? 1 : 0, fadeInterpolator);
+        setter.setFloat(mView, ALPHA, hasAllAppsContent ? 1 : 0, headerFade);
     }
 
     @Override
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index 52a896e..cd30dea 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -39,6 +39,8 @@
     public static final int ANIM_OVERVIEW_TRANSLATE_Y = 8;
     public static final int ANIM_OVERVIEW_FADE = 9;
     public static final int ANIM_ALL_APPS_FADE = 10;
+    public static final int ANIM_OVERVIEW_SCRIM_FADE = 11;
+    public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
 
     public static final int FLAG_DONT_ANIMATE_OVERVIEW = 1 << 0;
 
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index a72089d..a2dcbf8 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -153,16 +153,6 @@
         PinItemDragListener listener = new PinItemDragListener(mRequest, bounds,
                 img.getBitmap().getWidth(), img.getWidth());
 
-        Intent homeIntent = listener.addToIntent(
-                new Intent(Intent.ACTION_MAIN)
-                        .addCategory(Intent.CATEGORY_HOME)
-                        .setPackage(getPackageName())
-                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
-
-        listener.initWhenReady();
-        startActivity(homeIntent,
-                ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out).toBundle());
-        mFinishOnPause = true;
 
         // Start a system drag and drop. We use a transparent bitmap as preview for system drag
         // as the preview is handled internally by launcher.
@@ -179,6 +169,18 @@
                 outShadowTouchPoint.set(SHADOW_SIZE / 2, SHADOW_SIZE / 2);
             }
         }, null, View.DRAG_FLAG_GLOBAL);
+
+
+        Intent homeIntent = listener.addToIntent(
+                new Intent(Intent.ACTION_MAIN)
+                        .addCategory(Intent.CATEGORY_HOME)
+                        .setPackage(getPackageName())
+                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+
+        listener.initWhenReady();
+        startActivity(homeIntent,
+                ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out).toBundle());
+        mFinishOnPause = true;
         return false;
     }
 
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 6ba015b..b59164a 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -48,12 +48,13 @@
 import com.android.launcher3.DropTargetBar;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.graphics.RotationMode;
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.OverviewScrim;
+import com.android.launcher3.graphics.RotationMode;
 import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.uioverrides.UiFactory;
@@ -92,7 +93,8 @@
 
     // Related to adjacent page hints
     private final ViewGroupFocusHelper mFocusIndicatorHelper;
-    private final WorkspaceAndHotseatScrim mScrim;
+    private final WorkspaceAndHotseatScrim mWorkspaceScrim;
+    private final OverviewScrim mOverviewScrim;
 
     /**
      * Used to create a new DragLayer from XML.
@@ -108,12 +110,13 @@
         setChildrenDrawingOrderEnabled(true);
 
         mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
-        mScrim = new WorkspaceAndHotseatScrim(this);
+        mWorkspaceScrim = new WorkspaceAndHotseatScrim(this);
+        mOverviewScrim = new OverviewScrim(this);
     }
 
     public void setup(DragController dragController, Workspace workspace) {
         mDragController = dragController;
-        mScrim.setWorkspace(workspace);
+        mWorkspaceScrim.setWorkspace(workspace);
         recreateControllers();
     }
 
@@ -529,25 +532,39 @@
     @Override
     protected void dispatchDraw(Canvas canvas) {
         // Draw the background below children.
-        mScrim.draw(canvas);
+        mWorkspaceScrim.draw(canvas);
+        mOverviewScrim.updateCurrentScrimmedView(this);
         mFocusIndicatorHelper.draw(canvas);
         super.dispatchDraw(canvas);
     }
 
     @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        if (child == mOverviewScrim.getScrimmedView()) {
+            mOverviewScrim.draw(canvas);
+        }
+        return super.drawChild(canvas, child, drawingTime);
+    }
+
+    @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mScrim.setSize(w, h);
+        mWorkspaceScrim.setSize(w, h);
     }
 
     @Override
     public void setInsets(Rect insets) {
         super.setInsets(insets);
-        mScrim.onInsetsChanged(insets);
+        mWorkspaceScrim.onInsetsChanged(insets);
+        mOverviewScrim.onInsetsChanged(insets);
     }
 
     public WorkspaceAndHotseatScrim getScrim() {
-        return mScrim;
+        return mWorkspaceScrim;
+    }
+
+    public OverviewScrim getOverviewScrim() {
+        return mOverviewScrim;
     }
 
     @Override
diff --git a/src/com/android/launcher3/graphics/OverviewScrim.java b/src/com/android/launcher3/graphics/OverviewScrim.java
new file mode 100644
index 0000000..d707403
--- /dev/null
+++ b/src/com/android/launcher3/graphics/OverviewScrim.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.graphics;
+
+import static android.view.View.VISIBLE;
+
+import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * View scrim which draws behind overview (recent apps).
+ */
+public class OverviewScrim extends Scrim {
+
+    private @NonNull View mStableScrimmedView;
+    // Might be higher up if mStableScrimmedView is invisible.
+    private @Nullable View mCurrentScrimmedView;
+
+    public OverviewScrim(View view) {
+        super(view);
+        mStableScrimmedView = mCurrentScrimmedView = mLauncher.getOverviewPanel();
+
+        onExtractedColorsChanged(mWallpaperColorInfo);
+    }
+
+    public void onInsetsChanged(Rect insets) {
+        mStableScrimmedView = (OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0
+                ? mLauncher.getHotseat()
+                : mLauncher.getOverviewPanel();
+    }
+
+    public void updateCurrentScrimmedView(ViewGroup root) {
+        // Find the lowest view that is at or above the view we want to show the scrim behind.
+        mCurrentScrimmedView = mStableScrimmedView;
+        int currentIndex = root.indexOfChild(mCurrentScrimmedView);
+        final int childCount = root.getChildCount();
+        while (mCurrentScrimmedView.getVisibility() != VISIBLE && currentIndex < childCount) {
+            currentIndex++;
+            mCurrentScrimmedView = root.getChildAt(currentIndex);
+        }
+    }
+
+    /**
+     * @return The view to draw the scrim behind.
+     */
+    public View getScrimmedView() {
+        return mCurrentScrimmedView;
+    }
+}
diff --git a/src/com/android/launcher3/graphics/Scrim.java b/src/com/android/launcher3/graphics/Scrim.java
new file mode 100644
index 0000000..5c14f8d
--- /dev/null
+++ b/src/com/android/launcher3/graphics/Scrim.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.graphics;
+
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
+import android.graphics.Canvas;
+import android.util.Property;
+import android.view.View;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.uioverrides.WallpaperColorInfo;
+
+/**
+ * Contains general scrim properties such as wallpaper-extracted color that subclasses can use.
+ */
+public class Scrim implements View.OnAttachStateChangeListener,
+        WallpaperColorInfo.OnChangeListener {
+
+    public static Property<Scrim, Float> SCRIM_PROGRESS =
+            new Property<Scrim, Float>(Float.TYPE, "scrimProgress") {
+                @Override
+                public Float get(Scrim scrim) {
+                    return scrim.mScrimProgress;
+                }
+
+                @Override
+                public void set(Scrim scrim, Float value) {
+                    scrim.setScrimProgress(value);
+                }
+            };
+
+    protected final Launcher mLauncher;
+    protected final WallpaperColorInfo mWallpaperColorInfo;
+    protected final View mRoot;
+
+    protected float mScrimProgress;
+    protected int mScrimColor;
+    protected int mScrimAlpha = 0;
+
+    public Scrim(View view) {
+        mRoot = view;
+        mLauncher = Launcher.getLauncher(view.getContext());
+        mWallpaperColorInfo = WallpaperColorInfo.getInstance(mLauncher);
+
+        view.addOnAttachStateChangeListener(this);
+    }
+
+    public void draw(Canvas canvas) {
+        canvas.drawColor(setColorAlphaBound(mScrimColor, mScrimAlpha));
+    }
+
+    private void setScrimProgress(float progress) {
+        if (mScrimProgress != progress) {
+            mScrimProgress = progress;
+            mScrimAlpha = Math.round(255 * mScrimProgress);
+            invalidate();
+        }
+    }
+
+    @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) {
+        mScrimColor = wallpaperColorInfo.getMainColor();
+        if (mScrimAlpha > 0) {
+            invalidate();
+        }
+    }
+
+    public void invalidate() {
+        mRoot.invalidate();
+    }
+}
diff --git a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
index c0aa75f..6740fa1 100644
--- a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
+++ b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
@@ -40,34 +40,19 @@
 import android.util.Property;
 import android.view.View;
 
+import androidx.core.graphics.ColorUtils;
+
 import com.android.launcher3.CellLayout;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.ResourceUtils;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.uioverrides.WallpaperColorInfo;
 import com.android.launcher3.util.Themes;
 
-import androidx.core.graphics.ColorUtils;
-
 /**
  * View scrim which draws behind hotseat and workspace
  */
-public class WorkspaceAndHotseatScrim implements
-        View.OnAttachStateChangeListener, WallpaperColorInfo.OnChangeListener {
-
-    public static Property<WorkspaceAndHotseatScrim, Float> SCRIM_PROGRESS =
-            new Property<WorkspaceAndHotseatScrim, Float>(Float.TYPE, "scrimProgress") {
-                @Override
-                public Float get(WorkspaceAndHotseatScrim scrim) {
-                    return scrim.mScrimProgress;
-                }
-
-                @Override
-                public void set(WorkspaceAndHotseatScrim scrim, Float value) {
-                    scrim.setScrimProgress(value);
-                }
-            };
+public class WorkspaceAndHotseatScrim extends Scrim {
 
     public static Property<WorkspaceAndHotseatScrim, Float> SYSUI_PROGRESS =
             new Property<WorkspaceAndHotseatScrim, Float>(Float.TYPE, "sysUiProgress") {
@@ -117,9 +102,6 @@
     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 View mRoot;
 
     private Workspace mWorkspace;
 
@@ -132,11 +114,6 @@
 
     private final Drawable mTopScrim;
 
-    private int mFullScrimColor;
-
-    private float mScrimProgress;
-    private int mScrimAlpha = 0;
-
     private float mSysUiProgress = 1;
     private boolean mHideSysUiScrim;
 
@@ -144,9 +121,7 @@
     private float mSysUiAnimMultiplier = 1;
 
     public WorkspaceAndHotseatScrim(View view) {
-        mRoot = view;
-        mLauncher = Launcher.getLauncher(view.getContext());
-        mWallpaperColorInfo = WallpaperColorInfo.getInstance(mLauncher);
+        super(view);
 
         mMaskHeight = ResourceUtils.pxFromDp(ALPHA_MASK_BITMAP_DP,
                 view.getResources().getDisplayMetrics());
@@ -154,7 +129,6 @@
         mBottomMask = mTopScrim == null ? null : createDitheredAlphaMask();
         mHideSysUiScrim = mTopScrim == null;
 
-        view.addOnAttachStateChangeListener(this);
         onExtractedColorsChanged(mWallpaperColorInfo);
     }
 
@@ -176,7 +150,7 @@
                 canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE);
             }
 
-            canvas.drawColor(setColorAlphaBound(mFullScrimColor, mScrimAlpha));
+            super.draw(canvas);
             canvas.restore();
         }
 
@@ -190,11 +164,8 @@
                 mSysUiAnimMultiplier = 0;
                 reapplySysUiAlphaNoInvalidate();
 
-                ObjectAnimator anim = ObjectAnimator.ofFloat(this, SYSUI_ANIM_MULTIPLIER, 1);
-                anim.setAutoCancel(true);
-                anim.setDuration(600);
-                anim.setStartDelay(mLauncher.getWindow().getTransitionBackgroundFadeDuration());
-                anim.start();
+                animateToSysuiMultiplier(1, 600,
+                        mLauncher.getWindow().getTransitionBackgroundFadeDuration());
                 mAnimateScrimOnNextDraw = false;
             }
 
@@ -207,24 +178,24 @@
         }
     }
 
+    public void animateToSysuiMultiplier(float toMultiplier, long duration,
+            long startDelay) {
+        ObjectAnimator anim = ObjectAnimator.ofFloat(this, SYSUI_ANIM_MULTIPLIER, toMultiplier);
+        anim.setAutoCancel(true);
+        anim.setDuration(duration);
+        anim.setStartDelay(startDelay);
+        anim.start();
+    }
+
     public void onInsetsChanged(Rect insets) {
         mDrawTopScrim = mTopScrim != null && insets.top > 0;
         mDrawBottomScrim = mBottomMask != null &&
                 !mLauncher.getDeviceProfile().isVerticalBarLayout();
     }
 
-    private void setScrimProgress(float progress) {
-        if (mScrimProgress != progress) {
-            mScrimProgress = progress;
-            mScrimAlpha = Math.round(255 * mScrimProgress);
-            invalidate();
-        }
-    }
-
     @Override
     public void onViewAttachedToWindow(View view) {
-        mWallpaperColorInfo.addOnChangeListener(this);
-        onExtractedColorsChanged(mWallpaperColorInfo);
+        super.onViewAttachedToWindow(view);
 
         if (mTopScrim != null) {
             IntentFilter filter = new IntentFilter(ACTION_SCREEN_OFF);
@@ -235,7 +206,7 @@
 
     @Override
     public void onViewDetachedFromWindow(View view) {
-        mWallpaperColorInfo.removeOnChangeListener(this);
+        super.onViewDetachedFromWindow(view);
         if (mTopScrim != null) {
             mRoot.getContext().unregisterReceiver(mReceiver);
         }
@@ -248,10 +219,7 @@
         mBottomMaskPaint.setColor(ColorUtils.compositeColors(DARK_SCRIM_COLOR,
                 wallpaperColorInfo.getMainColor()));
         reapplySysUiAlpha();
-        mFullScrimColor = wallpaperColorInfo.getMainColor();
-        if (mScrimAlpha > 0) {
-            invalidate();
-        }
+        super.onExtractedColorsChanged(wallpaperColorInfo);
     }
 
     public void setSize(int w, int h) {
@@ -291,10 +259,6 @@
         }
     }
 
-    public void invalidate() {
-        mRoot.invalidate();
-    }
-
     public Bitmap createDitheredAlphaMask() {
         DisplayMetrics dm = mLauncher.getResources().getDisplayMetrics();
         int width = ResourceUtils.pxFromDp(ALPHA_MASK_WIDTH_DP, dm);
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 49f515a..0545344 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -518,6 +518,7 @@
             logReachedState(logAction, targetState);
         }
         mLauncher.getStateManager().goToState(targetState, false /* animated */);
+        mLauncher.getDragLayer().getScrim().animateToSysuiMultiplier(1, 0, 0);
     }
 
     private void logReachedState(int logAction, LauncherState targetState) {