Merge "Change TaskIconMenu to lay out vertically" into sc-dev
diff --git a/Android.mk b/Android.mk
index 54a80b7..c222f24 100644
--- a/Android.mk
+++ b/Android.mk
@@ -47,6 +47,9 @@
 
 LOCAL_MANIFEST_FILE := go/AndroidManifest.xml
 LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
 include $(BUILD_PACKAGE)
 
 #
@@ -116,6 +119,9 @@
 LOCAL_MANIFEST_FILE := quickstep/AndroidManifest.xml
 LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
 
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
 include $(BUILD_PACKAGE)
 
 
@@ -164,6 +170,9 @@
 
 LOCAL_MANIFEST_FILE := quickstep/AndroidManifest.xml
 LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
 include $(BUILD_PACKAGE)
 
 
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 4e72260..87a08af 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -94,12 +94,6 @@
         </receiver>
 
         <service
-            android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
-            android:exported="false"
-            android:process=":wallpaper_chooser"
-            android:permission="android.permission.BIND_JOB_SERVICE" />
-
-        <service
             android:name="com.android.launcher3.notification.NotificationListener"
             android:label="@string/notification_dots_service_title"
             android:exported="true"
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index fe81b4c..fb47b0a 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -125,6 +125,22 @@
   // Folder's label is empty(i.e., title == "").
   // Not eligible for auto-labeling.
   EMPTY_LABEL = 12;
+
+  ALL_APPS_SEARCH_RESULT_APPLICATION = 13;
+  ALL_APPS_SEARCH_RESULT_SHORTCUT = 14;
+  ALL_APPS_SEARCH_RESULT_PEOPLE = 15;
+  ALL_APPS_SEARCH_RESULT_ACTION = 16;
+  ALL_APPS_SEARCH_RESULT_SETTING = 17;
+  ALL_APPS_SEARCH_RESULT_SCREENSHOT = 18;
+  ALL_APPS_SEARCH_RESULT_SLICE = 19;
+  ALL_APPS_SEARCH_RESULT_WIDGETS = 20;
+  ALL_APPS_SEARCH_RESULT_PLAY = 21;
+  ALL_APPS_SEARCH_RESULT_SUGGEST = 22;
+  ALL_APPS_SEARCH_RESULT_ASSISTANT = 23;
+  ALL_APPS_SEARCH_RESULT_CHROMETAB = 24;
+  ALL_APPS_SEARCH_RESULT_NAVVYSITE = 25;
+  ALL_APPS_SEARCH_RESULT_TIPS = 26;
+  ALL_APPS_SEARCH_RESULT_PEOPLE_TILE = 27;
 }
 
 // Main app icons
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 5e5cf73..842abc3 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -97,9 +97,6 @@
                  android:resource="@xml/overview_file_provider_paths"/>
         </provider>
 
-        <service android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
-             tools:node="remove"/>
-
         <activity android:name="com.android.launcher3.proxy.ProxyActivityStarter"
              android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
              android:launchMode="singleTask"
diff --git a/quickstep/res/layout/fallback_recents_activity.xml b/quickstep/res/layout/fallback_recents_activity.xml
index 55400a7..a43296f 100644
--- a/quickstep/res/layout/fallback_recents_activity.xml
+++ b/quickstep/res/layout/fallback_recents_activity.xml
@@ -33,6 +33,12 @@
         android:layout_height="match_parent"
         android:clipChildren="false">
 
+        <com.android.launcher3.views.ScrimView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/scrim_view"
+            android:background="@android:color/transparent" />
+
         <com.android.quickstep.fallback.FallbackRecentsView
             android:id="@id/overview_panel"
             android:layout_width="match_parent"
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 5b1b59b..fb67645 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -79,6 +79,7 @@
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.views.FloatingIconView;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.quickstep.RemoteAnimationTargets;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskViewUtils;
@@ -86,6 +87,7 @@
 import com.android.quickstep.util.RemoteAnimationProvider;
 import com.android.quickstep.util.StaggeredWorkspaceAnim;
 import com.android.quickstep.util.SurfaceTransactionApplier;
+import com.android.quickstep.views.FloatingWidgetView;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.system.ActivityCompat;
 import com.android.systemui.shared.system.ActivityOptionsCompat;
@@ -100,7 +102,9 @@
 import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.wm.shell.startingsurface.IStartingWindowListener;
 
+import java.util.ArrayList;
 import java.util.LinkedHashMap;
+import java.util.List;
 
 /**
  * Manages the opening and closing app transitions from Launcher
@@ -160,6 +164,9 @@
 
     private static final int MAX_NUM_TASKS = 5;
 
+    // Cross-fade duration between App Widget and App
+    private static final int WIDGET_CROSSFADE_DURATION_MILLIS = 125;
+
     protected final BaseQuickstepLauncher mLauncher;
 
     private final DragLayer mDragLayer;
@@ -349,6 +356,29 @@
         }
     }
 
+    private void composeWidgetLaunchAnimator(
+            @NonNull AnimatorSet anim,
+            @NonNull LauncherAppWidgetHostView v,
+            @NonNull RemoteAnimationTargetCompat[] appTargets,
+            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
+            @NonNull RemoteAnimationTargetCompat[] nonAppTargets) {
+        mLauncher.getStateManager().setCurrentAnimation(anim);
+
+        Rect windowTargetBounds = getWindowTargetBounds(appTargets, getRotationChange(appTargets));
+        anim.play(getOpeningWindowAnimatorsForWidget(v, appTargets, wallpaperTargets, nonAppTargets,
+                windowTargetBounds, areAllTargetsTranslucent(appTargets)));
+
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mLauncher.addOnResumeCallback(() ->
+                        ObjectAnimator.ofFloat(mLauncher.getDepthController(), DEPTH,
+                                mLauncher.getStateManager().getState().getDepth(
+                                        mLauncher)).start());
+            }
+        });
+    }
+
     /**
      * Return the window bounds of the opening target.
      * In multiwindow mode, we need to get the final size of the opening app window target to help
@@ -457,32 +487,29 @@
             alpha.setInterpolator(LINEAR);
             launcherAnimator.play(alpha);
 
+            List<View> viewsToAnimate = new ArrayList<>();
+
             Workspace workspace = mLauncher.getWorkspace();
-            View currentPage = ((CellLayout) workspace.getChildAt(workspace.getCurrentPage()))
-                    .getShortcutsAndWidgets();
-            View hotseat = mLauncher.getHotseat();
-            View qsb = mLauncher.findViewById(R.id.search_container_all_apps);
+            workspace.getVisiblePages().forEach(
+                    view -> viewsToAnimate.add(((CellLayout) view).getShortcutsAndWidgets()));
 
-            currentPage.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            qsb.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            viewsToAnimate.add(mLauncher.getHotseat());
+            // Add QSB
+            viewsToAnimate.add(mLauncher.findViewById(R.id.search_container_all_apps));
 
-            launcherAnimator.play(ObjectAnimator.ofFloat(currentPage, View.TRANSLATION_Y, trans));
-            launcherAnimator.play(ObjectAnimator.ofFloat(hotseat, View.TRANSLATION_Y, trans));
-            launcherAnimator.play(ObjectAnimator.ofFloat(qsb, View.TRANSLATION_Y, trans));
+            viewsToAnimate.forEach(view -> {
+                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                launcherAnimator.play(ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, trans));
+            });
 
             // Pause page indicator animations as they lead to layer trashing.
             mLauncher.getWorkspace().getPageIndicator().pauseAnimations();
 
             endListener = () -> {
-                currentPage.setTranslationY(0);
-                hotseat.setTranslationY(0);
-                qsb.setTranslationY(0);
-
-                currentPage.setLayerType(View.LAYER_TYPE_NONE, null);
-                hotseat.setLayerType(View.LAYER_TYPE_NONE, null);
-                qsb.setLayerType(View.LAYER_TYPE_NONE, null);
-
+                viewsToAnimate.forEach(view -> {
+                    view.setTranslationY(0);
+                    view.setLayerType(View.LAYER_TYPE_NONE, null);
+                });
                 mDragLayerAlpha.setValue(1f);
                 mLauncher.getWorkspace().getPageIndicator().skipAnimationsToEnd();
             };
@@ -737,6 +764,112 @@
             }
         });
 
+        animatorSet.playTogether(appAnimator, getBackgroundAnimator(appTargets));
+        return animatorSet;
+    }
+
+    private Animator getOpeningWindowAnimatorsForWidget(LauncherAppWidgetHostView v,
+            RemoteAnimationTargetCompat[] appTargets,
+            RemoteAnimationTargetCompat[] wallpaperTargets,
+            RemoteAnimationTargetCompat[] nonAppTargets, Rect windowTargetBounds,
+            boolean appTargetsAreTranslucent) {
+        final RectF widgetBackgroundBounds = new RectF();
+        final Rect appWindowCrop = new Rect();
+        final Matrix matrix = new Matrix();
+
+        final float finalWindowRadius = mDeviceProfile.isMultiWindowMode
+                ? 0 : getWindowCornerRadius(mLauncher.getResources());
+        final FloatingWidgetView floatingView = FloatingWidgetView.getFloatingWidgetView(mLauncher,
+                v, widgetBackgroundBounds, windowTargetBounds, finalWindowRadius);
+        final float initialWindowRadius = supportsRoundedCornersOnWindows(mLauncher.getResources())
+                ? floatingView.getInitialCornerRadius() : 0;
+
+        RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets,
+                wallpaperTargets, nonAppTargets, MODE_OPENING);
+        SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(floatingView);
+        openingTargets.addReleaseCheck(surfaceApplier);
+
+        AnimatorSet animatorSet = new AnimatorSet();
+        ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
+        appAnimator.setDuration(APP_LAUNCH_DURATION);
+        appAnimator.setInterpolator(LINEAR);
+        appAnimator.addListener(floatingView);
+        appAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                openingTargets.release();
+            }
+        });
+        floatingView.setFastFinishRunnable(animatorSet::end);
+
+        appAnimator.addUpdateListener(new MultiValueUpdateListener() {
+            float mAppWindowScale = 1;
+            final FloatProp mWidgetForegroundAlpha = new FloatProp(1 /* start */,
+                    0 /* end */, 0 /* delay */,
+                    WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR);
+            final FloatProp mWidgetFallbackBackgroundAlpha = new FloatProp(0 /* start */,
+                    1 /* end */, 0 /* delay */, 75 /* duration */, LINEAR);
+            final FloatProp mPreviewAlpha = new FloatProp(0 /* start */, 1 /* end */,
+                    WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* delay */,
+                    WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR);
+            final FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius,
+                    0 /* start */, RADIUS_DURATION, LINEAR);
+            final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, 0, RADIUS_DURATION, LINEAR);
+
+            // Window & widget background positioning bounds
+            final FloatProp mDx = new FloatProp(widgetBackgroundBounds.centerX(),
+                    windowTargetBounds.centerX(), 0 /* delay */, APP_LAUNCH_CURVED_DURATION,
+                    EXAGGERATED_EASE);
+            final FloatProp mDy = new FloatProp(widgetBackgroundBounds.centerY(),
+                    windowTargetBounds.centerY(), 0 /* delay */, APP_LAUNCH_DURATION,
+                    EXAGGERATED_EASE);
+            final FloatProp mWidth = new FloatProp(widgetBackgroundBounds.width(),
+                    windowTargetBounds.width(), 0 /* delay */, APP_LAUNCH_DURATION,
+                    EXAGGERATED_EASE);
+            final FloatProp mHeight = new FloatProp(widgetBackgroundBounds.height(),
+                    windowTargetBounds.height(), 0 /* delay */, APP_LAUNCH_DURATION,
+                    EXAGGERATED_EASE);
+
+            @Override
+            public void onUpdate(float percent) {
+                widgetBackgroundBounds.set(mDx.value - mWidth.value / 2f,
+                        mDy.value - mHeight.value / 2f, mDx.value + mWidth.value / 2f,
+                        mDy.value + mHeight.value / 2f);
+                // Set app window scaling factor to match widget background width
+                mAppWindowScale = widgetBackgroundBounds.width() / windowTargetBounds.width();
+                // Crop scaled app window to match widget
+                appWindowCrop.set(0 /* left */, 0 /* top */,
+                        Math.round(windowTargetBounds.width()) /* right */,
+                        Math.round(widgetBackgroundBounds.height() / mAppWindowScale) /* bottom */);
+                matrix.setTranslate(widgetBackgroundBounds.left, widgetBackgroundBounds.top);
+                matrix.postScale(mAppWindowScale, mAppWindowScale, widgetBackgroundBounds.left,
+                        widgetBackgroundBounds.top);
+
+                SurfaceParams[] params = new SurfaceParams[appTargets.length];
+                float floatingViewAlpha = appTargetsAreTranslucent ? 1 - mPreviewAlpha.value : 1;
+                for (int i = appTargets.length - 1; i >= 0; i--) {
+                    RemoteAnimationTargetCompat target = appTargets[i];
+                    SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash);
+                    if (target.mode == MODE_OPENING) {
+                        floatingView.update(widgetBackgroundBounds, floatingViewAlpha,
+                                mWidgetForegroundAlpha.value, mWidgetFallbackBackgroundAlpha.value,
+                                mCornerRadiusProgress.value);
+                        builder.withMatrix(matrix)
+                                .withWindowCrop(appWindowCrop)
+                                .withAlpha(mPreviewAlpha.value)
+                                .withCornerRadius(mWindowRadius.value / mAppWindowScale);
+                    }
+                    params[i] = builder.build();
+                }
+                surfaceApplier.scheduleApply(params);
+            }
+        });
+
+        animatorSet.playTogether(appAnimator, getBackgroundAnimator(appTargets));
+        return animatorSet;
+    }
+
+    private ObjectAnimator getBackgroundAnimator(RemoteAnimationTargetCompat[] appTargets) {
         // When launching an app from overview that doesn't map to a task, we still want to just
         // blur the wallpaper instead of the launcher surface as well
         boolean allowBlurringLauncher = mLauncher.getStateManager().getState() != OVERVIEW;
@@ -754,9 +887,7 @@
                 }
             });
         }
-
-        animatorSet.playTogether(appAnimator, backgroundRadiusAnim);
-        return animatorSet;
+        return backgroundRadiusAnim;
     }
 
     /**
@@ -1120,9 +1251,13 @@
             boolean launcherClosing =
                     launcherIsATargetWithMode(appTargets, MODE_CLOSING);
 
+            final boolean launchingFromWidget = mV instanceof LauncherAppWidgetHostView;
             final boolean launchingFromRecents = isLaunchingFromRecents(mV, appTargets);
             final boolean launchingFromTaskbar = mLauncher.isViewInTaskbar(mV);
-            if (launchingFromRecents) {
+            if (launchingFromWidget) {
+                composeWidgetLaunchAnimator(anim, (LauncherAppWidgetHostView) mV, appTargets,
+                        wallpaperTargets, nonAppTargets);
+            } else if (launchingFromRecents) {
                 composeRecentsLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                         launcherClosing);
             } else if (launchingFromTaskbar) {
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 249ef3a..59d0afa 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -158,11 +158,7 @@
      * Sets the specified app target surface to apply the blur to.
      */
     public void setSurfaceToApp(RemoteAnimationTargetCompat target) {
-        if (target != null) {
-            setSurface(target.leash);
-        } else {
-            setActivityStarted(mLauncher.isStarted());
-        }
+        setSurface(target == null ? null : target.leash);
     }
 
     private void setSurface(SurfaceControlCompat surface) {
@@ -170,9 +166,6 @@
             mSurface = surface;
             if (surface != null) {
                 setDepth(mDepth);
-            } else {
-                // If there is no surface, then reset the ratio
-                setDepth(0f);
             }
         }
     }
@@ -192,8 +185,7 @@
     @Override
     public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
             PendingAnimation animation) {
-        if (mSurface == null
-                || config.hasAnimationFlag(SKIP_DEPTH_CONTROLLER)
+        if (config.hasAnimationFlag(SKIP_DEPTH_CONTROLLER)
                 || mIgnoreStateChangesDuringMultiWindowAnimation) {
             return;
         }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java b/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java
deleted file mode 100644
index 1417995..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides;
-
-import static android.app.WallpaperManager.FLAG_SYSTEM;
-
-import android.annotation.TargetApi;
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
-import android.app.WallpaperManager.OnColorsChangedListener;
-import android.content.Context;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Looper;
-
-import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.systemui.shared.system.TonalCompat;
-import com.android.systemui.shared.system.TonalCompat.ExtractionInfo;
-
-import java.util.ArrayList;
-
-@TargetApi(Build.VERSION_CODES.P)
-public class WallpaperColorInfo implements OnColorsChangedListener {
-
-    private static final int MAIN_COLOR_LIGHT = 0xffdadce0;
-    private static final int MAIN_COLOR_DARK = 0xff202124;
-    private static final int MAIN_COLOR_REGULAR = 0xff000000;
-
-    public static final MainThreadInitializedObject<WallpaperColorInfo> INSTANCE =
-            new MainThreadInitializedObject<>(WallpaperColorInfo::new);
-
-    private final ArrayList<OnChangeListener> mListeners = new ArrayList<>();
-    private final WallpaperManager mWallpaperManager;
-    private final TonalCompat mTonalCompat;
-
-    private ExtractionInfo mExtractionInfo;
-
-    private OnChangeListener[] mTempListeners = new OnChangeListener[0];
-
-    private WallpaperColorInfo(Context context) {
-        mWallpaperManager = context.getSystemService(WallpaperManager.class);
-        mTonalCompat = new TonalCompat(context);
-
-        mWallpaperManager.addOnColorsChangedListener(this, new Handler(Looper.getMainLooper()));
-        update(mWallpaperManager.getWallpaperColors(FLAG_SYSTEM));
-    }
-
-    public int getMainColor() {
-        return mExtractionInfo.mainColor;
-    }
-
-    public int getSecondaryColor() {
-        return mExtractionInfo.secondaryColor;
-    }
-
-    public boolean isDark() {
-        return mExtractionInfo.supportsDarkTheme;
-    }
-
-    public boolean supportsDarkText() {
-        return mExtractionInfo.supportsDarkText;
-    }
-
-    public boolean isMainColorDark() {
-        return mExtractionInfo.mainColor == MAIN_COLOR_DARK;
-    }
-
-    @Override
-    public void onColorsChanged(WallpaperColors colors, int which) {
-        if ((which & FLAG_SYSTEM) != 0) {
-            update(colors);
-            notifyChange();
-        }
-    }
-
-    private void update(WallpaperColors wallpaperColors) {
-        mExtractionInfo = mTonalCompat.extractDarkColors(wallpaperColors);
-    }
-
-    public void addOnChangeListener(OnChangeListener listener) {
-        mListeners.add(listener);
-    }
-
-    public void removeOnChangeListener(OnChangeListener listener) {
-        mListeners.remove(listener);
-    }
-
-    private void notifyChange() {
-        // Create a new array to avoid concurrent modification when the activity destroys itself.
-        mTempListeners = mListeners.toArray(mTempListeners);
-        for (int i = mTempListeners.length - 1; i >= 0; --i) {
-            final OnChangeListener listener = mTempListeners[i];
-            if (listener != null) {
-                listener.onExtractedColorsChanged(this);
-                mTempListeners[i] = null;
-            }
-        }
-    }
-
-    public interface OnChangeListener {
-        void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo);
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 4e03971..a81bdd5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -22,7 +22,9 @@
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.R;
 import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.util.Themes;
 
 /**
  * Definition for AllApps state
@@ -92,7 +94,7 @@
     }
 
     @Override
-    public float getWorkspaceScrimAlpha(Launcher launcher) {
-        return 1;
+    public int getWorkspaceScrimColor(Launcher launcher) {
+        return Themes.getAttrColor(launcher, R.attr.allAppsScrimColor);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index aa770d2..77c2611 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -18,6 +18,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 
 import android.content.Context;
+import android.graphics.Color;
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
@@ -86,6 +87,11 @@
         return 1f;
     }
 
+    @Override
+    public int getWorkspaceScrimColor(Launcher launcher) {
+        return Color.TRANSPARENT;
+    }
+
     public static float[] getOverviewScaleAndOffsetForBackgroundState(
             BaseDraggingActivity activity) {
         return new float[] {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 30c07b0..135c478 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -29,6 +29,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.Themes;
 import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
@@ -108,8 +109,8 @@
     }
 
     @Override
-    public float getWorkspaceScrimAlpha(Launcher launcher) {
-        return 1f;
+    public int getWorkspaceScrimColor(Launcher launcher) {
+        return Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
index 53afd21..d36e76b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
@@ -18,6 +18,8 @@
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 
 import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
 
 /**
  * State to indicate we are about to launch a recent task. Note that this state is only used when
@@ -39,6 +41,11 @@
     }
 
     @Override
+    public int getWorkspaceScrimColor(Launcher launcher) {
+        return Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
+    }
+
+    @Override
     public float getVerticalProgress(Launcher launcher) {
         // Don't move all apps shelf while quick-switching (just let it fade).
         return 1f;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 694998c..2d95ce2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -16,7 +16,7 @@
 
 package com.android.launcher3.uioverrides.touchcontrollers;
 
-import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
 import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.HINT_STATE;
@@ -127,11 +127,11 @@
         }
 
         if (mFromState == NORMAL && mToState == HINT_STATE) {
-            mNormalToHintOverviewScrimAnimator = ObjectAnimator.ofFloat(
+            mNormalToHintOverviewScrimAnimator = ObjectAnimator.ofArgb(
                     mLauncher.getScrimView(),
-                    VIEW_ALPHA,
-                    mFromState.getWorkspaceScrimAlpha(mLauncher),
-                    mToState.getWorkspaceScrimAlpha(mLauncher));
+                    VIEW_BACKGROUND_COLOR,
+                    mFromState.getWorkspaceScrimColor(mLauncher),
+                    mToState.getWorkspaceScrimColor(mLauncher));
         }
         mStartedOverview = false;
         mReachedOverview = false;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 77b0804..12de4a6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.uioverrides.touchcontrollers;
 
-import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -232,8 +231,8 @@
         //   - OverviewScrim
         PendingAnimation xAnim = new PendingAnimation((long) (mXRange * 2));
         xAnim.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1], LINEAR);
-        xAnim.setFloat(mLauncher.getScrimView(), VIEW_ALPHA,
-                toState.getWorkspaceScrimAlpha(mLauncher), LINEAR);
+        xAnim.setViewBackgroundColor(mLauncher.getScrimView(),
+                toState.getWorkspaceScrimColor(mLauncher), LINEAR);
         mXOverviewAnim = xAnim.createPlaybackController();
         mXOverviewAnim.dispatchOnStart();
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 94a7442..3953e42 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -29,7 +29,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
-import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
+import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
@@ -143,10 +143,9 @@
             if (tv != null) {
                 sysuiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
             }
-            mLauncher.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
+            mLauncher.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, sysuiFlags);
         } else {
-            mLauncher.getSystemUiController().updateUiState(
-                    UI_STATE_OVERVIEW, mOverviewPanel.hasLightBackground());
+            mLauncher.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 53f1fd0..61803aa 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -34,7 +34,7 @@
 import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
+import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
 import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
 import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
@@ -150,6 +150,9 @@
     protected Runnable mGestureEndCallback;
     protected MultiStateCallback mStateCallback;
     protected boolean mCanceled;
+    // One time flag set when onConsumerAboutToBeSwitched() is called, indicating that certain
+    // shared animations should not be canceled when this handler is invalidated
+    private boolean mConsumerIsSwitching;
     private boolean mRecentsViewScrollLinked = false;
 
     private static int getFlagForIndex(int index, String name) {
@@ -664,11 +667,10 @@
             mRecentsAnimationController.setSplitScreenMinimized(swipeUpThresholdPassed);
 
             if (swipeUpThresholdPassed) {
-                mActivity.getSystemUiController().updateUiState(
-                        UI_STATE_OVERVIEW, mRecentsView.hasLightBackground());
+                mActivity.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
             } else {
                 mActivity.getSystemUiController().updateUiState(
-                        UI_STATE_OVERVIEW, centermostTaskFlags);
+                        UI_STATE_FULLSCREEN_TASK, centermostTaskFlags);
             }
         }
     }
@@ -1003,7 +1005,14 @@
         animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocity);
     }
 
-    private void doLogGesture(GestureEndTarget endTarget, @Nullable TaskView targetTask) {
+    private int getLogGestureTaskIndex(@Nullable TaskView targetTask) {
+        return mRecentsView == null || targetTask == null
+                ? LOG_NO_OP_PAGE_INDEX
+                : mRecentsView.indexOfChild(targetTask);
+    }
+
+    private void doLogGesture(GestureEndTarget endTarget, @Nullable TaskView targetTask,
+            int pageIndex) {
         StatsLogManager.EventEnum event;
         switch (endTarget) {
             case HOME:
@@ -1032,9 +1041,6 @@
             // We probably never received an animation controller, skip logging.
             return;
         }
-        int pageIndex = endTarget == LAST_TASK
-                ? LOG_NO_OP_PAGE_INDEX
-                : mRecentsView.getNextPage();
         // TODO: set correct container using the pageIndex
         logger.log(event);
     }
@@ -1279,18 +1285,18 @@
     }
 
     public void onConsumerAboutToBeSwitched() {
+        mConsumerIsSwitching = true;
         if (mActivity != null) {
             // In the off chance that the gesture ends before Launcher is started, we should clear
             // the callback here so that it doesn't update with the wrong state
             mActivity.clearRunOnceOnStartCallback();
-            resetLauncherListeners();
         }
         if (mGestureState.getEndTarget() != null && !mGestureState.isRunningAnimationToLauncher()) {
             cancelCurrentAnimation();
         } else {
             mStateCallback.setStateOnUiThread(STATE_FINISH_WITH_NO_END);
-            reset();
         }
+        reset();
     }
 
     public boolean isCanceled() {
@@ -1301,13 +1307,14 @@
     private void resumeLastTask() {
         mRecentsAnimationController.finish(false /* toRecents */, null);
         ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
-        doLogGesture(LAST_TASK, null);
+        doLogGesture(LAST_TASK, null, getLogGestureTaskIndex(null));
         reset();
     }
 
     @UiThread
     private void startNewTask() {
         TaskView taskToLaunch = mRecentsView == null ? null : mRecentsView.getNextPageTaskView();
+        int taskPageIndex = getLogGestureTaskIndex(taskToLaunch);
         startNewTask(success -> {
             if (!success) {
                 reset();
@@ -1316,7 +1323,7 @@
                 endLauncherTransitionController();
                 updateSysUiFlags(1 /* windowProgress == overview */);
             }
-            doLogGesture(NEW_TASK, taskToLaunch);
+            doLogGesture(NEW_TASK, taskToLaunch, taskPageIndex);
         });
     }
 
@@ -1350,32 +1357,38 @@
     }
 
     private void invalidateHandler() {
-        if (!LIVE_TILE.get() || !mActivityInterface.isInLiveTileMode()
-                || mGestureState.getEndTarget() != RECENTS) {
-            mInputConsumerProxy.destroy();
-            mTaskAnimationManager.setLiveTileCleanUpHandler(null);
+        if (!mConsumerIsSwitching) {
+            if (!LIVE_TILE.get() || !mActivityInterface.isInLiveTileMode()
+                    || mGestureState.getEndTarget() != RECENTS) {
+                mInputConsumerProxy.destroy();
+                mTaskAnimationManager.setLiveTileCleanUpHandler(null);
+            }
+            endRunningWindowAnim(false /* cancel */);
+
+            if (mGestureEndCallback != null) {
+                mGestureEndCallback.run();
+            }
         }
+
         mInputConsumerProxy.unregisterCallback();
-        endRunningWindowAnim(false /* cancel */);
-
-        if (mGestureEndCallback != null) {
-            mGestureEndCallback.run();
-        }
-
         mActivityInitListener.unregister();
         ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mActivityRestartListener);
         mTaskSnapshot = null;
         mHandler.post(() -> {
             // Defer clearing the activity since invalidation can happen over multiple callbacks
+            // ie. invalidateHandlerWithLauncher()
             mActivity = null;
+            mRecentsView = null;
         });
     }
 
     private void invalidateHandlerWithLauncher() {
-        endLauncherTransitionController();
+        if (!mConsumerIsSwitching) {
+            endLauncherTransitionController();
+            mRecentsView.onGestureAnimationEnd();
+        }
 
         mRecentsView.removeOnScrollChangedListener(mOnRecentsScrollListener);
-        mRecentsView.onGestureAnimationEnd();
         resetLauncherListeners();
     }
 
@@ -1500,7 +1513,8 @@
                     () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
         }
         ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
-        doLogGesture(HOME, mRecentsView == null ? null : mRecentsView.getCurrentPageTaskView());
+        TaskView taskToLaunch = mRecentsView == null ? null : mRecentsView.getCurrentPageTaskView();
+        doLogGesture(HOME, taskToLaunch, getLogGestureTaskIndex(taskToLaunch));
     }
 
     /**
@@ -1531,7 +1545,8 @@
         }
 
         SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
-        doLogGesture(RECENTS, mRecentsView.getCurrentPageTaskView());
+        TaskView taskToLaunch = mRecentsView.getCurrentPageTaskView();
+        doLogGesture(RECENTS, taskToLaunch, getLogGestureTaskIndex(taskToLaunch));
         reset();
     }
 
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 147297a..7aa81d4 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -15,10 +15,12 @@
  */
 package com.android.quickstep;
 
+import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
+import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
 import static com.android.quickstep.SysUINavigationMode.getMode;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
@@ -28,9 +30,11 @@
 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
 
 import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Build;
@@ -51,6 +55,7 @@
 import com.android.launcher3.taskbar.TaskbarController;
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.WindowBounds;
+import com.android.launcher3.views.ScrimView;
 import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
@@ -344,15 +349,33 @@
     }
 
     /**
-     * Called when the gesture ends and the animation starts towards the given target. No-op by
-     * default, but subclasses can override to add an additional animation with the same duration.
+     * Called when the gesture ends and the animation starts towards the given target. Used to add
+     * an optional additional animation with the same duration.
      */
     public @Nullable Animator getParallelAnimationToLauncher(
             GestureState.GestureEndTarget endTarget, long duration) {
+        if (endTarget == RECENTS) {
+            ACTIVITY_TYPE activity = getCreatedActivity();
+            if (activity == null) {
+                return null;
+            }
+            STATE_TYPE state = stateFromGestureEndTarget(endTarget);
+            ScrimView scrimView = activity.getScrimView();
+            ObjectAnimator anim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR,
+                    getOverviewScrimColorForState(activity, state));
+            anim.setDuration(duration);
+            return anim;
+        }
         return null;
     }
 
     /**
+     * Returns the color of the scrim behind overview when at rest in this state.
+     * Return {@link Color#TRANSPARENT} for no scrim.
+     */
+    protected abstract int getOverviewScrimColorForState(ACTIVITY_TYPE activity, STATE_TYPE state);
+
+    /**
      * See {@link com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags}
      * @param systemUiStateFlags The latest SystemUiStateFlags
      */
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 8168e88..9fa65d9 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -196,4 +196,9 @@
         recentsView.setLayoutRotation(rotationTouchHelper.getCurrentActiveRotation(),
                 rotationTouchHelper.getDisplayRotation());
     }
+
+    @Override
+    protected int getOverviewScrimColorForState(RecentsActivity activity, RecentsState state) {
+        return state.getScrimColor(activity);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 878f5c9..dffee7f 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
 
 import android.animation.Animator;
+import android.animation.AnimatorSet;
 import android.content.Context;
 import android.graphics.Rect;
 import android.view.MotionEvent;
@@ -271,11 +272,25 @@
     public @Nullable Animator getParallelAnimationToLauncher(GestureEndTarget endTarget,
             long duration) {
         TaskbarController taskbarController = getTaskbarController();
+        Animator superAnimator = super.getParallelAnimationToLauncher(endTarget, duration);
         if (taskbarController == null) {
-            return null;
+            return superAnimator;
         }
         LauncherState toState = stateFromGestureEndTarget(endTarget);
-        return taskbarController.createAnimToLauncher(toState, duration);
+        Animator taskbarAnimator = taskbarController.createAnimToLauncher(toState, duration);
+        if (superAnimator == null) {
+            return taskbarAnimator;
+        } else {
+            AnimatorSet animatorSet = new AnimatorSet();
+            animatorSet.playTogether(superAnimator, taskbarAnimator);
+            return animatorSet;
+        }
+    }
+
+    @Override
+    protected int getOverviewScrimColorForState(BaseQuickstepLauncher launcher,
+            LauncherState state) {
+        return state.getWorkspaceScrimColor(launcher);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 2a6e478..c47300c 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -92,7 +92,7 @@
     };
 
     private static final String TAG = "OrientationTouchTransformer";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = true;
 
     private static final int QUICKSTEP_ROTATION_UNINITIALIZED = -1;
 
@@ -163,6 +163,10 @@
 
     void setNavigationMode(SysUINavigationMode.Mode newMode, Info info,
             Resources newRes) {
+        if (DEBUG) {
+            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "setNavigationMode new: " + newMode
+                    + " oldMode: " + mMode + " " + this);
+        }
         if (mMode == newMode) {
             return;
         }
@@ -254,10 +258,18 @@
 
         mCurrentDisplay = new CurrentDisplay(region.realSize, region.rotation);
         OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCurrentDisplay);
+        if (DEBUG) {
+            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "cached region: " + regionToKeep
+                    + " mCurrentDisplay: " + mCurrentDisplay + " " + this);
+        }
         if (regionToKeep == null) {
             regionToKeep = createRegionForDisplay(region);
         }
         mSwipeTouchRegions.clear();
+        if (DEBUG) {
+            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "adding region: " + regionToKeep
+                    + " mCurrentDisplay: " + mCurrentDisplay + " " + this);
+        }
         mSwipeTouchRegions.put(mCurrentDisplay, regionToKeep);
         updateAssistantRegions(regionToKeep);
     }
@@ -273,7 +285,8 @@
 
     private OrientationRectF createRegionForDisplay(Info display) {
         if (DEBUG) {
-            Log.d(TAG, "creating rotation region for: " + mCurrentDisplay.rotation);
+            Log.d(TAG, "creating rotation region for: " + mCurrentDisplay.rotation
+            + " with mode: " + mMode + " displayRotation: " + display.rotation);
         }
 
         Point size = display.realSize;
@@ -287,14 +300,19 @@
         } else {
             mAssistantLeftRegion.setEmpty();
             mAssistantRightRegion.setEmpty();
+            int navbarSize = getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
+            if (DEBUG) {
+                Log.d(TestProtocol.NO_SWIPE_TO_HOME, "else case mode: " + mMode
+                        + " getNavbarSize: " + navbarSize + " rotation: " + rotation + " " + this);
+            }
             switch (rotation) {
                 case Surface.ROTATION_90:
                     orientationRectF.left = orientationRectF.right
-                            - getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
+                            - navbarSize;
                     break;
                 case Surface.ROTATION_270:
                     orientationRectF.right = orientationRectF.left
-                            + getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
+                            + navbarSize;
                     break;
                 default:
                     orientationRectF.top = orientationRectF.bottom - touchHeight;
@@ -339,7 +357,7 @@
     boolean touchInValidSwipeRegions(float x, float y) {
         if (TestProtocol.sDebugTracing) {
             Log.d(TestProtocol.NO_SWIPE_TO_HOME, "touchInValidSwipeRegions " + x + "," + y + " in "
-                    + mLastRectTouched);
+                    + mLastRectTouched + " this: " + this);
         }
         if (mLastRectTouched != null) {
             return mLastRectTouched.contains(x, y);
@@ -462,7 +480,8 @@
                 if (DEBUG) {
                     Log.d(TAG, "Transforming rotation due to forceTransform, "
                             + "mCurrentRotation: " + mCurrentDisplay.rotation
-                            + "mRotation: " + mRotation);
+                            + "mRotation: " + mRotation
+                            + " this: " + this);
                 }
                 event.transform(mTmpMatrix);
                 return true;
@@ -473,9 +492,10 @@
 
             if (DEBUG) {
                 Log.d(TAG, "original: " + event.getX() + ", " + event.getY()
-                                + " new: " + mTmpPoint[0] + ", " + mTmpPoint[1]
-                                + " rect: " + this + " forceTransform: " + forceTransform
-                                + " contains: " + contains(mTmpPoint[0], mTmpPoint[1]));
+                        + " new: " + mTmpPoint[0] + ", " + mTmpPoint[1]
+                        + " rect: " + this + " forceTransform: " + forceTransform
+                        + " contains: " + contains(mTmpPoint[0], mTmpPoint[1])
+                        + " this: " + this);
             }
 
             if (contains(mTmpPoint[0], mTmpPoint[1])) {
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index ec224ed..3b92779 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -59,7 +59,9 @@
 import com.android.launcher3.util.ActivityTracker;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.views.ScrimView;
 import com.android.quickstep.fallback.FallbackRecentsStateController;
 import com.android.quickstep.fallback.FallbackRecentsView;
 import com.android.quickstep.fallback.RecentsDragLayer;
@@ -89,6 +91,7 @@
     private Handler mUiHandler = new Handler(Looper.getMainLooper());
 
     private RecentsDragLayer mDragLayer;
+    private ScrimView mScrimView;
     private FallbackRecentsView mFallbackRecentsView;
     private OverviewActionsView mActionsView;
 
@@ -106,6 +109,7 @@
         inflateRootView(R.layout.fallback_recents_activity);
         setContentView(getRootView());
         mDragLayer = findViewById(R.id.drag_layer);
+        mScrimView = findViewById(R.id.scrim_view);
         mFallbackRecentsView = findViewById(R.id.overview_panel);
         mActionsView = findViewById(R.id.overview_actions_view);
 
@@ -164,6 +168,10 @@
         return mDragLayer;
     }
 
+    public ScrimView getScrimView() {
+        return mScrimView;
+    }
+
     @Override
     public <T extends View> T getOverviewPanel() {
         return (T) mFallbackRecentsView;
@@ -269,7 +277,7 @@
         setupViews();
 
         getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
-                mFallbackRecentsView.hasLightBackground());
+                Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
         ACTIVITY_TRACKER.handleCreate(this);
     }
 
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 4560735..78da311 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -25,6 +25,7 @@
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.RunnableList;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -43,6 +44,8 @@
 
     private boolean mUseLauncherSysBarFlags = false;
     private boolean mSplitScreenMinimized = false;
+    private boolean mFinishRequested = false;
+    private RunnableList mPendingFinishCallbacks = new RunnableList();
 
     public RecentsAnimationController(RecentsAnimationControllerCompat controller,
             boolean allowMinimizeSplitScreen,
@@ -132,14 +135,22 @@
 
     @UiThread
     public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) {
+        if (mFinishRequested) {
+            // If finishing, add to pending finish callbacks, otherwise, if finished, adding to the
+            // destroyed RunnableList will just trigger the callback to be called immediately
+            mPendingFinishCallbacks.add(callback);
+            return;
+        }
+
+        // Finish not yet requested
+        mFinishRequested = true;
         mOnFinishedListener.accept(this);
+        mPendingFinishCallbacks.add(callback);
         UI_HELPER_EXECUTOR.execute(() -> {
             mController.finish(toRecents, sendUserLeaveHint);
             InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
             InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
-            if (callback != null) {
-                MAIN_EXECUTOR.execute(callback);
-            }
+            MAIN_EXECUTOR.execute(mPendingFinishCallbacks::executeAllAndDestroy);
         });
     }
 
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index b4f1330..ef09957 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -54,6 +54,7 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.Surface;
 
@@ -61,6 +62,7 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
 import com.android.launcher3.util.DisplayController.Info;
@@ -127,14 +129,27 @@
     private boolean mIsUserSetupComplete;
 
     public RecentsAnimationDeviceState(Context context) {
+        this(context, false);
+    }
+
+    /**
+     * @param isInstanceForTouches {@code true} if this is the persistent instance being used for
+     *                                   gesture touch handling
+     */
+    public RecentsAnimationDeviceState(Context context, boolean isInstanceForTouches) {
         mContext = context;
         mDisplayController = DisplayController.INSTANCE.get(context);
         mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context);
         mDisplayId = mDisplayController.getInfo().id;
         mIsOneHandedModeSupported = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false);
         runOnDestroy(() -> mDisplayController.removeChangeListener(this));
-        mRotationTouchHelper = new RotationTouchHelper(context, mDisplayController);
-        runOnDestroy(mRotationTouchHelper::destroy);
+        mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(context);
+        if (isInstanceForTouches) {
+            // rotationTouchHelper doesn't get initialized after being destroyed, so only destroy
+            // if primary TouchInteractionService instance needs to be destroyed.
+            mRotationTouchHelper.init();
+            runOnDestroy(mRotationTouchHelper::destroy);
+        }
 
         // Register for user unlocked if necessary
         mIsUserUnlocked = context.getSystemService(UserManager.class)
@@ -214,6 +229,7 @@
      * Cleans up all the registered listeners and receivers.
      */
     public void destroy() {
+        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "destroying RADS", new Throwable());
         for (Runnable r : mOnDestroyActions) {
             r.run();
         }
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index f4688a1..fd0de42 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -24,6 +24,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.OrientationEventListener;
 
@@ -31,6 +32,7 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
 import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -43,10 +45,13 @@
         SysUINavigationMode.NavigationModeChangeListener,
         DisplayInfoChangeListener {
 
-    private final OrientationTouchTransformer mOrientationTouchTransformer;
-    private final DisplayController mDisplayController;
-    private final SysUINavigationMode mSysUiNavMode;
-    private final int mDisplayId;
+    public static final MainThreadInitializedObject<RotationTouchHelper> INSTANCE =
+            new MainThreadInitializedObject<>(RotationTouchHelper::new);
+
+    private OrientationTouchTransformer mOrientationTouchTransformer;
+    private DisplayController mDisplayController;
+    private SysUINavigationMode mSysUiNavMode;
+    private int mDisplayId;
     private int mDisplayRotation;
 
     private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
@@ -117,25 +122,46 @@
      */
     private boolean mInOverview;
     private boolean mTaskListFrozen;
-
-
     private final Context mContext;
 
-    public RotationTouchHelper(Context context, DisplayController displayController) {
+    /**
+     * Keeps track of whether destroy has been called for this instance. Mainly used for TAPL tests
+     * where multiple instances of RotationTouchHelper are being created. b/177316094
+     */
+    private boolean mNeedsInit = true;
+
+    private RotationTouchHelper(Context context) {
         mContext = context;
-        mDisplayController = displayController;
+        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "RotationTouchHelper ctor init? " + mNeedsInit
+                + " " + this);
+        if (mNeedsInit) {
+            init();
+        }
+    }
+
+    public void init() {
+        if (!mNeedsInit) {
+            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "Did not need init? " + " " + this);
+            return;
+        }
+        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "RotationTouchHelper init() " + this,
+                new Throwable());
+        mDisplayController = DisplayController.INSTANCE.get(mContext);
         Resources resources = mContext.getResources();
-        mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context);
+        mSysUiNavMode = SysUINavigationMode.INSTANCE.get(mContext);
         mDisplayId = mDisplayController.getInfo().id;
 
         mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode,
                 () -> QuickStepContract.getWindowCornerRadius(resources));
 
         // Register for navigation mode changes
-        onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
+        SysUINavigationMode.Mode newMode = mSysUiNavMode.addModeChangeListener(this);
+        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "AddedModeChangeListener: " + this +
+                " currentMode: " + newMode);
+        onNavigationModeChanged(newMode);
         runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
 
-        mOrientationListener = new OrientationEventListener(context) {
+        mOrientationListener = new OrientationEventListener(mContext) {
             @Override
             public void onOrientationChanged(int degrees) {
                 int newRotation = RecentsOrientedState.getRotationForUserDegreesRotated(degrees,
@@ -154,6 +180,7 @@
                 }
             }
         };
+        mNeedsInit = false;
     }
 
     private void setupOrientationSwipeHandler() {
@@ -176,9 +203,11 @@
      * Cleans up all the registered listeners and receivers.
      */
     public void destroy() {
+        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "destroying " + this);
         for (Runnable r : mOnDestroyActions) {
             r.run();
         }
+        mNeedsInit = true;
     }
 
     public boolean isTaskListFrozen() {
@@ -223,6 +252,7 @@
 
     @Override
     public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
+        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "nav mode changed: " + newMode);
         mDisplayController.removeChangeListener(this);
         mDisplayController.addChangeListener(this);
         onDisplayInfoChanged(mContext, mDisplayController.getInfo(), CHANGE_ALL);
@@ -374,4 +404,8 @@
         pw.println("  displayRotation=" + getDisplayRotation());
         mOrientationTouchTransformer.dump(pw);
     }
+
+    public OrientationTouchTransformer getOrientationTouchTransformer() {
+        return mOrientationTouchTransformer;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index b6dad2d..c87cd17 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -86,6 +86,7 @@
     @UiThread
     public RecentsAnimationCallbacks startRecentsAnimation(GestureState gestureState,
             Intent intent, RecentsAnimationCallbacks.RecentsAnimationListener listener) {
+        Log.d("b/186444448", "startRecentsAnimation");
         // Notify if recents animation is still running
         if (mController != null) {
             String msg = "New recents animation started before old animation completed";
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 18c0b7a..4fc9770 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -300,7 +300,9 @@
         // Everything else should be initialized in onUserUnlocked() below.
         mMainChoreographer = Choreographer.getInstance();
         mAM = ActivityManagerWrapper.getInstance();
-        mDeviceState = new RecentsAnimationDeviceState(this);
+        mDeviceState = new RecentsAnimationDeviceState(this, true);
+            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "RADS OTT instance: " +
+                    mDeviceState.getRotationTouchHelper().getOrientationTouchTransformer());
         mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
         mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
         mDeviceState.addOneHandedModeChangedCallback(this::onOneHandedModeOverlayChanged);
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 8962ec9..7067dbc 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -20,6 +20,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCRIM_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
@@ -95,5 +96,8 @@
         setter.setFloat(mRecentsView, FULLSCREEN_PROGRESS, state.isFullScreen() ? 1 : 0, LINEAR);
         setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS,
                 state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()) ? 1f : 0f, LINEAR);
+
+        setter.setViewBackgroundColor(mActivity.getScrimView(), state.getScrimColor(mActivity),
+                config.getInterpolator(ANIM_WORKSPACE_SCRIM_FADE, LINEAR));
     }
 }
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsDragLayer.java b/quickstep/src/com/android/quickstep/fallback/RecentsDragLayer.java
index a00015a..29c3dc8 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsDragLayer.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsDragLayer.java
@@ -16,11 +16,8 @@
 package com.android.quickstep.fallback;
 
 import android.content.Context;
-import android.graphics.Rect;
 import android.util.AttributeSet;
 
-import com.android.launcher3.R;
-import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.quickstep.RecentsActivity;
@@ -41,12 +38,4 @@
                 new FallbackNavBarTouchController(mActivity),
         };
     }
-
-    @Override
-    public void setInsets(Rect insets) {
-        super.setInsets(insets);
-        setBackground(insets.top == 0  || !mAllowSysuiScrims
-                ? null
-                : Themes.getAttrDrawable(getContext(), R.attr.workspaceStatusBarScrim));
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index bbe279e..b3d6cfa 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -19,10 +19,13 @@
 import static com.android.launcher3.uioverrides.states.OverviewModalTaskState.getOverviewScaleAndOffsetForModalState;
 
 import android.content.Context;
+import android.graphics.Color;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.util.Themes;
 import com.android.quickstep.RecentsActivity;
 
 /**
@@ -35,12 +38,13 @@
     private static final int FLAG_FULL_SCREEN = BaseState.getFlag(2);
     private static final int FLAG_OVERVIEW_ACTIONS = BaseState.getFlag(3);
     private static final int FLAG_SHOW_AS_GRID = BaseState.getFlag(4);
+    private static final int FLAG_SCRIM = BaseState.getFlag(5);
 
     public static final RecentsState DEFAULT = new RecentsState(0,
-            FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_SHOW_AS_GRID);
+            FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_SHOW_AS_GRID | FLAG_SCRIM);
     public static final RecentsState MODAL_TASK = new ModalState(1,
             FLAG_DISABLE_RESTORE | FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_MODAL
-                    | FLAG_SHOW_AS_GRID);
+                    | FLAG_SHOW_AS_GRID | FLAG_SCRIM);
     public static final RecentsState BACKGROUND_APP = new BackgroundAppState(2,
             FLAG_DISABLE_RESTORE | FLAG_NON_INTERACTIVE | FLAG_FULL_SCREEN);
     public static final RecentsState HOME = new RecentsState(3, 0);
@@ -103,6 +107,14 @@
         return hasFlag(FLAG_OVERVIEW_ACTIONS);
     }
 
+    /**
+     * For this state, what color scrim should be drawn behind overview.
+     */
+    public int getScrimColor(RecentsActivity activity) {
+        return hasFlag(FLAG_SCRIM) ? Themes.getAttrColor(activity, R.attr.overviewScrimColor)
+                : Color.TRANSPARENT;
+    }
+
     public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
         return new float[] { NO_SCALE, NO_OFFSET };
     }
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index de6c4f5..ab95138 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -140,7 +140,7 @@
 
         addDepthAnimationForState(launcher, NORMAL, DURATION_MS);
 
-        mAnimators.play(launcher.getDragLayer().getSysUiScrim().createSysuiMultiplierAnim(0f, 1f)
+        mAnimators.play(launcher.getRootView().getSysUiScrim().createSysuiMultiplierAnim(0f, 1f)
                 .setDuration(DURATION_MS));
         mAnimators.addListener(new AnimatorListenerAdapter() {
             @Override
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
new file mode 100644
index 0000000..f74aa55
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Outline;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.widget.RemoteViews.RemoteViewOutlineProvider;
+
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.RoundedCornerEnforcement;
+
+import java.util.stream.IntStream;
+
+/**
+ * Mimics the appearance of the background view of a {@link LauncherAppWidgetHostView} through a
+ * an App Widget activity launch animation.
+ */
+@TargetApi(Build.VERSION_CODES.S)
+final class FloatingWidgetBackgroundView extends View {
+    private final ColorDrawable mFallbackDrawable = new ColorDrawable();
+    private final DrawableProperties mForegroundProperties = new DrawableProperties();
+    private final DrawableProperties mBackgroundProperties = new DrawableProperties();
+
+    private Drawable mOriginalForeground;
+    private Drawable mOriginalBackground;
+    private float mFinalRadius;
+    private float mInitialOutlineRadius;
+    private float mOutlineRadius;
+    private boolean mIsUsingFallback;
+    private View mSourceView;
+
+    FloatingWidgetBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius);
+            }
+        });
+        setClipToOutline(true);
+    }
+
+    void init(LauncherAppWidgetHostView hostView, View backgroundView, float finalRadius) {
+        mFinalRadius = finalRadius;
+        mSourceView = backgroundView;
+        mInitialOutlineRadius = getOutlineRadius(hostView, backgroundView);
+        mIsUsingFallback = false;
+        if (isSupportedDrawable(backgroundView.getForeground())) {
+            mOriginalForeground = backgroundView.getForeground();
+            mForegroundProperties.init(
+                    mOriginalForeground.getConstantState().newDrawable().mutate());
+            setForeground(mForegroundProperties.mDrawable);
+            mSourceView.setForeground(null);
+        }
+        if (isSupportedDrawable(backgroundView.getBackground())) {
+            mOriginalBackground = backgroundView.getBackground();
+            mBackgroundProperties.init(
+                    mOriginalBackground.getConstantState().newDrawable().mutate());
+            setBackground(mBackgroundProperties.mDrawable);
+            mSourceView.setBackground(null);
+        } else if (mOriginalForeground == null) {
+            mFallbackDrawable.setColor(Themes.getColorBackground(backgroundView.getContext()));
+            setBackground(mFallbackDrawable);
+            mIsUsingFallback = true;
+        }
+    }
+
+    /** Update the animated properties of the drawables. */
+    void update(float cornerRadiusProgress, float fallbackAlpha) {
+        if (isUninitialized()) return;
+        mOutlineRadius = mInitialOutlineRadius + (mFinalRadius - mInitialOutlineRadius)
+                * cornerRadiusProgress;
+        mForegroundProperties.updateDrawable(mFinalRadius, cornerRadiusProgress);
+        mBackgroundProperties.updateDrawable(mFinalRadius, cornerRadiusProgress);
+        setAlpha(mIsUsingFallback ? fallbackAlpha : 1f);
+    }
+
+    /** Restores the drawables to the source view. */
+    void finish() {
+        if (isUninitialized()) return;
+        mSourceView.setForeground(mOriginalForeground);
+        mSourceView.setBackground(mOriginalBackground);
+    }
+
+    void recycle() {
+        mSourceView = null;
+        mOriginalForeground = null;
+        mOriginalBackground = null;
+        mOutlineRadius = 0;
+        mFinalRadius = 0;
+        setForeground(null);
+        setBackground(null);
+    }
+
+    /** Get the largest of drawable corner radii or background view outline radius. */
+    float getMaximumRadius() {
+        if (isUninitialized()) return 0;
+        return Math.max(mInitialOutlineRadius, Math.max(getMaxRadius(mOriginalForeground),
+                getMaxRadius(mOriginalBackground)));
+    }
+
+    private boolean isUninitialized() {
+        return mSourceView == null;
+    }
+
+    /** Returns the maximum corner radius of {@param drawable}. */
+    private static float getMaxRadius(Drawable drawable) {
+        if (!(drawable instanceof GradientDrawable)) return 0;
+        float[] cornerRadii = ((GradientDrawable) drawable).getCornerRadii();
+        float cornerRadius = ((GradientDrawable) drawable).getCornerRadius();
+        double radiiMax = cornerRadii == null ? 0 : IntStream.range(0, cornerRadii.length)
+                .mapToDouble(i -> cornerRadii[i]).max().orElse(0);
+        return Math.max(cornerRadius, (float) radiiMax);
+    }
+
+    /** Returns whether the given drawable type is supported. */
+    private static boolean isSupportedDrawable(Drawable drawable) {
+        return drawable instanceof ColorDrawable || (drawable instanceof GradientDrawable
+                && ((GradientDrawable) drawable).getShape() == GradientDrawable.RECTANGLE);
+    }
+
+    /** Corner radius from source view's outline, or enforced view. */
+    private static float getOutlineRadius(LauncherAppWidgetHostView hostView, View v) {
+        if (RoundedCornerEnforcement.isRoundedCornerEnabled()
+                && hostView.hasEnforcedCornerRadius()) {
+            return hostView.getEnforcedCornerRadius();
+        } else if (v.getOutlineProvider() instanceof RemoteViewOutlineProvider
+                && v.getClipToOutline()) {
+            return ((RemoteViewOutlineProvider) v.getOutlineProvider()).getRadius();
+        }
+        return 0;
+    }
+
+    /** Stores and modifies a drawable's properties through an animation. */
+    private static class DrawableProperties {
+        private Drawable mDrawable;
+        private float mOriginalRadius;
+        private float[] mOriginalRadii;
+        private final float[] mTmpRadii = new float[8];
+
+        /** Store a drawable's animated properties. */
+        void init(Drawable drawable) {
+            mDrawable = drawable;
+            if (!(drawable instanceof GradientDrawable)) return;
+            mOriginalRadius = ((GradientDrawable) drawable).getCornerRadius();
+            mOriginalRadii = ((GradientDrawable) drawable).getCornerRadii();
+        }
+
+        /**
+         * Update the drawable for the given animation state.
+         *
+         * @param finalRadius the radius of each corner when {@param progress} is 1
+         * @param progress    the linear progress of the corner radius from its original value to
+         *                    {@param finalRadius}
+         */
+        void updateDrawable(float finalRadius, float progress) {
+            if (!(mDrawable instanceof GradientDrawable)) return;
+            GradientDrawable d = (GradientDrawable) mDrawable;
+            if (mOriginalRadii != null) {
+                for (int i = 0; i < mOriginalRadii.length; i++) {
+                    mTmpRadii[i] = mOriginalRadii[i] + (finalRadius - mOriginalRadii[i]) * progress;
+                }
+                d.setCornerRadii(mTmpRadii);
+            } else {
+                d.setCornerRadius(mOriginalRadius + (finalRadius - mOriginalRadius) * progress);
+            }
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
new file mode 100644
index 0000000..d23884c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.GhostView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.views.ListenerView;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.RoundedCornerEnforcement;
+
+/** A view that mimics an App Widget through a launch animation. */
+@TargetApi(Build.VERSION_CODES.S)
+public class FloatingWidgetView extends FrameLayout implements AnimatorListener {
+    private static final Matrix sTmpMatrix = new Matrix();
+
+    private final Launcher mLauncher;
+    private final ListenerView mListenerView;
+    private final FloatingWidgetBackgroundView mBackgroundView;
+    private final RectF mBackgroundOffset = new RectF();
+
+    private LauncherAppWidgetHostView mAppWidgetView;
+    private View mAppWidgetBackgroundView;
+    private RectF mBackgroundPosition;
+    private GhostView mForegroundOverlayView;
+
+    private Runnable mEndRunnable;
+    private Runnable mFastFinishRunnable;
+
+    public FloatingWidgetView(Context context) {
+        this(context, null);
+    }
+
+    public FloatingWidgetView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public FloatingWidgetView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mLauncher = Launcher.getLauncher(context);
+        mListenerView = new ListenerView(context, attrs);
+        mBackgroundView = new FloatingWidgetBackgroundView(context, attrs, defStyleAttr);
+        addView(mBackgroundView);
+        setWillNotDraw(false);
+    }
+
+    @Override
+    public void onAnimationEnd(Animator animator) {
+        Runnable endRunnable = mEndRunnable;
+        mEndRunnable = null;
+        if (endRunnable != null) {
+            endRunnable.run();
+        }
+    }
+
+    @Override
+    public void onAnimationStart(Animator animator) {
+    }
+
+    @Override
+    public void onAnimationCancel(Animator animator) {
+    }
+
+    @Override
+    public void onAnimationRepeat(Animator animator) {
+    }
+
+    /** Sets a runnable that is called after a call to {@link #fastFinish()}. */
+    public void setFastFinishRunnable(Runnable runnable) {
+        mFastFinishRunnable = runnable;
+    }
+
+    /** Callback at the end or early exit of the animation. */
+    public void fastFinish() {
+        if (isUninitialized()) return;
+        Runnable fastFinishRunnable = mFastFinishRunnable;
+        if (fastFinishRunnable != null) {
+            fastFinishRunnable.run();
+        }
+        Runnable endRunnable = mEndRunnable;
+        mEndRunnable = null;
+        if (endRunnable != null) {
+            endRunnable.run();
+        }
+    }
+
+    private void init(DragLayer dragLayer, LauncherAppWidgetHostView originalView,
+            RectF widgetBackgroundPosition, Rect windowTargetBounds, float windowCornerRadius) {
+        mAppWidgetView = originalView;
+        mAppWidgetView.beginDeferringUpdates();
+        mBackgroundPosition = widgetBackgroundPosition;
+        mEndRunnable = () -> finish(dragLayer);
+
+        mAppWidgetBackgroundView = RoundedCornerEnforcement.findBackground(mAppWidgetView);
+        if (mAppWidgetBackgroundView == null) {
+            mAppWidgetBackgroundView = mAppWidgetView;
+        }
+
+        getRelativePosition(mAppWidgetBackgroundView, dragLayer, mBackgroundPosition);
+        getRelativePosition(mAppWidgetBackgroundView, mAppWidgetView, mBackgroundOffset);
+        mBackgroundView.init(mAppWidgetView, mAppWidgetBackgroundView, windowCornerRadius);
+        // Layout call before GhostView creation so that the overlaid view isn't clipped
+        layout(0, 0, windowTargetBounds.width(), windowTargetBounds.height());
+        mForegroundOverlayView = GhostView.addGhost(mAppWidgetView, this);
+        positionViews();
+
+        mListenerView.setListener(this::fastFinish);
+        dragLayer.addView(mListenerView);
+    }
+
+    /**
+     * Updates the position and opacity of the floating widget's components.
+     *
+     * @param backgroundPosition      the new position of the widget's background relative to the
+     *                                {@link FloatingWidgetView}'s parent
+     * @param floatingWidgetAlpha     the overall opacity of the {@link FloatingWidgetView}
+     * @param foregroundAlpha         the opacity of the foreground layer
+     * @param fallbackBackgroundAlpha the opacity of the fallback background used when the App
+     *                                Widget doesn't have a background
+     * @param cornerRadiusProgress    progress of the corner radius animation, where 0 is the
+     *                                original radius and 1 is the window radius
+     */
+    public void update(RectF backgroundPosition, float floatingWidgetAlpha, float foregroundAlpha,
+            float fallbackBackgroundAlpha, float cornerRadiusProgress) {
+        if (isUninitialized()) return;
+        setAlpha(floatingWidgetAlpha);
+        mBackgroundView.update(cornerRadiusProgress, fallbackBackgroundAlpha);
+        mAppWidgetView.setAlpha(foregroundAlpha);
+        mBackgroundPosition = backgroundPosition;
+        positionViews();
+    }
+
+    /** Sets the layout parameters of the floating view and its background view child. */
+    private void positionViews() {
+        LayoutParams layoutParams = (LayoutParams) getLayoutParams();
+        layoutParams.setMargins(0, 0, 0, 0);
+        setLayoutParams(layoutParams);
+
+        // FloatingWidgetView layout is forced LTR
+        mBackgroundView.setTranslationX(mBackgroundPosition.left);
+        mBackgroundView.setTranslationY(mBackgroundPosition.top);
+        LayoutParams backgroundParams = (LayoutParams) mBackgroundView.getLayoutParams();
+        backgroundParams.leftMargin = 0;
+        backgroundParams.topMargin = 0;
+        backgroundParams.width = (int) mBackgroundPosition.width();
+        backgroundParams.height = (int) mBackgroundPosition.height();
+        mBackgroundView.setLayoutParams(backgroundParams);
+
+        sTmpMatrix.reset();
+        float foregroundScale = mBackgroundPosition.width() / mAppWidgetBackgroundView.getWidth();
+        sTmpMatrix.setTranslate(-mBackgroundOffset.left - mAppWidgetView.getLeft(),
+                -mBackgroundOffset.top - mAppWidgetView.getTop());
+        sTmpMatrix.postScale(foregroundScale, foregroundScale);
+        sTmpMatrix.postTranslate(mBackgroundPosition.left, mBackgroundPosition.top);
+        mForegroundOverlayView.setMatrix(sTmpMatrix);
+    }
+
+    private void finish(DragLayer dragLayer) {
+        mAppWidgetView.setAlpha(1f);
+        GhostView.removeGhost(mAppWidgetView);
+        ((ViewGroup) dragLayer.getParent()).removeView(this);
+        dragLayer.removeView(mListenerView);
+        mBackgroundView.finish();
+        mAppWidgetView.endDeferringUpdates();
+        recycle();
+        mLauncher.getViewCache().recycleView(R.layout.floating_widget_view, this);
+    }
+
+    public float getInitialCornerRadius() {
+        return mBackgroundView.getMaximumRadius();
+    }
+
+    private boolean isUninitialized() {
+        return mForegroundOverlayView == null;
+    }
+
+    private void recycle() {
+        mEndRunnable = null;
+        mFastFinishRunnable = null;
+        mBackgroundPosition = null;
+        mListenerView.setListener(null);
+        mAppWidgetView = null;
+        mForegroundOverlayView = null;
+        mAppWidgetBackgroundView = null;
+        mBackgroundView.recycle();
+    }
+
+    /**
+     * Configures and returns a an instance of {@link FloatingWidgetView} matching the appearance of
+     * {@param originalView}.
+     *
+     * @param widgetBackgroundPosition a {@link RectF} that will be updated with the widget's
+     *                                 background bounds
+     * @param windowTargetBounds       the bounds of the window when launched
+     * @param windowCornerRadius       the corner radius of the window
+     */
+    public static FloatingWidgetView getFloatingWidgetView(Launcher launcher,
+            LauncherAppWidgetHostView originalView, RectF widgetBackgroundPosition,
+            Rect windowTargetBounds, float windowCornerRadius) {
+        final DragLayer dragLayer = launcher.getDragLayer();
+        ViewGroup parent = (ViewGroup) dragLayer.getParent();
+        FloatingWidgetView floatingView =
+                launcher.getViewCache().getView(R.layout.floating_widget_view, launcher, parent);
+        floatingView.recycle();
+
+        floatingView.init(dragLayer, originalView, widgetBackgroundPosition, windowTargetBounds,
+                windowCornerRadius);
+        parent.addView(floatingView);
+        return floatingView;
+    }
+
+    private static void getRelativePosition(View descendant, View ancestor, RectF position) {
+        float[] points = new float[]{0, 0, descendant.getWidth(), descendant.getHeight()};
+        Utilities.getDescendantCoordRelativeToAncestor(descendant, ancestor, points,
+                false /* includeRootScroll */);
+        position.set(
+                Math.min(points[0], points[2]),
+                Math.min(points[1], points[3]),
+                Math.max(points[0], points[2]),
+                Math.max(points[1], points[3]));
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 41076f3..e5ce950 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -45,7 +45,7 @@
 import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
+import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
 import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
 import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
@@ -450,7 +450,6 @@
 
     private boolean mRunningTaskIconScaledDown = false;
 
-    private final boolean mHasLightBackground;
     private boolean mOverviewStateEnabled;
     private boolean mHandleTaskStackChanges;
     private boolean mSwipeDownShouldLaunchApp;
@@ -584,8 +583,6 @@
         mLiveTileTaskViewSimulator.recentsViewScale.value = 1;
         mLiveTileTaskViewSimulator.setOrientationState(mOrientationState);
         mLiveTileTaskViewSimulator.setDrawsBelowRecents(true);
-
-        mHasLightBackground = Themes.getAttrBoolean(mActivity, android.R.attr.isLightTheme);
     }
 
     public OverScroller getScroller() {
@@ -908,13 +905,6 @@
                 cancelSplitSelect(false);
             }
         }
-
-        if (enabled) {
-            mActivity.getSystemUiController().updateUiState(
-                    UI_STATE_OVERVIEW, hasLightBackground());
-        } else {
-            mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
-        }
     }
 
     /**
@@ -1277,23 +1267,20 @@
         }
 
         float accumulatedTranslationX = 0;
-        float[] fullscreenTranslations = new float[taskCount];
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = getTaskViewAt(i);
             taskView.updateTaskSize();
-            fullscreenTranslations[i] += accumulatedTranslationX;
+            taskView.getPrimaryFullscreenTranslationProperty().set(taskView,
+                    accumulatedTranslationX);
+            taskView.getSecondaryFullscreenTranslationProperty().set(taskView, 0f);
             // Compensate space caused by TaskView scaling.
             float widthDiff =
                     taskView.getLayoutParams().width * (1 - taskView.getFullscreenScale());
             // Compensate page spacing widening caused by RecentsView scaling.
             widthDiff += mPageSpacing * (1 - 1 / mFullscreenScale);
-            float fullscreenTranslationX = mIsRtl ? widthDiff : -widthDiff;
-            accumulatedTranslationX += fullscreenTranslationX;
+            accumulatedTranslationX += mIsRtl ? widthDiff : -widthDiff;
         }
 
-        for (int i = 0; i < taskCount; i++) {
-            getTaskViewAt(i).setFullscreenTranslationX(fullscreenTranslations[i]);
-        }
         mClearAllButton.setFullscreenTranslationPrimary(accumulatedTranslationX);
 
         updateGridProperties();
@@ -1526,7 +1513,6 @@
 
         unloadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
         setCurrentPage(0);
-        mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
         LayoutUtils.setViewEnabled(mActionsView, true);
         if (mOrientationState.setGestureActive(false)) {
             updateOrientationHandler();
@@ -1600,8 +1586,9 @@
      * {@link #onGestureAnimationStart} and {@link #onGestureAnimationEnd()}.
      */
     public void onSwipeUpAnimationSuccess() {
+        Log.d("b/186444448", "onSwipeUpAnimationSuccess");
         if (getRunningTaskView() != null) {
-            animateUpRunningTaskIconScale(0f);
+            animateUpRunningTaskIconScale();
         }
         setSwipeDownShouldLaunchApp(true);
     }
@@ -1664,20 +1651,22 @@
      * Called when a gesture from an app has finished, and the animation to the target has ended.
      */
     public void onGestureAnimationEnd() {
+        Log.d("b/186444448", "onGestureEnd");
         mGestureActive = false;
         if (mOrientationState.setGestureActive(false)) {
             updateOrientationHandler();
         }
 
         setEnableFreeScroll(true);
-        setEnableDrawingLiveTile(true);
+        setEnableDrawingLiveTile(mCurrentGestureEndTarget == GestureState.GestureEndTarget.RECENTS);
         if (!LIVE_TILE.get()) {
             setRunningTaskViewShowScreenshot(true);
         }
         setRunningTaskHidden(false);
         animateUpRunningTaskIconScale();
 
-        if (!showAsGrid() || getFocusedTaskView() != null) {
+        if (mCurrentGestureEndTarget == GestureState.GestureEndTarget.RECENTS
+                && (!showAsGrid() || getFocusedTaskView() != null)) {
             animateActionsViewIn();
         }
 
@@ -1817,15 +1806,13 @@
     }
 
     public void animateUpRunningTaskIconScale() {
-        animateUpRunningTaskIconScale(0);
-    }
-
-    public void animateUpRunningTaskIconScale(float startProgress) {
         mRunningTaskIconScaledDown = false;
         TaskView firstTask = getRunningTaskView();
+        Log.d("b/186444448", "animateUpRunningTaskIconScale: firstTask="
+                + (firstTask != null ? "t:" + firstTask.getTask() : null));
         if (firstTask != null) {
+            firstTask.setIconScaleAnimStartProgress(0f);
             firstTask.animateIconScaleAndDimIntoView();
-            firstTask.setIconScaleAnimStartProgress(startProgress);
         }
     }
 
@@ -1997,29 +1984,12 @@
                 gridTranslationAnimators.add(taskDismissAnimator);
             }
             taskView.setGridTranslationX(gridTranslations[i] - snappedTaskGridTranslationX);
-            taskView.setNonFullscreenTranslationX(snappedTaskFullscreenScrollAdjustment);
+            taskView.getPrimaryNonFullscreenTranslationProperty().set(taskView,
+                    snappedTaskFullscreenScrollAdjustment);
+            taskView.getSecondaryNonFullscreenTranslationProperty().set(taskView, 0f);
         }
         AnimatorSet gridTranslationAnimatorSet = new AnimatorSet();
         gridTranslationAnimatorSet.playTogether(gridTranslationAnimators);
-        gridTranslationAnimatorSet.addListener(new AnimatorListenerAdapter() {
-            @Override
-            // Allow the actions view to display again once in focus mode
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                if (getFocusedTaskView() == null) {
-                    mActionsView.getScrollAlpha().setValue(1);
-                }
-            }
-
-            @Override
-            // Hide the actions view if not in focus mode
-            public void onAnimationStart(Animator animation) {
-                super.onAnimationStart(animation);
-                if (getFocusedTaskView() == null) {
-                    mActionsView.getScrollAlpha().setValue(0);
-                }
-            }
-        });
         gridTranslationAnimatorSet.start();
 
         // Use the accumulated translation of the row containing the last task.
@@ -2322,7 +2292,8 @@
                         snapToPageImmediately(pageToSnapTo);
                         // Grid got messed up, reapply.
                         updateGridProperties(taskView, draggedIndex - mTaskViewStartIndex);
-                        if (showAsGrid() && getFocusedTaskView() == null) {
+                        if (showAsGrid() && getFocusedTaskView() == null
+                                && mActionsView.getVisibilityAlpha().getValue() == 1) {
                             animateActionsViewOut();
                         }
                     }
@@ -2819,14 +2790,6 @@
         }
     }
 
-    /**
-     * True if the background scrim of the recents view is light colored and the foreground elements
-     * should use dark colors.
-     */
-    public boolean hasLightBackground() {
-        return mHasLightBackground;
-    }
-
     public void initiateSplitSelect(TaskView taskView, SplitPositionOption splitPositionOption) {
         mSplitHiddenTaskView = taskView;
         SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
@@ -3077,10 +3040,9 @@
             // tasks' flags
             if (animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD) {
                 mActivity.getSystemUiController().updateUiState(
-                        UI_STATE_OVERVIEW, targetSysUiFlags);
+                        UI_STATE_FULLSCREEN_TASK, targetSysUiFlags);
             } else {
-                mActivity.getSystemUiController().updateUiState(
-                        UI_STATE_OVERVIEW, hasLightBackground());
+                mActivity.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
             }
 
             // Passing the threshold from taskview to fullscreen app will vibrate
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 35acdd1..3349b74 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -250,6 +250,58 @@
                 }
             };
 
+    private static final FloatProperty<TaskView> FULLSCREEN_TRANSLATION_X =
+            new FloatProperty<TaskView>("fullscreenTranslationX") {
+                @Override
+                public void setValue(TaskView taskView, float v) {
+                    taskView.setFullscreenTranslationX(v);
+                }
+
+                @Override
+                public Float get(TaskView taskView) {
+                    return taskView.mFullscreenTranslationX;
+                }
+            };
+
+    private static final FloatProperty<TaskView> FULLSCREEN_TRANSLATION_Y =
+            new FloatProperty<TaskView>("fullscreenTranslationY") {
+                @Override
+                public void setValue(TaskView taskView, float v) {
+                    taskView.setFullscreenTranslationY(v);
+                }
+
+                @Override
+                public Float get(TaskView taskView) {
+                    return taskView.mFullscreenTranslationY;
+                }
+            };
+
+    private static final FloatProperty<TaskView> NON_FULLSCREEN_TRANSLATION_X =
+            new FloatProperty<TaskView>("nonFullscreenTranslationX") {
+                @Override
+                public void setValue(TaskView taskView, float v) {
+                    taskView.setNonFullscreenTranslationX(v);
+                }
+
+                @Override
+                public Float get(TaskView taskView) {
+                    return taskView.mNonFullscreenTranslationX;
+                }
+            };
+
+    private static final FloatProperty<TaskView> NON_FULLSCREEN_TRANSLATION_Y =
+            new FloatProperty<TaskView>("nonFullscreenTranslationY") {
+                @Override
+                public void setValue(TaskView taskView, float v) {
+                    taskView.setNonFullscreenTranslationY(v);
+                }
+
+                @Override
+                public Float get(TaskView taskView) {
+                    return taskView.mNonFullscreenTranslationY;
+                }
+            };
+
     private static final FloatProperty<TaskView> COLOR_TINT =
             new FloatProperty<TaskView>("colorTint") {
                 @Override
@@ -284,9 +336,11 @@
     private float mTaskResistanceTranslationY;
     // The following translation variables should only be used in the same orientation as Launcher.
     private float mFullscreenTranslationX;
+    private float mFullscreenTranslationY;
     // Applied as a complement to fullscreenTranslation, for adjusting the carousel overview, or the
     // in transition carousel before forming the grid on tablets.
     private float mNonFullscreenTranslationX;
+    private float mNonFullscreenTranslationY;
     private float mBoxTranslationY;
     // The following grid translations scales with mGridProgress.
     private float mGridTranslationX;
@@ -740,6 +794,8 @@
     }
 
     public void animateIconScaleAndDimIntoView() {
+        Log.d("b/186444448", "animateIconScaleAndDimIntoView: startProgress="
+                + mIconScaleAnimStartProgress);
         if (mIconAndDimAnimator != null) {
             mIconAndDimAnimator.cancel();
         }
@@ -749,6 +805,7 @@
         mIconAndDimAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
+                Log.d("b/186444448", "animateIconScaleAndDimIntoView: end");
                 mIconAndDimAnimator = null;
             }
         });
@@ -786,8 +843,9 @@
 
     @Override
     public void onRecycle() {
-        mFullscreenTranslationX = mNonFullscreenTranslationX =
-                mGridTranslationX = mGridTranslationY = mBoxTranslationY = 0f;
+        mFullscreenTranslationX = mFullscreenTranslationY = mNonFullscreenTranslationX =
+                mNonFullscreenTranslationY = mGridTranslationX = mGridTranslationY =
+                        mBoxTranslationY = 0f;
         resetViewTransforms();
         // Clear any references to the thumbnail (it will be re-read either from the cache or the
         // system on next bind)
@@ -929,16 +987,26 @@
         applyTranslationY();
     }
 
-    public void setFullscreenTranslationX(float fullscreenTranslationX) {
+    private void setFullscreenTranslationX(float fullscreenTranslationX) {
         mFullscreenTranslationX = fullscreenTranslationX;
         applyTranslationX();
     }
 
-    public void setNonFullscreenTranslationX(float nonFullscreenTranslationX) {
+    private void setFullscreenTranslationY(float fullscreenTranslationY) {
+        mFullscreenTranslationY = fullscreenTranslationY;
+        applyTranslationY();
+    }
+
+    private void setNonFullscreenTranslationX(float nonFullscreenTranslationX) {
         mNonFullscreenTranslationX = nonFullscreenTranslationX;
         applyTranslationX();
     }
 
+    private void setNonFullscreenTranslationY(float nonFullscreenTranslationY) {
+        mNonFullscreenTranslationY = nonFullscreenTranslationY;
+        applyTranslationY();
+    }
+
     public void setGridTranslationX(float gridTranslationX) {
         mGridTranslationX = gridTranslationX;
         applyTranslationX();
@@ -960,9 +1028,9 @@
     public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
         float scrollAdjustment = 0;
         if (fullscreenEnabled) {
-            scrollAdjustment += mFullscreenTranslationX;
+            scrollAdjustment += getPrimaryFullscreenTranslationProperty().get(this);
         } else {
-            scrollAdjustment += mNonFullscreenTranslationX;
+            scrollAdjustment += getPrimaryNonFullscreenTranslationProperty().get(this);
         }
         if (gridEnabled) {
             scrollAdjustment += mGridTranslationX;
@@ -1012,7 +1080,10 @@
      * change according to a temporary state (e.g. task offset).
      */
     public float getPersistentTranslationY() {
-        return getGridTrans(mGridTranslationY) + mBoxTranslationY;
+        return mBoxTranslationY
+                + getFullscreenTrans(mFullscreenTranslationY)
+                + getNonFullscreenTrans(mNonFullscreenTranslationY)
+                + getGridTrans(mGridTranslationY);
     }
 
     public FloatProperty<TaskView> getPrimaryDismissTranslationProperty() {
@@ -1035,6 +1106,26 @@
                 TASK_RESISTANCE_TRANSLATION_X, TASK_RESISTANCE_TRANSLATION_Y);
     }
 
+    public FloatProperty<TaskView> getPrimaryFullscreenTranslationProperty() {
+        return getPagedOrientationHandler().getPrimaryValue(
+                FULLSCREEN_TRANSLATION_X, FULLSCREEN_TRANSLATION_Y);
+    }
+
+    public FloatProperty<TaskView> getSecondaryFullscreenTranslationProperty() {
+        return getPagedOrientationHandler().getSecondaryValue(
+                FULLSCREEN_TRANSLATION_X, FULLSCREEN_TRANSLATION_Y);
+    }
+
+    public FloatProperty<TaskView> getPrimaryNonFullscreenTranslationProperty() {
+        return getPagedOrientationHandler().getPrimaryValue(
+                NON_FULLSCREEN_TRANSLATION_X, NON_FULLSCREEN_TRANSLATION_Y);
+    }
+
+    public FloatProperty<TaskView> getSecondaryNonFullscreenTranslationProperty() {
+        return getPagedOrientationHandler().getSecondaryValue(
+                NON_FULLSCREEN_TRANSLATION_X, NON_FULLSCREEN_TRANSLATION_Y);
+    }
+
     @Override
     public boolean hasOverlappingRendering() {
         // TODO: Clip-out the icon region from the thumbnail, since they are overlapping.
diff --git a/res/color-v31/overview_scrim.xml b/res/color-v31/overview_scrim.xml
new file mode 100644
index 0000000..8079995
--- /dev/null
+++ b/res/color-v31/overview_scrim.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:color="@android:color/system_neutral2_500" android:lStar="87" />
+</selector>
diff --git a/res/color-v31/overview_scrim_dark.xml b/res/color-v31/overview_scrim_dark.xml
new file mode 100644
index 0000000..b8ed774
--- /dev/null
+++ b/res/color-v31/overview_scrim_dark.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:color="@android:color/system_neutral1_800" />
+</selector>
diff --git a/res/color/overview_scrim.xml b/res/color/overview_scrim.xml
new file mode 100644
index 0000000..48cf576
--- /dev/null
+++ b/res/color/overview_scrim.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:color="#30000000" />
+</selector>
diff --git a/res/color/overview_scrim_dark.xml b/res/color/overview_scrim_dark.xml
new file mode 100644
index 0000000..48cf576
--- /dev/null
+++ b/res/color/overview_scrim_dark.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:color="#30000000" />
+</selector>
diff --git a/res/layout/floating_widget_view.xml b/res/layout/floating_widget_view.xml
new file mode 100644
index 0000000..eea7a92
--- /dev/null
+++ b/res/layout/floating_widget_view.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.quickstep.views.FloatingWidgetView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layoutDirection="ltr" />
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index f34e685..039d8d3 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -66,8 +66,7 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:id="@+id/scrim_view"
-            android:background="?attr/allAppsScrimColor"
-            android:alpha="0" />
+            android:background="@android:color/transparent" />
 
         <include
             android:id="@+id/apps_view"
diff --git a/res/layout/widgets_full_sheet_search_and_recommendations.xml b/res/layout/widgets_full_sheet_search_and_recommendations.xml
index e322c6c..bfce01d 100644
--- a/res/layout/widgets_full_sheet_search_and_recommendations.xml
+++ b/res/layout/widgets_full_sheet_search_and_recommendations.xml
@@ -46,7 +46,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:background="@drawable/widgets_recommendation_background"
-        android:paddingVertical="8dp"
+        android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
         android:layout_marginTop="16dp"
         android:visibility="gone"/>
 </LinearLayout>
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index f4b4130..f20af87 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -35,6 +35,7 @@
         tools:src="@drawable/ic_corp"/>
 
     <LinearLayout
+        android:id="@+id/app_container"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 2e17d44..24aabc5 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -130,7 +130,7 @@
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Добавить на главный экран"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Переместить элемент сюда"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент добавлен на главный экран"</string>
-    <string name="item_removed" msgid="851119963877842327">"Элемент удален"</string>
+    <string name="item_removed" msgid="851119963877842327">"Элемент удален."</string>
     <string name="undo" msgid="4151576204245173321">"Отменить"</string>
     <string name="action_move" msgid="4339390619886385032">"Переместить элемент"</string>
     <string name="move_to_empty_cell" msgid="2833711483015685619">"Переместить в ячейку <xliff:g id="NUMBER_0">%1$s</xliff:g> <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 24aac10..7f27bf8 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -17,9 +17,11 @@
 */
 -->
 <resources>
+    <color name="popup_color_neutral_light">@android:color/system_neutral1_0</color>
     <color name="popup_color_primary_light">@android:color/system_neutral1_50</color>
     <color name="popup_color_secondary_light">@android:color/system_neutral2_100</color>
     <color name="popup_color_tertiary_light">@android:color/system_neutral2_300</color>
+    <color name="popup_color_neutral_dark">@android:color/system_neutral1_1000</color>
     <color name="popup_color_primary_dark">@android:color/system_neutral1_800</color>
     <color name="popup_color_secondary_dark">@android:color/system_neutral1_900</color>
     <color name="popup_color_tertiary_dark">@android:color/system_neutral2_700</color>
@@ -30,4 +32,7 @@
     <color name="text_color_primary_dark">@android:color/system_neutral1_50</color>
     <color name="text_color_secondary_dark">@android:color/system_neutral2_200</color>
     <color name="text_color_tertiary_dark">@android:color/system_neutral2_400</color>
+
+    <color name="wallpaper_popup_scrim">@android:color/system_neutral1_900</color>
+
 </resources>
\ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index dbb40d5..9089a64 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -19,9 +19,9 @@
 
     <!-- Attributes used for launcher theme -->
     <attr name="allAppsScrimColor" format="color" />
-    <attr name="allAppsInterimScrimAlpha" format="integer" />
     <attr name="allAppsNavBarScrimColor" format="color" />
     <attr name="allAppsTheme" format="reference" />
+    <attr name="popupColorNeutral" format="color" />
     <attr name="popupColorPrimary" format="color" />
     <attr name="popupColorSecondary" format="color" />
     <attr name="popupColorTertiary" format="color" />
@@ -35,6 +35,7 @@
     <attr name="widgetsTheme" format="reference" />
     <attr name="iconOnlyShortcutColor" format="color" />
     <attr name="eduHalfSheetBGColor" format="color" />
+    <attr name="overviewScrimColor" format="color" />
 
     <attr name="folderDotColor" format="color" />
     <attr name="folderFillColor" format="color" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 7d48adf..83d2deb 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -41,9 +41,11 @@
     <color name="gesture_tutorial_action_button_label_color">#FF000000</color>
     <color name="gesture_tutorial_primary_color">#B7F29F</color> <!-- Light Green -->
 
+    <color name="popup_color_neutral_light">#FFF</color>
     <color name="popup_color_primary_light">#FFF</color>
     <color name="popup_color_secondary_light">#F1F3F4</color>
     <color name="popup_color_tertiary_light">#E0E0E0</color> <!-- Gray 300 -->
+    <color name="popup_color_neutral_dark">#3C4043</color> <!-- Gray 800 -->
     <color name="popup_color_primary_dark">#3C4043</color> <!-- Gray 800 -->
     <color name="popup_color_secondary_dark">#202124</color>
     <color name="popup_color_tertiary_dark">#757575</color> <!-- Gray 600 -->
@@ -55,4 +57,6 @@
     <color name="text_color_secondary_dark">#FFFFFFFF</color>
     <color name="text_color_tertiary_dark">#CCFFFFFF</color>
 
+    <color name="wallpaper_popup_scrim">?android:attr/colorAccent</color>
+
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index b75af7f..f8a517d 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -216,9 +216,6 @@
         <item>@dimen/c2_d</item>
     </array>
 
-    <string-array name="live_wallpapers_remove_sysui_scrims">
-    </string-array>
-
     <string-array name="filtered_components" ></string-array>
 
     <!-- Name of the class used to generate colors from the wallpaper colors. Must be implementing the LauncherAppWidgetHostView.ColorGenerator interface. -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 8a160bd..600a550 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -118,6 +118,7 @@
     <dimen name="widget_cell_horizontal_padding">16dp</dimen>
     <dimen name="widget_cell_font_size">14sp</dimen>
 
+    <dimen name="recommended_widgets_table_vertical_padding">8dp</dimen>
 
     <dimen name="widget_list_top_bottom_corner_radius">28dp</dimen>
     <dimen name="widget_list_content_corner_radius">4dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 37b7e2d..8d46f1c 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -32,9 +32,9 @@
     <style name="LauncherTheme" parent="@style/BaseLauncherTheme">
         <item name="android:textColorSecondary">#DE000000</item>
         <item name="allAppsScrimColor">?android:attr/colorBackgroundFloating</item>
-        <item name="allAppsInterimScrimAlpha">46</item>
         <item name="allAppsNavBarScrimColor">#66FFFFFF</item>
         <item name="allAppsTheme">@style/AllAppsTheme</item>
+        <item name="popupColorNeutral">@color/popup_color_neutral_light</item>
         <item name="popupColorPrimary">@color/popup_color_primary_light</item>
         <item name="popupColorSecondary">@color/popup_color_secondary_light</item>
         <item name="popupColorTertiary">@color/popup_color_tertiary_light</item>
@@ -57,6 +57,7 @@
         <item name="eduHalfSheetBGColor">?android:attr/colorAccent</item>
         <item name="disabledIconAlpha">.54</item>
         <item name="gridColor">?android:attr/colorAccent</item>
+        <item name="overviewScrimColor">@color/overview_scrim</item>
 
         <item name="android:windowTranslucentStatus">false</item>
         <item name="android:windowTranslucentNavigation">false</item>
@@ -76,7 +77,6 @@
 
     <style name="LauncherTheme.DarkText" parent="@style/LauncherTheme">
         <item name="workspaceTextColor">@color/workspace_text_color_dark</item>
-        <item name="allAppsInterimScrimAlpha">128</item>
         <item name="workspaceShadowColor">@android:color/transparent</item>
         <item name="workspaceAmbientShadowColor">@android:color/transparent</item>
         <item name="workspaceKeyShadowColor">@android:color/transparent</item>
@@ -96,9 +96,9 @@
         <item name="android:colorControlHighlight">#A0FFFFFF</item>
         <item name="android:colorPrimary">#FF212121</item>
         <item name="allAppsScrimColor">?android:attr/colorBackgroundFloating</item>
-        <item name="allAppsInterimScrimAlpha">102</item>
         <item name="allAppsNavBarScrimColor">#80000000</item>
         <item name="allAppsTheme">@style/AllAppsTheme.Dark</item>
+        <item name="popupColorNeutral">@color/popup_color_neutral_dark</item>
         <item name="popupColorPrimary">@color/popup_color_primary_dark</item>
         <item name="popupColorSecondary">@color/popup_color_secondary_dark</item>
         <item name="popupColorTertiary">@color/popup_color_tertiary_dark</item>
@@ -113,6 +113,7 @@
         <item name="iconOnlyShortcutColor">#B3FFFFFF</item>
         <item name="workProfileOverlayTextColor">@android:color/white</item>
         <item name="eduHalfSheetBGColor">#DD000000</item>
+        <item name="overviewScrimColor">@color/overview_scrim_dark</item>
     </style>
 
     <style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark">
@@ -123,7 +124,6 @@
 
     <style name="LauncherTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark">
         <item name="android:colorControlHighlight">#75212121</item>
-        <item name="allAppsInterimScrimAlpha">25</item>
         <item name="folderFillColor">#CDFFFFFF</item>
         <item name="folderTextColor">?attr/workspaceTextColor</item>
         <item name="workspaceTextColor">@color/workspace_text_color_dark</item>
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index f77f7e8..f64ce5c 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -17,7 +17,7 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
-import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
+import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -39,6 +39,7 @@
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.ViewCache;
 import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.ScrimView;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -157,6 +158,10 @@
         return mSystemUiController;
     }
 
+    public ScrimView getScrimView() {
+        return null;
+    }
+
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
@@ -197,7 +202,7 @@
 
         // Reset the overridden sysui flags used for the task-swipe launch animation, this is a
         // catch all for if we do not get resumed (and therefore not paused below)
-        getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
+        getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
     }
 
     @Override
@@ -209,7 +214,7 @@
         // here instead of at the end of the animation because the start of the new activity does
         // not happen immediately, which would cause us to reset to launcher's sysui flags and then
         // back to the new app (causing a flash)
-        getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
+        getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
     }
 
     @Override
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 4c5f9f2..2c76e52 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -18,8 +18,12 @@
 
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
 import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.app.ActivityOptions;
+import android.app.WallpaperColors;
+import android.app.WallpaperManager;
+import android.app.WallpaperManager.OnColorsChangedListener;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
@@ -54,7 +58,6 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.touch.ItemClickHandler;
-import com.android.launcher3.uioverrides.WallpaperColorInfo;
 import com.android.launcher3.util.ActivityOptionsWrapper;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
@@ -68,8 +71,9 @@
 /**
  * Extension of BaseActivity allowing support for drag-n-drop
  */
+@SuppressWarnings("NewApi")
 public abstract class BaseDraggingActivity extends BaseActivity
-        implements WallpaperColorInfo.OnChangeListener, DisplayInfoChangeListener {
+        implements OnColorsChangedListener, DisplayInfoChangeListener {
 
     private static final String TAG = "BaseDraggingActivity";
 
@@ -89,13 +93,15 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-
         mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
                 () -> getPackageManager().isSafeMode());
         DisplayController.INSTANCE.get(this).addChangeListener(this);
 
         // Update theme
-        WallpaperColorInfo.INSTANCE.get(this).addOnChangeListener(this);
+        if (Utilities.ATLEAST_P) {
+            getSystemService(WallpaperManager.class)
+                    .addOnColorsChangedListener(this, MAIN_EXECUTOR.getHandler());
+        }
         int themeRes = Themes.getActivityThemeRes(this);
         if (themeRes != mThemeRes) {
             mThemeRes = themeRes;
@@ -114,7 +120,7 @@
     }
 
     @Override
-    public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
+    public void onColorsChanged(WallpaperColors wallpaperColors, int which) {
         updateTheme();
     }
 
@@ -278,7 +284,9 @@
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        WallpaperColorInfo.INSTANCE.get(this).removeOnChangeListener(this);
+        if (Utilities.ATLEAST_P) {
+            getSystemService(WallpaperManager.class).removeOnColorsChangedListener(this);
+        }
         DisplayController.INSTANCE.get(this).removeChangeListener(this);
     }
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 36d3625..f640118 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1197,7 +1197,7 @@
 
         // Setup the drag controller (drop targets have to be added in reverse order in priority)
         mDropTargetBar.setup(mDragController);
-        mAllAppsController.setupViews(mAppsView, mScrimView);
+        mAllAppsController.setupViews(mAppsView);
     }
 
     /**
@@ -1426,6 +1426,7 @@
         return mDropTargetBar;
     }
 
+    @Override
     public ScrimView getScrimView() {
         return mScrimView;
     }
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index 803f8d2..b56c012 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -19,6 +19,8 @@
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.FloatProperty;
 import android.util.IntProperty;
@@ -135,6 +137,22 @@
                         }
                     };
 
+    public static final IntProperty<View> VIEW_BACKGROUND_COLOR =
+            new IntProperty<View>("backgroundColor") {
+                @Override
+                public void setValue(View view, int color) {
+                    view.setBackgroundColor(color);
+                }
+
+                @Override
+                public Integer get(View view) {
+                    if (!(view.getBackground() instanceof ColorDrawable)) {
+                        return Color.TRANSPARENT;
+                    }
+                    return ((ColorDrawable) view.getBackground()).getColor();
+                }
+            };
+
     /**
      * Utility method to create an {@link AnimatorListener} which executes a callback on animation
      * cancel.
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 83ddf64..f26cfe8 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -33,11 +33,12 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mForceHideBackArrow;
 
-    private SysUiScrim mSysUiScrim;
+    private final SysUiScrim mSysUiScrim;
 
     public LauncherRootView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mActivity = StatefulActivity.fromContext(context);
+        mSysUiScrim = new SysUiScrim(this);
     }
 
     private void handleSystemWindowInsets(Rect insets) {
@@ -72,6 +73,7 @@
         // modifying child layout params.
         if (!insets.equals(mInsets)) {
             super.setInsets(insets);
+            mSysUiScrim.onInsetsChanged(insets);
         }
     }
 
@@ -100,15 +102,9 @@
         }
     }
 
-    public void setSysUiScrim(SysUiScrim scrim) {
-        mSysUiScrim = scrim;
-    }
-
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        if (mSysUiScrim != null) {
-            mSysUiScrim.draw(canvas);
-        }
+        mSysUiScrim.draw(canvas);
         super.dispatchDraw(canvas);
     }
 
@@ -117,6 +113,7 @@
         super.onLayout(changed, l, t, r, b);
         SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(l, t, r, b);
         setDisallowBackGesture(mDisallowBackGesture);
+        mSysUiScrim.setSize(r - l, b - t);
     }
 
     @TargetApi(Build.VERSION_CODES.Q)
@@ -136,6 +133,10 @@
                 : Collections.emptyList());
     }
 
+    public SysUiScrim getSysUiScrim() {
+        return mSysUiScrim;
+    }
+
     public interface WindowStateListener {
 
         void onWindowFocusChanged(boolean hasFocus);
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 58df9c8..4c11725 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -30,6 +30,7 @@
 import static com.android.launcher3.testing.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
 
 import android.content.Context;
+import android.graphics.Color;
 import android.view.animation.Interpolator;
 
 import com.android.launcher3.statemanager.BaseState;
@@ -217,8 +218,12 @@
         return 0;
     }
 
-    public float getWorkspaceScrimAlpha(Launcher launcher) {
-        return 0;
+    /**
+     * What color should the workspace scrim be in when at rest in this state.
+     * Return {@link Color#TRANSPARENT} for no scrim.
+     */
+    public int getWorkspaceScrimColor(Launcher launcher) {
+        return Color.TRANSPARENT;
     }
 
     /**
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index f43452c..75d25d7 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -457,10 +457,24 @@
             drawable.setBounds(x, 0, x + previewWidth, previewHeight);
             drawable.draw(c);
         } else {
-            RectF boxRect = drawBoxWithShadow(c, previewWidth, previewHeight);
+            RectF boxRect;
 
             // Draw horizontal and vertical lines to represent individual columns.
             final Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+            if (Utilities.ATLEAST_S) {
+                boxRect = new RectF(/* left= */ 0, /* top= */ 0, /* right= */
+                        previewWidth, /* bottom= */ previewHeight);
+
+                p.setStyle(Paint.Style.FILL);
+                p.setColor(Color.WHITE);
+                float roundedCorner = mContext.getResources().getDimension(
+                        android.R.dimen.system_app_widget_background_radius);
+                c.drawRoundRect(boxRect, roundedCorner, roundedCorner, p);
+            } else {
+                boxRect = drawBoxWithShadow(c, previewWidth, previewHeight);
+            }
+
             p.setStyle(Paint.Style.STROKE);
             p.setStrokeWidth(mContext.getResources()
                     .getDimension(R.dimen.widget_preview_cell_divider_width));
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 0c3a356..05d6e04 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2066,9 +2066,6 @@
         if (mDragOverlappingLayout != null) {
             mDragOverlappingLayout.setIsDragOverlapping(true);
         }
-        // Invalidating the scrim will also force this CellLayout
-        // to be invalidated so that it is highlighted if necessary.
-        mLauncher.getDragLayer().getWorkspaceDragScrim().invalidate();
     }
 
     public CellLayout getCurrentDragOverlappingLayout() {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 41962a4..aa99d52 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -36,6 +36,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCRIM_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
 
@@ -161,9 +162,14 @@
         propertySetter.setFloat(workspaceDragScrim, SCRIM_PROGRESS,
                 state.getWorkspaceBackgroundAlpha(mLauncher), LINEAR);
 
-        SysUiScrim sysUiScrim = mLauncher.getDragLayer().getSysUiScrim();
+        SysUiScrim sysUiScrim = mLauncher.getRootView().getSysUiScrim();
         propertySetter.setFloat(sysUiScrim, SYSUI_PROGRESS,
                 state.hasFlag(FLAG_HAS_SYS_UI_SCRIM) ? 1 : 0, LINEAR);
+
+
+        propertySetter.setViewBackgroundColor(mLauncher.getScrimView(),
+                state.getWorkspaceScrimColor(mLauncher),
+                config.getInterpolator(ANIM_WORKSPACE_SCRIM_FADE, LINEAR));
     }
 
     public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 5c1bffb..c61c0d6 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -43,7 +43,6 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.views.ScrimView;
 
 /**
  * Handles AllApps view transition.
@@ -71,11 +70,10 @@
                     controller.setProgress(progress);
                 }
             };
-    private final Launcher mLauncher;
 
     private AllAppsContainerView mAppsView;
-    private ScrimView mScrimView;
 
+    private final Launcher mLauncher;
     private boolean mIsVerticalLayout;
 
     // Animation in this class is controlled by a single variable {@link mProgress}.
@@ -123,8 +121,6 @@
      */
     public void setProgress(float progress) {
         mProgress = progress;
-        //Note: Take inverted progress so progress=0 maps to a transparent scrim
-        mScrimView.setProgress(1 - progress);
         mAppsView.setTranslationY(mProgress * mShiftRange);
     }
 
@@ -189,12 +185,8 @@
         return AnimationSuccessListener.forRunnable(this::onProgressAnimationEnd);
     }
 
-    /**
-     * Setup views
-     */
-    public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) {
+    public void setupViews(AllAppsContainerView appsView) {
         mAppsView = appsView;
-        mScrimView = scrimView;
         if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && Utilities.ATLEAST_R) {
             mLauncher.getSystemUiController().updateUiState(UI_STATE_ALLAPPS,
                     View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index 9068331..8057475 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.anim;
 
 import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
 import static com.android.launcher3.anim.AnimatorPlaybackController.addAnimationHoldersRecur;
 
 import android.animation.Animator;
@@ -25,6 +26,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
+import android.graphics.drawable.ColorDrawable;
 import android.util.FloatProperty;
 import android.util.IntProperty;
 import android.view.View;
@@ -85,6 +87,17 @@
     }
 
     @Override
+    public void setViewBackgroundColor(View view, int color, TimeInterpolator interpolator) {
+        if (view == null || (view.getBackground() instanceof ColorDrawable
+                && ((ColorDrawable) view.getBackground()).getColor() == color)) {
+            return;
+        }
+        ObjectAnimator anim = ObjectAnimator.ofArgb(view, VIEW_BACKGROUND_COLOR, color);
+        anim.setInterpolator(interpolator);
+        add(anim);
+    }
+
+    @Override
     public <T> void setFloat(T target, FloatProperty<T> property, float value,
             TimeInterpolator interpolator) {
         if (property.get(target) == value) {
diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java
index 2ce620b..729523f 100644
--- a/src/com/android/launcher3/anim/PropertySetter.java
+++ b/src/com/android/launcher3/anim/PropertySetter.java
@@ -41,6 +41,15 @@
     }
 
     /**
+     * Sets the background color of the provided view using the provided interpolator.
+     */
+    default void setViewBackgroundColor(View view, int color, TimeInterpolator interpolator) {
+        if (view != null) {
+            view.setBackgroundColor(color);
+        }
+    }
+
+    /**
      * Updates the float property of the target using the provided interpolator
      */
     default <T> void setFloat(T target, FloatProperty<T> property, float value,
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 274e033..c2f609c 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -41,13 +41,11 @@
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DropTargetBar;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherRootView;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.graphics.Scrim;
-import com.android.launcher3.graphics.SysUiScrim;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.views.BaseDragLayer;
@@ -84,8 +82,6 @@
     // Related to adjacent page hints
     private final ViewGroupFocusHelper mFocusIndicatorHelper;
     private Scrim mWorkspaceDragScrim;
-    private SysUiScrim mSysUiScrim;
-    private LauncherRootView mRootView;
 
     /**
      * Used to create a new DragLayer from XML.
@@ -107,12 +103,6 @@
         mDragController = dragController;
         recreateControllers();
         mWorkspaceDragScrim = new Scrim(this);
-
-        // We delegate drawing of the workspace scrim to LauncherRootView (one level up), so as
-        // to avoid artifacts when translating the entire drag layer in the -1 transition.
-        mRootView = (LauncherRootView) getParent();
-        mSysUiScrim = new SysUiScrim(mRootView);
-        mRootView.setSysUiScrim(mSysUiScrim);
     }
 
     @Override
@@ -526,23 +516,7 @@
         super.dispatchDraw(canvas);
     }
 
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        mSysUiScrim.setSize(w, h);
-    }
-
-    @Override
-    public void setInsets(Rect insets) {
-        super.setInsets(insets);
-        mSysUiScrim.onInsetsChanged(insets, mAllowSysuiScrims);
-    }
-
     public Scrim getWorkspaceDragScrim() {
         return mWorkspaceDragScrim;
     }
-
-    public SysUiScrim getSysUiScrim() {
-        return mSysUiScrim;
-    }
 }
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 767fffe..5ddf84f 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -50,6 +50,8 @@
  */
 public class PreviewBackground extends CellLayout.DelegatedCellDrawing {
 
+    private static final boolean DRAW_SHADOW = false;
+
     private static final int CONSUMPTION_ANIMATION_DURATION = 100;
 
     private final PorterDuffXfermode mShadowPorterDuffXfermode
@@ -163,13 +165,15 @@
         // Stroke width is 1dp
         mStrokeWidth = context.getResources().getDisplayMetrics().density;
 
-        float radius = getScaledRadius();
-        float shadowRadius = radius + mStrokeWidth;
-        int shadowColor = Color.argb(SHADOW_OPACITY, 0, 0, 0);
-        mShadowShader = new RadialGradient(0, 0, 1,
-                new int[] {shadowColor, Color.TRANSPARENT},
-                new float[] {radius / shadowRadius, 1},
-                Shader.TileMode.CLAMP);
+        if (DRAW_SHADOW) {
+            float radius = getScaledRadius();
+            float shadowRadius = radius + mStrokeWidth;
+            int shadowColor = Color.argb(SHADOW_OPACITY, 0, 0, 0);
+            mShadowShader = new RadialGradient(0, 0, 1,
+                    new int[]{shadowColor, Color.TRANSPARENT},
+                    new float[]{radius / shadowRadius, 1},
+                    Shader.TileMode.CLAMP);
+        }
 
         invalidate();
     }
@@ -239,6 +243,9 @@
     }
 
     public void drawShadow(Canvas canvas) {
+        if (!DRAW_SHADOW) {
+            return;
+        }
         if (mShadowShader == null) {
             return;
         }
@@ -277,6 +284,9 @@
     }
 
     public void fadeInBackgroundShadow() {
+        if (!DRAW_SHADOW) {
+            return;
+        }
         if (mShadowAnimator != null) {
             mShadowAnimator.cancel();
         }
diff --git a/src/com/android/launcher3/graphics/Scrim.java b/src/com/android/launcher3/graphics/Scrim.java
index a151cba..a77e058 100644
--- a/src/com/android/launcher3/graphics/Scrim.java
+++ b/src/com/android/launcher3/graphics/Scrim.java
@@ -22,14 +22,12 @@
 import android.util.FloatProperty;
 import android.view.View;
 
-import com.android.launcher3.Launcher;
-import com.android.launcher3.uioverrides.WallpaperColorInfo;
+import com.android.launcher3.R;
 
 /**
  * Contains general scrim properties such as wallpaper-extracted color that subclasses can use.
  */
-public class Scrim implements View.OnAttachStateChangeListener,
-        WallpaperColorInfo.OnChangeListener {
+public class Scrim {
 
     public static final FloatProperty<Scrim> SCRIM_PROGRESS =
             new FloatProperty<Scrim>("scrimProgress") {
@@ -44,8 +42,6 @@
                 }
             };
 
-    protected final Launcher mLauncher;
-    protected final WallpaperColorInfo mWallpaperColorInfo;
     protected final View mRoot;
 
     protected float mScrimProgress;
@@ -54,48 +50,18 @@
 
     public Scrim(View view) {
         mRoot = view;
-        mLauncher = Launcher.getLauncher(view.getContext());
-        mWallpaperColorInfo = WallpaperColorInfo.INSTANCE.get(mLauncher);
-
-        view.addOnAttachStateChangeListener(this);
+        mScrimColor = mRoot.getContext().getColor(R.color.wallpaper_popup_scrim);
     }
 
     public void draw(Canvas canvas) {
-        canvas.drawColor(setColorAlphaBound(mScrimColor, getScrimAlpha()));
-    }
-
-    protected int getScrimAlpha() {
-        return mScrimAlpha;
+        canvas.drawColor(setColorAlphaBound(mScrimColor, mScrimAlpha));
     }
 
     private void setScrimProgress(float progress) {
         if (mScrimProgress != progress) {
             mScrimProgress = progress;
             mScrimAlpha = Math.round(255 * mScrimProgress);
-            invalidate();
+            mRoot.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/SysUiScrim.java b/src/com/android/launcher3/graphics/SysUiScrim.java
index d9c648b..c09dac8 100644
--- a/src/com/android/launcher3/graphics/SysUiScrim.java
+++ b/src/com/android/launcher3/graphics/SysUiScrim.java
@@ -41,18 +41,16 @@
 import android.view.View;
 import android.view.WindowInsets;
 
-import androidx.core.graphics.ColorUtils;
-
+import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
 import com.android.launcher3.ResourceUtils;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.uioverrides.WallpaperColorInfo;
 import com.android.launcher3.util.Themes;
 
 /**
  * View scrim which draws behind hotseat and workspace
  */
-public class SysUiScrim extends Scrim {
+public class SysUiScrim implements View.OnAttachStateChangeListener {
 
     public static final FloatProperty<SysUiScrim> SYSUI_PROGRESS =
             new FloatProperty<SysUiScrim>("sysUiProgress") {
@@ -83,7 +81,6 @@
 
     /**
      * Receiver used to get a signal that the user unlocked their device.
-     * @see KEYGUARD_ANIMATION For proper signal.
      */
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
@@ -99,7 +96,6 @@
         }
     };
 
-    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;
@@ -112,6 +108,8 @@
     private final Bitmap mBottomMask;
     private final int mMaskHeight;
 
+    private final View mRoot;
+    private final BaseDraggingActivity mActivity;
     private final Drawable mTopScrim;
 
     private float mSysUiProgress = 1;
@@ -121,14 +119,15 @@
     private float mSysUiAnimMultiplier = 1;
 
     public SysUiScrim(View view) {
-        super(view);
+        mRoot = view;
+        mActivity = BaseDraggingActivity.fromContext(view.getContext());
         mMaskHeight = ResourceUtils.pxFromDp(ALPHA_MASK_BITMAP_DP,
                 view.getResources().getDisplayMetrics());
         mTopScrim = Themes.getAttrDrawable(view.getContext(), R.attr.workspaceStatusBarScrim);
         mBottomMask = mTopScrim == null ? null : createDitheredAlphaMask();
         mHideSysUiScrim = mTopScrim == null;
 
-        onExtractedColorsChanged(mWallpaperColorInfo);
+        view.addOnAttachStateChangeListener(this);
     }
 
     /**
@@ -147,7 +146,7 @@
 
                 ObjectAnimator oa = createSysuiMultiplierAnim(1);
                 oa.setDuration(600);
-                oa.setStartDelay(mLauncher.getWindow().getTransitionBackgroundFadeDuration());
+                oa.setStartDelay(mActivity.getWindow().getTransitionBackgroundFadeDuration());
                 oa.start();
                 mAnimateScrimOnNextDraw = false;
             }
@@ -173,20 +172,17 @@
     /**
      * Determines whether to draw the top and/or bottom scrim based on new insets.
      */
-    public void onInsetsChanged(Rect insets, boolean allowSysuiScrims) {
-        mDrawTopScrim = allowSysuiScrims
-                && mTopScrim != null
-                && insets.top > 0;
-        mDrawBottomScrim = allowSysuiScrims
-                && mBottomMask != null
-                && !mLauncher.getDeviceProfile().isVerticalBarLayout()
+    public void onInsetsChanged(Rect insets) {
+        mDrawTopScrim = mTopScrim != null && insets.top > 0;
+        mDrawBottomScrim = mBottomMask != null
+                && !mActivity.getDeviceProfile().isVerticalBarLayout()
                 && hasBottomNavButtons();
     }
 
     private boolean hasBottomNavButtons() {
-        if (Utilities.ATLEAST_Q && mLauncher.getRootView() != null
-                && mLauncher.getRootView().getRootWindowInsets() != null) {
-            WindowInsets windowInsets = mLauncher.getRootView().getRootWindowInsets();
+        if (Utilities.ATLEAST_Q && mActivity.getRootView() != null
+                && mActivity.getRootView().getRootWindowInsets() != null) {
+            WindowInsets windowInsets = mActivity.getRootView().getRootWindowInsets();
             return windowInsets.getTappableElementInsets().bottom > 0;
         }
         return true;
@@ -194,8 +190,6 @@
 
     @Override
     public void onViewAttachedToWindow(View view) {
-        super.onViewAttachedToWindow(view);
-
         if (!KEYGUARD_ANIMATION.get() && mTopScrim != null) {
             IntentFilter filter = new IntentFilter(ACTION_SCREEN_OFF);
             filter.addAction(ACTION_USER_PRESENT); // When the device wakes up + keyguard is gone
@@ -205,22 +199,11 @@
 
     @Override
     public void onViewDetachedFromWindow(View view) {
-        super.onViewDetachedFromWindow(view);
         if (!KEYGUARD_ANIMATION.get() && mTopScrim != null) {
             mRoot.getContext().unregisterReceiver(mReceiver);
         }
     }
 
-    @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
-        mBottomMaskPaint.setColor(ColorUtils.compositeColors(DARK_SCRIM_COLOR,
-                wallpaperColorInfo.getMainColor()));
-        reapplySysUiAlpha();
-        super.onExtractedColorsChanged(wallpaperColorInfo);
-    }
-
     /**
      * Set the width and height of the view being scrimmed
      * @param w
@@ -243,7 +226,7 @@
     private void reapplySysUiAlpha() {
         reapplySysUiAlphaNoInvalidate();
         if (!mHideSysUiScrim) {
-            invalidate();
+            mRoot.invalidate();
         }
     }
 
@@ -256,7 +239,7 @@
     }
 
     private Bitmap createDitheredAlphaMask() {
-        DisplayMetrics dm = mLauncher.getResources().getDisplayMetrics();
+        DisplayMetrics dm = mActivity.getResources().getDisplayMetrics();
         int width = ResourceUtils.pxFromDp(ALPHA_MASK_WIDTH_DP, dm);
         int gradientHeight = ResourceUtils.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm);
         Bitmap dst = Bitmap.createBitmap(width, mMaskHeight, Bitmap.Config.ALPHA_8);
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 05fd77d..e388965 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -366,7 +366,7 @@
         return itemBuilder.build();
     }
 
-    LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
+    protected LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
         LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
         itemBuilder.setIsWork(user != Process.myUserHandle());
         return itemBuilder;
diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
index a7cd10d..f73d782 100644
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -24,7 +24,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.uioverrides.WallpaperColorInfo;
+import com.android.launcher3.util.Themes;
 
 /**
  * A PageIndicator that briefly shows a fraction of a line when moving between pages
@@ -123,7 +123,7 @@
         mLauncher = Launcher.getLauncher(context);
         mLineHeight = res.getDimensionPixelSize(R.dimen.workspace_page_indicator_line_height);
 
-        boolean darkText = WallpaperColorInfo.INSTANCE.get(context).supportsDarkText();
+        boolean darkText = Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText);
         mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
         mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE);
     }
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 3736538..c19dfe9 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.popup;
 
+import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
 
@@ -48,12 +49,14 @@
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.RevealOutlineAnimation;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.shortcuts.DeepShortcutView;
+import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BaseDragLayer;
 
@@ -65,7 +68,8 @@
  *
  * @param <T> The activity on with the popup shows
  */
-public abstract class ArrowPopup<T extends BaseDraggingActivity> extends AbstractFloatingView {
+public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
+        extends AbstractFloatingView {
 
     // +1 for system shortcut view
     private static final int MAX_NUM_CHILDREN = MAX_SHORTCUTS + 1;
@@ -139,14 +143,21 @@
         mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius,
                 smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius});
 
-        int primaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
-        int secondaryColor = Themes.getAttrColor(context, R.attr.popupColorSecondary);
-        ArgbEvaluator argb = new ArgbEvaluator();
-        mColors = new int[MAX_NUM_CHILDREN];
-        // Interpolate between the two colors, exclusive.
-        float step = 1f / (MAX_NUM_CHILDREN + 1);
-        for (int i = 0; i < mColors.length; ++i) {
-            mColors[i] = (int) argb.evaluate((i + 1) * step, primaryColor, secondaryColor);
+        boolean isAboveAnotherSurface = getTopOpenViewWithType(mLauncher, TYPE_FOLDER) != null
+                || mLauncher.getStateManager().getState() == LauncherState.ALL_APPS;
+        if (isAboveAnotherSurface) {
+            mColors = new int[] { Themes.getAttrColor(context, R.attr.popupColorNeutral) };
+        } else {
+            int primaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
+            int secondaryColor = Themes.getAttrColor(context, R.attr.popupColorSecondary);
+            ArgbEvaluator argb = new ArgbEvaluator();
+            mColors = new int[MAX_NUM_CHILDREN];
+            // Interpolate between the two colors, exclusive.
+            float step = 1f / (MAX_NUM_CHILDREN + 1);
+            for (int i = 0; i < mColors.length; ++i) {
+                mColors[i] =
+                        (int) argb.evaluate((i + 1) * step, primaryColor, secondaryColor);
+            }
         }
     }
 
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index c282ae8..1659e6d 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -46,6 +46,7 @@
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate;
@@ -60,10 +61,10 @@
 import com.android.launcher3.notification.NotificationInfo;
 import com.android.launcher3.notification.NotificationItemView;
 import com.android.launcher3.notification.NotificationKeyData;
-import com.android.launcher3.notification.NotificationMainView;
 import com.android.launcher3.popup.PopupDataProvider.PopupDataChangeListener;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.ShortcutUtil;
@@ -81,8 +82,8 @@
  *
  * @param <T> The activity on with the popup shows
  */
-public class PopupContainerWithArrow<T extends BaseDraggingActivity> extends ArrowPopup<T>
-        implements DragSource, DragController.DragListener {
+public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
+        extends ArrowPopup<T> implements DragSource, DragController.DragListener {
 
     private final List<DeepShortcutView> mShortcuts = new ArrayList<>();
     private final PointF mInterceptTouchDown = new PointF();
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index 22c9d5b..8b52016 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -19,8 +19,12 @@
 
 import android.content.Context;
 
+import androidx.core.graphics.ColorUtils;
+
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
 
 /**
  * Scale down workspace/hotseat to hint at going to either overview (on pause) or first home screen.
@@ -49,8 +53,9 @@
     }
 
     @Override
-    public float getWorkspaceScrimAlpha(Launcher launcher) {
-        return 0.4f;
+    public int getWorkspaceScrimColor(Launcher launcher) {
+        return ColorUtils.setAlphaComponent(
+                Themes.getAttrColor(launcher, R.attr.overviewScrimColor), 100);
     }
 
     @Override
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 39bcdc5..8db1dbe 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -89,7 +89,7 @@
 
     @Override
     public float getWorkspaceBackgroundAlpha(Launcher launcher) {
-        return 0.3f;
+        return 0.2f;
     }
 
     @Override
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index a437293..d092f11 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -352,7 +352,7 @@
             // case the user started interacting with it before the animation finished.
             mLauncher.getStateManager().goToState(targetState, false /* animated */);
         }
-        mLauncher.getDragLayer().getSysUiScrim().createSysuiMultiplierAnim(
+        mLauncher.getRootView().getSysUiScrim().createSysuiMultiplierAnim(
                 1f).setDuration(0).start();
     }
 
diff --git a/src/com/android/launcher3/util/RunnableList.java b/src/com/android/launcher3/util/RunnableList.java
index 55add14..644537b 100644
--- a/src/com/android/launcher3/util/RunnableList.java
+++ b/src/com/android/launcher3/util/RunnableList.java
@@ -29,6 +29,9 @@
      * Ads a runnable to this list
      */
     public void add(Runnable runnable) {
+        if (runnable == null) {
+            return;
+        }
         if (mDestroyed) {
             runnable.run();
             return;
diff --git a/src/com/android/launcher3/util/SystemUiController.java b/src/com/android/launcher3/util/SystemUiController.java
index 50166c3..630df7e 100644
--- a/src/com/android/launcher3/util/SystemUiController.java
+++ b/src/com/android/launcher3/util/SystemUiController.java
@@ -30,7 +30,7 @@
     public static final int UI_STATE_BASE_WINDOW = 0;
     public static final int UI_STATE_SCRIM_VIEW = 1;
     public static final int UI_STATE_WIDGET_BOTTOM_SHEET = 2;
-    public static final int UI_STATE_OVERVIEW = 3;
+    public static final int UI_STATE_FULLSCREEN_TASK = 3;
     public static final int UI_STATE_ALLAPPS = 4;
 
     public static final int FLAG_LIGHT_NAV = 1 << 0;
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index e8a0635..11b856e 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -16,6 +16,10 @@
 
 package com.android.launcher3.util;
 
+import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_TEXT;
+import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_THEME;
+
+import android.app.WallpaperManager;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
@@ -29,35 +33,40 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.icons.GraphicsUtils;
-import com.android.launcher3.uioverrides.WallpaperColorInfo;
 
 /**
  * Various utility methods associated with theming.
  */
+@SuppressWarnings("NewApi")
 public class Themes {
 
     public static int getActivityThemeRes(Context context) {
-        WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.INSTANCE.get(context);
-        boolean darkTheme;
-        if (Utilities.ATLEAST_Q) {
-            Configuration configuration = context.getResources().getConfiguration();
-            int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
-            darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES;
-        } else {
-            darkTheme = wallpaperColorInfo.isDark();
-        }
+        int colorHints = Utilities.ATLEAST_P ? context.getSystemService(WallpaperManager.class)
+                .getWallpaperColors(WallpaperManager.FLAG_SYSTEM).getColorHints()
+                : 0;
+        return getActivityThemeRes(context, colorHints);
+    }
+
+    public static int getActivityThemeRes(Context context, int wallpaperColorHints) {
+        Configuration configuration = context.getResources().getConfiguration();
+        int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        boolean darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES;
+
+        boolean supportsDarkText = Utilities.ATLEAST_S
+                && (wallpaperColorHints & HINT_SUPPORTS_DARK_TEXT) != 0;
+        boolean isMainColorDark = Utilities.ATLEAST_S
+                && (wallpaperColorHints & HINT_SUPPORTS_DARK_THEME) != 0;
 
         if (darkTheme) {
-            return wallpaperColorInfo.supportsDarkText() ?
-                    R.style.AppTheme_Dark_DarkText : wallpaperColorInfo.isMainColorDark() ?
-                            R.style.AppTheme_Dark_DarkMainColor : R.style.AppTheme_Dark;
+            return supportsDarkText ? R.style.AppTheme_Dark_DarkText
+                    : isMainColorDark ? R.style.AppTheme_Dark_DarkMainColor : R.style.AppTheme_Dark;
         } else {
-            return wallpaperColorInfo.supportsDarkText() ?
-                    R.style.AppTheme_DarkText : wallpaperColorInfo.isMainColorDark() ?
-                            R.style.AppTheme_DarkMainColor : R.style.AppTheme;
+            return supportsDarkText ? R.style.AppTheme_DarkText
+                    : isMainColorDark ? R.style.AppTheme_DarkMainColor : R.style.AppTheme;
         }
     }
 
+
     public static String getDefaultBodyFont(Context context) {
         TypedArray ta = context.obtainStyledAttributes(android.R.style.TextAppearance_DeviceDefault,
                 new int[]{android.R.attr.fontFamily});
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 1939d15..01c0b56 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -23,11 +23,8 @@
 import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 
 import android.annotation.TargetApi;
-import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -42,15 +39,11 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 
-import androidx.annotation.Nullable;
-
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.InsettableFrameLayout;
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
-import com.android.launcher3.util.SimpleBroadcastReceiver;
 import com.android.launcher3.util.TouchController;
 
 import java.io.PrintWriter;
@@ -117,9 +110,6 @@
     protected final T mActivity;
     private final MultiValueAlpha mMultiValueAlpha;
     private final WallpaperManager mWallpaperManager;
-    private final SimpleBroadcastReceiver mWallpaperChangeReceiver =
-            new SimpleBroadcastReceiver(this::onWallpaperChanged);
-    private final String[] mWallpapersWithoutSysuiScrims;
 
     // All the touch controllers for the view
     protected TouchController[] mControllers;
@@ -130,15 +120,11 @@
 
     private TouchCompleteListener mTouchCompleteListener;
 
-    protected boolean mAllowSysuiScrims = true;
-
     public BaseDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
         super(context, attrs);
         mActivity = (T) ActivityContext.lookupContext(context);
         mMultiValueAlpha = new MultiValueAlpha(this, alphaChannelCount);
         mWallpaperManager = context.getSystemService(WallpaperManager.class);
-        mWallpapersWithoutSysuiScrims = getResources().getStringArray(
-                R.array.live_wallpapers_remove_sysui_scrims);
     }
 
     /**
@@ -562,46 +548,4 @@
         }
         return super.dispatchApplyWindowInsets(insets);
     }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mWallpaperChangeReceiver.register(mActivity, Intent.ACTION_WALLPAPER_CHANGED);
-        onWallpaperChanged(null);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mActivity.unregisterReceiver(mWallpaperChangeReceiver);
-    }
-
-    private void onWallpaperChanged(Intent unusedBroadcastIntent) {
-        WallpaperInfo newWallpaperInfo = mWallpaperManager.getWallpaperInfo();
-        boolean oldAllowSysuiScrims = mAllowSysuiScrims;
-        mAllowSysuiScrims = computeAllowSysuiScrims(newWallpaperInfo);
-        if (mAllowSysuiScrims != oldAllowSysuiScrims) {
-            // Reapply insets so scrim can be removed or re-added if necessary.
-            setInsets(mInsets);
-        }
-    }
-
-    /**
-     * Determines whether we can scrim the status bar and nav bar for the given wallpaper by
-     * checking against a list of live wallpapers that we don't show the scrims on.
-     */
-    private boolean computeAllowSysuiScrims(@Nullable WallpaperInfo newWallpaperInfo) {
-        if (newWallpaperInfo == null) {
-            // Static wallpapers need scrim unless determined otherwise by wallpaperColors.
-            return true;
-        }
-        ComponentName newWallpaper = newWallpaperInfo.getComponent();
-        for (String wallpaperWithoutScrim : mWallpapersWithoutSysuiScrims) {
-            if (newWallpaper.equals(ComponentName.unflattenFromString(wallpaperWithoutScrim))) {
-                // New wallpaper does not need a scrim.
-                return false;
-            }
-        }
-        return true;
-    }
 }
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 9b809ae..5387a3e 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -15,23 +15,19 @@
  */
 package com.android.launcher3.views;
 
-import static com.android.launcher3.anim.Interpolators.ACCEL;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_SCRIM_VIEW;
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.animation.Interpolator;
 
 import androidx.core.graphics.ColorUtils;
 
+import com.android.launcher3.BaseActivity;
 import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.util.SystemUiController;
-import com.android.launcher3.util.Themes;
 
 /**
  * Simple scrim which draws a flat color
@@ -39,47 +35,31 @@
 public class ScrimView extends View implements Insettable {
     private static final float STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD = 0.9f;
 
-
-    private static final float TINT_DECAY_MULTIPLIER = .5f;
-
-    //min progress for scrim to become visible
-    private static final float SCRIM_VISIBLE_THRESHOLD = .1f;
-    //max progress where scrim alpha animates.
-    private static final float SCRIM_SOLID_THRESHOLD = .5f;
-    private final Interpolator mScrimInterpolator = Interpolators.clampToProgress(ACCEL,
-            SCRIM_VISIBLE_THRESHOLD,
-            SCRIM_SOLID_THRESHOLD);
-
-    private final boolean mIsScrimDark;
     private SystemUiController mSystemUiController;
 
-    private float mProgress;
-
     public ScrimView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mIsScrimDark = ColorUtils.calculateLuminance(
-                Themes.getAttrColor(context, R.attr.allAppsScrimColor)) < 0.5f;
         setFocusable(false);
     }
 
     @Override
-    public void setInsets(Rect insets) {
-    }
+    public void setInsets(Rect insets) { }
 
     @Override
     public boolean hasOverlappingRendering() {
         return false;
     }
 
-    /**
-     * Set progress of scrim animation.
-     * Note: progress should range from 0 for transparent to 1 for solid
-     */
-    public void setProgress(float progress) {
-        if (mProgress != progress) {
-            mProgress = progress;
-            setAlpha(mScrimInterpolator.getInterpolation(progress));
-        }
+    @Override
+    protected boolean onSetAlpha(int alpha) {
+        updateSysUiColors();
+        return super.onSetAlpha(alpha);
+    }
+
+    @Override
+    public void setBackgroundColor(int color) {
+        updateSysUiColors();
+        super.setBackgroundColor(color);
     }
 
     @Override
@@ -94,7 +74,7 @@
         boolean forceChange =
                 getVisibility() == VISIBLE && getAlpha() > STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD;
         if (forceChange) {
-            getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark);
+            getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !isScrimDark());
         } else {
             getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, 0);
         }
@@ -102,8 +82,18 @@
 
     private SystemUiController getSystemUiController() {
         if (mSystemUiController == null) {
-            mSystemUiController = Launcher.getLauncher(getContext()).getSystemUiController();
+            mSystemUiController = BaseActivity.fromContext(getContext()).getSystemUiController();
         }
         return mSystemUiController;
     }
+
+    private boolean isScrimDark() {
+        if (!(getBackground() instanceof ColorDrawable)) {
+            throw new IllegalStateException(
+                    "ScrimView must have a ColorDrawable background, this one has: "
+                            + getBackground());
+        }
+        return ColorUtils.calculateLuminance(
+                ((ColorDrawable) getBackground()).getColor()) < 0.5f;
+    }
 }
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 415f48d..a7ecb07 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -35,7 +35,6 @@
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.touch.ItemLongClickListener;
-import com.android.launcher3.uioverrides.WallpaperColorInfo;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.AbstractSlideInView;
@@ -56,9 +55,8 @@
     }
 
     protected int getScrimColor(Context context) {
-        WallpaperColorInfo colors = WallpaperColorInfo.INSTANCE.get(context);
         int alpha = context.getResources().getInteger(R.integer.extracted_color_gradient_alpha);
-        return setColorAlphaBound(colors.getSecondaryColor(), alpha);
+        return setColorAlphaBound(context.getColor(R.color.wallpaper_popup_scrim), alpha);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index f77c740..620604a 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -72,6 +72,8 @@
 
     // Maintains a list of widget ids which are supposed to be auto advanced.
     private static final SparseBooleanArray sAutoAdvanceWidgetIds = new SparseBooleanArray();
+    // Maximum duration for which updates can be deferred.
+    private static final long UPDATE_LOCK_TIMEOUT_MILLIS = 1000;
 
     protected final LayoutInflater mInflater;
 
@@ -110,6 +112,9 @@
             }
         }
     };
+    private final Object mUpdateLock = new Object();
+    private long mDeferUpdatesUntilMillis = 0;
+    private RemoteViews mMostRecentRemoteViews;
 
     public LauncherAppWidgetHostView(Context context) {
         super(context);
@@ -165,6 +170,11 @@
 
     @Override
     public void updateAppWidget(RemoteViews remoteViews) {
+        synchronized (mUpdateLock) {
+            mMostRecentRemoteViews = remoteViews;
+            if (SystemClock.uptimeMillis() < mDeferUpdatesUntilMillis) return;
+        }
+
         super.updateAppWidget(remoteViews);
 
         // The provider info or the views might have changed.
@@ -198,6 +208,34 @@
         return false;
     }
 
+    /**
+     * Begin deferring the application of any {@link RemoteViews} updates made through
+     * {@link #updateAppWidget(RemoteViews)} until {@link #endDeferringUpdates()} has been called or
+     * the next {@link #updateAppWidget(RemoteViews)} call after {@link #UPDATE_LOCK_TIMEOUT_MILLIS}
+     * have elapsed.
+     */
+    public void beginDeferringUpdates() {
+        synchronized (mUpdateLock) {
+            mDeferUpdatesUntilMillis = SystemClock.uptimeMillis() + UPDATE_LOCK_TIMEOUT_MILLIS;
+        }
+    }
+
+    /**
+     * Stop deferring the application of {@link RemoteViews} updates made through
+     * {@link #updateAppWidget(RemoteViews)} and apply the most recently received update.
+     */
+    public void endDeferringUpdates() {
+        RemoteViews remoteViews;
+        synchronized (mUpdateLock) {
+            mDeferUpdatesUntilMillis = 0;
+            remoteViews = mMostRecentRemoteViews;
+            mMostRecentRemoteViews = null;
+        }
+        if (remoteViews != null) {
+            updateAppWidget(remoteViews);
+        }
+    }
+
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             DragLayer dragLayer = mLauncher.getDragLayer();
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 155a285..f18b63e 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -20,6 +20,7 @@
 
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.IntProperty;
@@ -71,6 +72,7 @@
     private Rect mInsets;
     private final int mMaxTableHeight;
     private int mMaxHorizontalSpan = 4;
+    private Configuration mCurrentConfiguration;
 
     public WidgetsBottomSheet(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -85,6 +87,7 @@
         // Set the max table height to 2 / 3 of the grid height so that the bottom picker won't
         // take over the entire view vertically.
         mMaxTableHeight = deviceProfile.inv.numRows * 2 / 3  * deviceProfile.cellHeightPx;
+        mCurrentConfiguration = new Configuration(getResources().getConfiguration());
     }
 
     @Override
@@ -212,6 +215,14 @@
     }
 
     @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        if (mCurrentConfiguration.orientation != newConfig.orientation) {
+            mInsets.setEmpty();
+        }
+        mCurrentConfiguration.updateFrom(newConfig);
+    }
+
+    @Override
     protected Pair<View, String> getAccessibilityTarget() {
         return Pair.create(findViewById(R.id.title),  getContext().getString(
                 mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed));
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 240958b..8f5d4dc 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -221,7 +221,7 @@
         WidgetsRecyclerView currentRecyclerView =
                 mAdapters.get(currentActivePage).mWidgetsRecyclerView;
 
-        updateNoWidgetsView(currentAdapterHolder);
+        updateRecyclerViewVisibility(currentAdapterHolder);
         attachScrollbarToRecyclerView(currentRecyclerView);
         resetExpandedHeaders();
     }
@@ -232,22 +232,17 @@
         reset();
     }
 
-    private void updateNoWidgetsView(AdapterHolder adapterHolder) {
+    private void updateRecyclerViewVisibility(AdapterHolder adapterHolder) {
         boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.getItemCount() > 0;
         adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
 
-        // Always resets the text in case this is updated by search.
-        mNoWidgetsView.setText(R.string.no_widgets_available);
+        mNoWidgetsView.setText(
+                adapterHolder.mAdapterType == AdapterHolder.SEARCH
+                        ? R.string.no_search_results
+                        : R.string.no_widgets_available);
         mNoWidgetsView.setVisibility(isWidgetAvailable ? GONE : VISIBLE);
     }
 
-    private void updateNoSearchResultsView(boolean isVisible) {
-        mNoWidgetsView.setVisibility(isVisible ? VISIBLE : GONE);
-        if (isVisible) {
-            mNoWidgetsView.setText(R.string.no_search_results);
-        }
-    }
-
     private void reset() {
         mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.scrollToTop();
         if (mHasWorkProfile) {
@@ -394,16 +389,22 @@
 
     @Override
     public void onWidgetsBound() {
+        if (mIsInSearchMode) {
+            return;
+        }
         List<WidgetsListBaseEntry> allWidgets = mLauncher.getPopupDataProvider().getAllWidgets();
 
         AdapterHolder primaryUserAdapterHolder = mAdapters.get(AdapterHolder.PRIMARY);
         primaryUserAdapterHolder.mWidgetsListAdapter.setWidgets(allWidgets);
-        updateNoWidgetsView(primaryUserAdapterHolder);
 
         if (mHasWorkProfile) {
+            mViewPager.setVisibility(VISIBLE);
+            mTabsView.setVisibility(VISIBLE);
             AdapterHolder workUserAdapterHolder = mAdapters.get(AdapterHolder.WORK);
             workUserAdapterHolder.mWidgetsListAdapter.setWidgets(allWidgets);
             onActivePageChanged(mViewPager.getCurrentPage());
+        } else {
+            updateRecyclerViewVisibility(primaryUserAdapterHolder);
         }
     }
 
@@ -431,8 +432,7 @@
     @Override
     public void onSearchResults(List<WidgetsListBaseEntry> entries) {
         mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setWidgetsOnSearch(entries);
-        updateNoSearchResultsView(
-                mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.getItemCount() == 0);
+        updateRecyclerViewVisibility(mAdapters.get(AdapterHolder.SEARCH));
         mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
     }
 
@@ -440,19 +440,22 @@
         mIsInSearchMode = isInSearchMode;
         if (isInSearchMode) {
             mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable.setVisibility(GONE);
+            if (mHasWorkProfile) {
+                mViewPager.setVisibility(GONE);
+                mTabsView.setVisibility(GONE);
+            } else {
+                mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.setVisibility(GONE);
+            }
+            updateRecyclerViewVisibility(mAdapters.get(AdapterHolder.SEARCH));
+            // Hide no search results view to prevent it from flashing on enter search.
+            mNoWidgetsView.setVisibility(GONE);
         } else {
+            mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
+            // Visibility of recommended widgets, recycler views and headers are handled in methods
+            // below.
             onRecommendedWidgetsBound();
+            onWidgetsBound();
         }
-        if (mHasWorkProfile) {
-            mViewPager.setVisibility(isInSearchMode ? GONE : VISIBLE);
-            mTabsView.setVisibility(isInSearchMode ? GONE : VISIBLE);
-        } else {
-            mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView
-                    .setVisibility(isInSearchMode ? GONE : VISIBLE);
-        }
-        mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView
-                .setVisibility(mIsInSearchMode ? VISIBLE : GONE);
-        mNoWidgetsView.setVisibility(GONE);
     }
 
     private void resetExpandedHeaders() {
@@ -462,11 +465,14 @@
 
     @Override
     public void onRecommendedWidgetsBound() {
+        if (mIsInSearchMode) {
+            return;
+        }
         List<WidgetItem> recommendedWidgets =
                 mLauncher.getPopupDataProvider().getRecommendedWidgets();
         WidgetsRecommendationTableLayout table =
                 mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable;
-        if (!mIsInSearchMode && recommendedWidgets.size() > 0) {
+        if (recommendedWidgets.size() > 0) {
             // TODO(b/185508758): Revert the following log after debugging.
             if (getHeaderViewHeight() == 0) {
                 Log.d(TAG, "Header view height is 0 when inflating recommended widgets");
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index 8794a4a..ccf3187 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -19,7 +19,10 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.util.AttributeSet;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.CheckBox;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -94,6 +97,32 @@
         mTitle = findViewById(R.id.app_title);
         mSubtitle = findViewById(R.id.app_subtitle);
         mExpandToggle = findViewById(R.id.toggle);
+        findViewById(R.id.app_container).setAccessibilityDelegate(new AccessibilityDelegate() {
+
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                if (mIsExpanded) {
+                    info.removeAction(AccessibilityNodeInfo.ACTION_EXPAND);
+                    info.addAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
+                } else {
+                    info.removeAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
+                    info.addAction(AccessibilityNodeInfo.ACTION_EXPAND);
+                }
+                super.onInitializeAccessibilityNodeInfo(host, info);
+            }
+
+            @Override
+            public boolean performAccessibilityAction(View host, int action, Bundle args) {
+                switch (action) {
+                    case AccessibilityNodeInfo.ACTION_EXPAND:
+                    case AccessibilityNodeInfo.ACTION_COLLAPSE:
+                        callOnClick();
+                        return true;
+                    default:
+                        return super.performAccessibilityAction(host, action, args);
+                }
+            }
+        });
     }
 
     /**
@@ -106,7 +135,9 @@
         // Use the entire touch area of this view to expand / collapse an app widgets section.
         setOnClickListener(view -> {
             setExpanded(!mIsExpanded);
-            onExpandChangeListener.onExpansionChange(mIsExpanded);
+            if (onExpandChangeListener != null) {
+                onExpandChangeListener.onExpansionChange(mIsExpanded);
+            }
         });
     }
 
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index 18f1be3..2d3f1a0 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -42,6 +42,7 @@
     private static final String TAG = "WidgetsRecommendationTableLayout";
     private static final float DOWN_SCALE_RATIO = 0.9f;
     private static final float MAX_DOWN_SCALE_RATIO = 0.5f;
+    private final float mWidgetsRecommendationTableVerticalPadding;
     private final float mWidgetCellTextViewsHeight;
     private final float mWidgetPreviewPadding;
 
@@ -57,6 +58,8 @@
     public WidgetsRecommendationTableLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
         // There are 1 row for title, 1 row for dimension and 2 rows for description.
+        mWidgetsRecommendationTableVerticalPadding = 2 * getResources()
+                .getDimensionPixelSize(R.dimen.widget_cell_vertical_padding);
         mWidgetCellTextViewsHeight = 4 * getResources().getDimension(R.dimen.widget_cell_font_size);
         mWidgetPreviewPadding = 2 * getResources()
                 .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
@@ -143,7 +146,7 @@
             return new RecommendationTableData(List.of(), previewScale);
         }
         // A naive estimation of the widgets recommendation table height without inflation.
-        float totalHeight = 0;
+        float totalHeight = mWidgetsRecommendationTableVerticalPadding;
         DeviceProfile deviceProfile = Launcher.getLauncher(getContext()).getDeviceProfile();
         for (int i = 0; i < recommendedWidgetsInTable.size(); i++) {
             List<WidgetItem> widgetItems = recommendedWidgetsInTable.get(i);
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java b/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
deleted file mode 100644
index b3aa365..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides;
-
-import static android.app.WallpaperManager.FLAG_SYSTEM;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.util.Pair;
-
-import com.android.launcher3.uioverrides.dynamicui.ColorExtractionAlgorithm;
-import com.android.launcher3.uioverrides.dynamicui.WallpaperColorsCompat;
-import com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompat;
-import com.android.launcher3.util.MainThreadInitializedObject;
-
-import java.util.ArrayList;
-
-public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChangedListenerCompat {
-
-    private static final int MAIN_COLOR_LIGHT = 0xffdadce0;
-    private static final int MAIN_COLOR_DARK = 0xff202124;
-    private static final int MAIN_COLOR_REGULAR = 0xff000000;
-
-    private static final int FALLBACK_COLOR = Color.WHITE;
-
-    public static final MainThreadInitializedObject<WallpaperColorInfo> INSTANCE =
-            new MainThreadInitializedObject<>(WallpaperColorInfo::new);
-
-    private final ArrayList<OnChangeListener> mListeners = new ArrayList<>();
-    private final WallpaperManagerCompat mWallpaperManager;
-    private final ColorExtractionAlgorithm mExtractionType;
-    private int mMainColor;
-    private int mSecondaryColor;
-    private boolean mIsDark;
-    private boolean mSupportsDarkText;
-
-    private OnChangeListener[] mTempListeners;
-
-    private WallpaperColorInfo(Context context) {
-        mWallpaperManager = WallpaperManagerCompat.getInstance(context);
-        mWallpaperManager.addOnColorsChangedListener(this);
-        mExtractionType = new ColorExtractionAlgorithm();
-        update(mWallpaperManager.getWallpaperColors(FLAG_SYSTEM));
-    }
-
-    public int getMainColor() {
-        return mMainColor;
-    }
-
-    public int getSecondaryColor() {
-        return mSecondaryColor;
-    }
-
-    public boolean isDark() {
-        return mIsDark;
-    }
-
-    public boolean supportsDarkText() {
-        return mSupportsDarkText;
-    }
-
-    public boolean isMainColorDark() {
-        return mMainColor == MAIN_COLOR_DARK;
-    }
-
-    @Override
-    public void onColorsChanged(WallpaperColorsCompat colors, int which) {
-        if ((which & FLAG_SYSTEM) != 0) {
-            update(colors);
-            notifyChange();
-        }
-    }
-
-    private void update(WallpaperColorsCompat wallpaperColors) {
-        Pair<Integer, Integer> colors = mExtractionType.extractInto(wallpaperColors);
-        if (colors != null) {
-            mMainColor = colors.first;
-            mSecondaryColor = colors.second;
-        } else {
-            mMainColor = FALLBACK_COLOR;
-            mSecondaryColor = FALLBACK_COLOR;
-        }
-        mSupportsDarkText = wallpaperColors != null
-                ? (wallpaperColors.getColorHints()
-                & WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT) > 0 : false;
-        mIsDark = wallpaperColors != null
-                ? (wallpaperColors.getColorHints()
-                & WallpaperColorsCompat.HINT_SUPPORTS_DARK_THEME) > 0 : false;
-    }
-
-    public void addOnChangeListener(OnChangeListener listener) {
-        mListeners.add(listener);
-    }
-
-    public void removeOnChangeListener(OnChangeListener listener) {
-        mListeners.remove(listener);
-    }
-
-    private void notifyChange() {
-        OnChangeListener[] copy =
-                mTempListeners != null && mTempListeners.length == mListeners.size() ?
-                        mTempListeners : new OnChangeListener[mListeners.size()];
-
-        // Create a new array to avoid concurrent modification when the activity destroys itself.
-        mTempListeners = mListeners.toArray(copy);
-        for (OnChangeListener listener : mTempListeners) {
-            listener.onExtractedColorsChanged(this);
-        }
-    }
-
-    public interface OnChangeListener {
-        void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo);
-    }
-}
\ No newline at end of file
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
deleted file mode 100644
index 780a0f0..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
+++ /dev/null
@@ -1,795 +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.uioverrides.dynamicui;
-
-import android.graphics.Color;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Range;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.graphics.ColorUtils;
-
-import com.android.launcher3.Utilities;
-
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Implementation of tonal color extraction
- **/
-public class ColorExtractionAlgorithm {
-
-    private static final String TAG = "Tonal";
-
-    // Used for tonal palette fitting
-    private static final float FIT_WEIGHT_H = 1.0f;
-    private static final float FIT_WEIGHT_S = 1.0f;
-    private static final float FIT_WEIGHT_L = 10.0f;
-
-    public static final int MAIN_COLOR_LIGHT = 0xffb0b0b0;
-    public static final int SECONDARY_COLOR_LIGHT = 0xff9e9e9e;
-    public static final int MAIN_COLOR_DARK = 0xff212121;
-    public static final int SECONDARY_COLOR_DARK = 0xff000000;
-
-    // Temporary variable to avoid allocations
-    private float[] mTmpHSL = new float[3];
-
-    public Pair<Integer, Integer> extractInto(WallpaperColorsCompat inWallpaperColors) {
-        if (inWallpaperColors == null) {
-            return applyFallback(inWallpaperColors);
-        }
-
-        final List<Integer> mainColors = getMainColors(inWallpaperColors);
-        final int mainColorsSize = mainColors.size();
-        final boolean supportsDarkText = (inWallpaperColors.getColorHints() &
-                WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT) != 0;
-
-        if (mainColorsSize == 0) {
-            return applyFallback(inWallpaperColors);
-        }
-        // Tonal is not really a sort, it takes a color from the extracted
-        // palette and finds a best fit amongst a collection of pre-defined
-        // palettes. The best fit is tweaked to be closer to the source color
-        // and replaces the original palette
-
-        // Get the most preeminent, non-disallowed color.
-        Integer bestColor = 0;
-        final float[] hsl = new float[3];
-        for (int i = 0; i < mainColorsSize; i++) {
-            final int colorValue = mainColors.get(i);
-            ColorUtils.RGBToHSL(Color.red(colorValue), Color.green(colorValue),
-                    Color.blue(colorValue), hsl);
-
-            // Stop when we find a color that meets our criteria
-            if (!isDisallowed(hsl)) {
-                bestColor = colorValue;
-                break;
-            }
-        }
-
-        // Fail if not found
-        if (bestColor == null) {
-            return applyFallback(inWallpaperColors);
-        }
-
-        int colorValue = bestColor;
-        ColorUtils.RGBToHSL(Color.red(colorValue), Color.green(colorValue), Color.blue(colorValue),
-                hsl);
-
-        // The Android HSL definition requires the hue to go from 0 to 360 but
-        // the Material Tonal Palette defines hues from 0 to 1.
-        hsl[0] /= 360f;
-
-        // Find the palette that contains the closest color
-        TonalPalette palette = findTonalPalette(hsl[0], hsl[1]);
-        if (palette == null) {
-            Log.w(TAG, "Could not find a tonal palette!");
-            return applyFallback(inWallpaperColors);
-        }
-
-        // Figure out what's the main color index in the optimal palette
-        int fitIndex = bestFit(palette, hsl[0], hsl[1], hsl[2]);
-        if (fitIndex == -1) {
-            Log.w(TAG, "Could not find best fit!");
-            return applyFallback(inWallpaperColors);
-        }
-
-        // Generate the 10 colors palette by offsetting each one of them
-        float[] h = fit(palette.h, hsl[0], fitIndex,
-                Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
-        float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f);
-        float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f);
-
-        int primaryIndex = fitIndex;
-        int mainColor = getColorInt(primaryIndex, h, s, l);
-
-        // We might want use the fallback in case the extracted color is brighter than our
-        // light fallback or darker than our dark fallback.
-        ColorUtils.colorToHSL(mainColor, mTmpHSL);
-        final float mainLuminosity = mTmpHSL[2];
-        ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
-        final float lightLuminosity = mTmpHSL[2];
-        if (mainLuminosity > lightLuminosity) {
-            return applyFallback(inWallpaperColors);
-        }
-        ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
-        final float darkLuminosity = mTmpHSL[2];
-        if (mainLuminosity < darkLuminosity) {
-            return applyFallback(inWallpaperColors);
-        }
-
-        // Dark colors:
-        // Stops at 4th color, only lighter if dark text is supported
-        if (supportsDarkText) {
-            primaryIndex = h.length - 1;
-        } else if (fitIndex < 2) {
-            primaryIndex = 0;
-        } else {
-            primaryIndex = Math.min(fitIndex, 3);
-        }
-        int secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
-        int secondaryColor = getColorInt(secondaryIndex, h, s, l);
-
-        return new Pair<>(mainColor, secondaryColor);
-    }
-
-    public static Pair<Integer, Integer> applyFallback(WallpaperColorsCompat inWallpaperColors) {
-        boolean light = inWallpaperColors != null
-                && (inWallpaperColors.getColorHints()
-                    & WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT)!= 0;
-        int innerColor = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK;
-        int outerColor = light ? SECONDARY_COLOR_LIGHT : SECONDARY_COLOR_DARK;
-        return new Pair<>(innerColor, outerColor);
-    }
-
-    private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) {
-        mTmpHSL[0] = fract(h[fitIndex]) * 360.0f;
-        mTmpHSL[1] = s[fitIndex];
-        mTmpHSL[2] = l[fitIndex];
-        return ColorUtils.HSLToColor(mTmpHSL);
-    }
-
-    /**
-     * Checks if a given color exists in the disallowed_colors list.
-     * @param hsl float array with 3 components (H 0..360, S 0..1 and L 0..1)
-     * @return true if color should be avoided
-     */
-    private boolean isDisallowed(float[] hsl) {
-        for (ColorRange badRange: DISALLOWED_COLORS) {
-            if (badRange.containsColor(hsl[0], hsl[1], hsl[2])) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Offsets all colors by a delta, clamping values that go beyond what's
-     * supported on the color space.
-     * @param data what you want to fit
-     * @param v how big should be the offset
-     * @param index which index to calculate the delta against
-     * @param min minimum accepted value (clamp)
-     * @param max maximum accepted value (clamp)
-     * @return new shifted palette
-     */
-    private static float[] fit(float[] data, float v, int index, float min, float max) {
-        float[] fitData = new float[data.length];
-        float delta = v - data[index];
-
-        for (int i = 0; i < data.length; i++) {
-            fitData[i] = Utilities.boundToRange(data[i] + delta, min, max);
-        }
-
-        return fitData;
-    }
-
-    /**
-     * Finds the closest color in a palette, given another HSL color
-     *
-     * @param palette where to search
-     * @param h hue
-     * @param s saturation
-     * @param l lightness
-     * @return closest index or -1 if palette is empty.
-     */
-    private static int bestFit(@NonNull TonalPalette palette, float h, float s, float l) {
-        int minErrorIndex = -1;
-        float minError = Float.POSITIVE_INFINITY;
-
-        for (int i = 0; i < palette.h.length; i++) {
-            float error =
-                    FIT_WEIGHT_H * Math.abs(h - palette.h[i])
-                            + FIT_WEIGHT_S * Math.abs(s - palette.s[i])
-                            + FIT_WEIGHT_L * Math.abs(l - palette.l[i]);
-            if (error < minError) {
-                minError = error;
-                minErrorIndex = i;
-            }
-        }
-
-        return minErrorIndex;
-    }
-
-    @Nullable
-    private static TonalPalette findTonalPalette(float h, float s) {
-        // Fallback to a grey palette if the color is too desaturated.
-        // This avoids hue shifts.
-        if (s < 0.05f) {
-            return GREY_PALETTE;
-        }
-
-        TonalPalette best = null;
-        float error = Float.POSITIVE_INFINITY;
-
-        for (int i = 0; i < TONAL_PALETTES.length; i++) {
-            final TonalPalette candidate = TONAL_PALETTES[i];
-
-            if (h >= candidate.minHue && h <= candidate.maxHue) {
-                best = candidate;
-                break;
-            }
-
-            if (candidate.maxHue > 1.0f && h >= 0.0f && h <= fract(candidate.maxHue)) {
-                best = candidate;
-                break;
-            }
-
-            if (candidate.minHue < 0.0f && h >= fract(candidate.minHue) && h <= 1.0f) {
-                best = candidate;
-                break;
-            }
-
-            if (h <= candidate.minHue && candidate.minHue - h < error) {
-                best = candidate;
-                error = candidate.minHue - h;
-            } else if (h >= candidate.maxHue && h - candidate.maxHue < error) {
-                best = candidate;
-                error = h - candidate.maxHue;
-            } else if (candidate.maxHue > 1.0f && h >= fract(candidate.maxHue)
-                    && h - fract(candidate.maxHue) < error) {
-                best = candidate;
-                error = h - fract(candidate.maxHue);
-            } else if (candidate.minHue < 0.0f && h <= fract(candidate.minHue)
-                    && fract(candidate.minHue) - h < error) {
-                best = candidate;
-                error = fract(candidate.minHue) - h;
-            }
-        }
-
-        return best;
-    }
-
-    private static float fract(float v) {
-        return v - (float) Math.floor(v);
-    }
-
-    static class TonalPalette {
-        final float[] h;
-        final float[] s;
-        final float[] l;
-        final float minHue;
-        final float maxHue;
-
-        TonalPalette(float[] h, float[] s, float[] l) {
-            if (h.length != s.length || s.length != l.length) {
-                throw new IllegalArgumentException("All arrays should have the same size. h: "
-                        + Arrays.toString(h) + " s: " + Arrays.toString(s) + " l: "
-                        + Arrays.toString(l));
-            }
-
-            this.h = h;
-            this.s = s;
-            this.l = l;
-
-            float minHue = Float.POSITIVE_INFINITY;
-            float maxHue = Float.NEGATIVE_INFINITY;
-
-            for (float v : h) {
-                minHue = Math.min(v, minHue);
-                maxHue = Math.max(v, maxHue);
-            }
-
-            this.minHue = minHue;
-            this.maxHue = maxHue;
-        }
-    }
-
-    // Data definition of Material Design tonal palettes
-    // When the sort type is set to TONAL, these palettes are used to find
-    // a best fit. Each palette is defined as 22 HSL colors
-    private static final TonalPalette[] TONAL_PALETTES = {
-            new TonalPalette(
-                    new float[] {1f, 1f, 0.991f, 0.991f, 0.9833333333333333f, 0f, 0f, 0f,
-                            0.01134380453752181f, 0.015625000000000003f, 0.024193548387096798f,
-                            0.027397260273972573f, 0.017543859649122865f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.8434782608695652f, 1f, 1f, 1f, 1f,
-                            1f},
-                    new float[] {0.04f, 0.09f, 0.14f, 0.2f, 0.27450980392156865f,
-                            0.34901960784313724f, 0.4235294117647059f, 0.5490196078431373f,
-                            0.6254901960784314f, 0.6862745098039216f, 0.7568627450980392f,
-                            0.8568627450980393f, 0.9254901960784314f}
-            ),
-            new TonalPalette(
-                    new float[] {0.638f, 0.638f, 0.6385767790262171f, 0.6301169590643275f,
-                            0.6223958333333334f, 0.6151079136690647f, 0.6065400843881856f,
-                            0.5986964618249534f, 0.5910746812386157f, 0.5833333333333334f,
-                            0.5748031496062993f, 0.5582010582010583f},
-                    new float[] {1f, 1f, 1f, 1f, 0.9014084507042253f, 0.8128654970760234f,
-                            0.7979797979797981f, 0.7816593886462883f, 0.778723404255319f, 1f, 1f,
-                            1f},
-                    new float[] {0.05f, 0.12f, 0.17450980392156862f, 0.2235294117647059f,
-                            0.2784313725490196f, 0.3352941176470588f, 0.388235294117647f,
-                            0.44901960784313727f, 0.5392156862745098f, 0.6509803921568628f,
-                            0.7509803921568627f, 0.8764705882352941f}
-            ),
-            new TonalPalette(
-                    new float[] {0.563f, 0.569f, 0.5666f, 0.5669934640522876f, 0.5748031496062993f,
-                            0.5595238095238095f, 0.5473118279569893f, 0.5393258426966292f,
-                            0.5315955766192734f, 0.524031007751938f, 0.5154711673699016f,
-                            0.508080808080808f, 0.5f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.8847736625514403f, 1f, 1f,
-                            1f},
-                    new float[] {0.07f, 0.12f, 0.16f, 0.2f, 0.24901960784313726f,
-                            0.27450980392156865f, 0.30392156862745096f, 0.34901960784313724f,
-                            0.4137254901960784f, 0.47647058823529415f, 0.5352941176470588f,
-                            0.6764705882352942f, 0.8f}
-            ),
-            new TonalPalette(
-                    new float[] {0.508f, 0.511f, 0.508f, 0.508f, 0.5082304526748972f,
-                            0.5069444444444444f, 0.5f, 0.5f, 0.5f, 0.48724954462659376f,
-                            0.4800347222222222f, 0.4755134281200632f, 0.4724409448818897f,
-                            0.4671052631578947f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 0.8888888888888887f, 0.9242424242424242f, 1f,
-                            1f, 0.8133333333333332f, 0.7868852459016393f, 1f, 1f, 1f},
-                    new float[] {0.04f, 0.06f, 0.08f, 0.12f, 0.1588235294117647f,
-                            0.21176470588235297f, 0.25882352941176473f, 0.3f, 0.34901960784313724f,
-                            0.44117647058823534f, 0.5215686274509804f, 0.5862745098039216f,
-                            0.7509803921568627f, 0.8509803921568627f}
-            ),
-            new TonalPalette(
-                    new float[] {0.333f, 0.333f, 0.333f, 0.3333333333333333f, 0.3333333333333333f,
-                            0.34006734006734f, 0.34006734006734f, 0.34006734006734f,
-                            0.34259259259259256f, 0.3475783475783476f, 0.34767025089605735f,
-                            0.3467741935483871f, 0.3703703703703704f},
-                    new float[] {0.70f, 0.72f, 0.69f, 0.6703296703296703f, 0.728813559322034f,
-                            0.5657142857142856f, 0.5076923076923077f, 0.3944223107569721f,
-                            0.6206896551724138f, 0.8931297709923666f, 1f, 1f, 1f},
-                    new float[] {0.05f, 0.08f, 0.14f, 0.1784313725490196f, 0.23137254901960785f,
-                            0.3431372549019608f, 0.38235294117647056f, 0.49215686274509807f,
-                            0.6588235294117647f, 0.7431372549019608f, 0.8176470588235294f,
-                            0.8784313725490196f, 0.9294117647058824f}
-            ),
-            new TonalPalette(
-                    new float[] {0.161f, 0.163f, 0.163f, 0.162280701754386f, 0.15032679738562088f,
-                            0.15879265091863518f, 0.16236559139784948f, 0.17443868739205526f,
-                            0.17824074074074076f, 0.18674698795180725f, 0.18692449355432778f,
-                            0.1946778711484594f, 0.18604651162790695f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
-                    new float[] {0.05f, 0.08f, 0.11f, 0.14901960784313725f, 0.2f,
-                            0.24901960784313726f, 0.30392156862745096f, 0.3784313725490196f,
-                            0.4235294117647059f, 0.48823529411764705f, 0.6450980392156863f,
-                            0.7666666666666666f, 0.8313725490196078f}
-            ),
-            new TonalPalette(
-                    new float[] {0.108f, 0.105f, 0.105f, 0.105f, 0.10619469026548674f,
-                            0.11924686192468618f, 0.13046448087431692f, 0.14248366013071895f,
-                            0.1506024096385542f, 0.16220238095238093f, 0.16666666666666666f,
-                            0.16666666666666666f, 0.162280701754386f, 0.15686274509803924f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
-                    new float[] {0.17f, 0.22f, 0.28f, 0.35f, 0.44313725490196076f,
-                            0.46862745098039216f, 0.47843137254901963f, 0.5f, 0.5117647058823529f,
-                            0.5607843137254902f, 0.6509803921568628f, 0.7509803921568627f,
-                            0.8509803921568627f, 0.9f}
-            ),
-            new TonalPalette(
-                    new float[] {0.036f, 0.036f, 0.036f, 0.036f, 0.03561253561253561f,
-                            0.05098039215686275f, 0.07516339869281045f, 0.09477124183006536f,
-                            0.1150326797385621f, 0.134640522875817f, 0.14640522875816991f,
-                            0.1582397003745319f, 0.15773809523809523f, 0.15359477124183002f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
-                    new float[] {0.19f, 0.26f, 0.34f, 0.39f, 0.4588235294117647f, 0.5f, 0.5f, 0.5f,
-                            0.5f, 0.5f, 0.5f, 0.6509803921568628f, 0.7803921568627451f, 0.9f}
-            ),
-            new TonalPalette(
-                    new float[] {0.955f, 0.961f, 0.958f, 0.9596491228070175f, 0.9593837535014005f,
-                            0.9514767932489452f, 0.943859649122807f, 0.9396825396825397f,
-                            0.9395424836601307f, 0.9393939393939394f, 0.9362745098039216f,
-                            0.9754098360655739f, 0.9824561403508771f},
-                    new float[] {0.87f, 0.85f, 0.85f, 0.84070796460177f, 0.8206896551724138f,
-                            0.7979797979797981f, 0.7661290322580644f, 0.9051724137931036f,
-                            1f, 1f, 1f, 1f, 1f},
-                    new float[] {0.06f, 0.11f, 0.16f, 0.22156862745098038f, 0.2843137254901961f,
-                            0.388235294117647f, 0.48627450980392156f, 0.5450980392156863f,
-                            0.6f, 0.6764705882352942f, 0.8f, 0.8803921568627451f,
-                            0.9254901960784314f}
-            ),
-            new TonalPalette(
-                    new float[] {0.866f, 0.855f, 0.841025641025641f, 0.8333333333333334f,
-                            0.8285256410256411f, 0.821522309711286f, 0.8083333333333333f,
-                            0.8046594982078853f, 0.8005822416302766f, 0.7842377260981912f,
-                            0.7771084337349398f, 0.7747747747747749f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f,
-                            0.737142857142857f, 0.6434108527131781f, 0.46835443037974644f},
-                    new float[] {0.05f, 0.08f, 0.12745098039215685f, 0.15490196078431373f,
-                            0.20392156862745098f, 0.24901960784313726f, 0.3137254901960784f,
-                            0.36470588235294116f, 0.44901960784313727f, 0.6568627450980392f,
-                            0.7470588235294118f, 0.8450980392156863f}
-            ),
-            new TonalPalette(
-                    new float[] {0.925f, 0.93f, 0.938f, 0.947f, 0.955952380952381f,
-                            0.9681069958847737f, 0.9760479041916167f, 0.9873563218390804f, 0f, 0f,
-                            0.009057971014492771f, 0.026748971193415648f,
-                            0.041666666666666616f, 0.05303030303030304f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 0.8350515463917526f, 0.6929460580912863f,
-                            0.6387665198237885f, 0.6914893617021276f, 0.7583892617449666f,
-                            0.8070175438596495f, 0.9310344827586209f, 1f, 1f},
-                    new float[] {0.10f, 0.13f, 0.17f, 0.2f, 0.27450980392156865f,
-                            0.3803921568627451f, 0.4725490196078432f, 0.5549019607843138f,
-                            0.6313725490196078f, 0.707843137254902f, 0.7764705882352941f,
-                            0.8294117647058823f, 0.9058823529411765f, 0.9568627450980391f}
-            ),
-            new TonalPalette(
-                    new float[] {0.733f, 0.736f, 0.744f, 0.7514619883040936f, 0.7679738562091503f,
-                            0.7802083333333333f, 0.7844311377245509f, 0.796875f,
-                            0.8165618448637316f, 0.8487179487179487f, 0.8582375478927203f,
-                            0.8562091503267975f, 0.8666666666666667f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 0.8163265306122449f, 0.6653386454183268f,
-                            0.7547169811320753f, 0.929824561403509f, 0.9558823529411766f,
-                            0.9560439560439562f, 1f, 1f},
-                    new float[] {0.07f, 0.12f, 0.17f, 0.2235294117647059f, 0.3f,
-                            0.38431372549019605f, 0.492156862745098f, 0.5843137254901961f,
-                            0.6647058823529411f, 0.7333333333333334f, 0.8215686274509804f, 0.9f,
-                            0.9411764705882353f}
-            ),
-            new TonalPalette(
-                    new float[] {0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
-                            0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
-                            0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
-                            0.6666666666666666f, 0.6666666666666666f},
-                    new float[] {0.25f, 0.24590163934426232f, 0.17880794701986752f,
-                            0.14606741573033713f, 0.13761467889908252f, 0.14893617021276592f,
-                            0.16756756756756758f, 0.20312500000000017f, 0.26086956521739135f,
-                            0.29999999999999966f, 0.5000000000000004f},
-                    new float[] {0.18f, 0.2392156862745098f, 0.296078431372549f,
-                            0.34901960784313724f, 0.4274509803921569f, 0.5392156862745098f,
-                            0.6372549019607843f, 0.7490196078431373f, 0.8196078431372549f,
-                            0.8823529411764706f, 0.9372549019607843f}
-            ),
-            new TonalPalette(
-                    new float[] {0.938f, 0.944f, 0.952f, 0.961f, 0.9678571428571429f,
-                            0.9944812362030905f, 0f, 0f,
-                            0.0047348484848484815f, 0.00316455696202532f, 0f,
-                            0.9980392156862745f, 0.9814814814814816f, 0.9722222222222221f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 0.7023255813953488f, 0.6638655462184874f,
-                            0.6521739130434782f, 0.7719298245614035f, 0.8315789473684211f,
-                            0.6867469879518071f, 0.7264957264957265f, 0.8181818181818182f,
-                            0.8181818181818189f},
-                    new float[] {0.08f, 0.13f, 0.18f, 0.23f, 0.27450980392156865f,
-                            0.4215686274509804f,
-                            0.4666666666666667f, 0.503921568627451f, 0.5529411764705883f,
-                            0.6274509803921569f, 0.6745098039215687f, 0.7705882352941176f,
-                            0.892156862745098f, 0.9568627450980391f}
-            ),
-            new TonalPalette(
-                    new float[] {0.88f, 0.888f, 0.897f, 0.9052287581699346f, 0.9112021857923498f,
-                            0.9270152505446624f, 0.9343137254901961f, 0.9391534391534391f,
-                            0.9437984496124031f, 0.943661971830986f, 0.9438943894389439f,
-                            0.9426229508196722f, 0.9444444444444444f},
-                    new float[] {1f, 1f, 1f, 1f, 0.8133333333333332f, 0.7927461139896375f,
-                            0.7798165137614679f, 0.7777777777777779f, 0.8190476190476191f,
-                            0.8255813953488372f, 0.8211382113821142f, 0.8133333333333336f,
-                            0.8000000000000006f},
-                    new float[] {0.08f, 0.12f, 0.16f, 0.2f, 0.29411764705882354f,
-                            0.3784313725490196f, 0.42745098039215684f, 0.4764705882352941f,
-                            0.5882352941176471f, 0.6627450980392157f, 0.7588235294117647f,
-                            0.8529411764705882f, 0.9411764705882353f}
-            ),
-            new TonalPalette(
-                    new float[] {0.669f, 0.680f, 0.6884057971014492f, 0.6974789915966387f,
-                            0.7079889807162534f, 0.7154471544715447f, 0.7217741935483872f,
-                            0.7274143302180687f, 0.7272727272727273f, 0.7258064516129031f,
-                            0.7252252252252251f, 0.7333333333333333f},
-                    new float[] {0.81f, 0.81f, 0.8214285714285715f, 0.6878612716763006f,
-                            0.6080402010050251f, 0.5774647887323943f, 0.5391304347826086f,
-                            0.46724890829694316f, 0.4680851063829788f, 0.462686567164179f,
-                            0.45679012345678977f, 0.4545454545454551f},
-                    new float[] {0.12f, 0.16f, 0.2196078431372549f, 0.33921568627450976f,
-                            0.39019607843137255f, 0.4176470588235294f, 0.45098039215686275f,
-                            0.5509803921568628f, 0.6313725490196078f, 0.7372549019607844f,
-                            0.8411764705882353f, 0.9352941176470588f}
-            ),
-            new TonalPalette(
-                    new float[] {0.6470588235294118f, 0.6516666666666667f, 0.6464174454828661f,
-                            0.6441441441441442f, 0.6432748538011696f, 0.6416666666666667f,
-                            0.6402439024390243f, 0.6412429378531074f, 0.6435185185185186f,
-                            0.6428571428571429f},
-                    new float[] {0.8095238095238095f, 0.6578947368421053f, 0.5721925133689839f,
-                            0.5362318840579711f, 0.5f, 0.4424778761061947f, 0.44086021505376327f,
-                            0.44360902255639095f, 0.4499999999999997f, 0.4375000000000006f},
-                    new float[] {0.16470588235294117f, 0.2980392156862745f, 0.36666666666666664f,
-                            0.40588235294117647f, 0.44705882352941173f,
-                            0.5568627450980392f, 0.6352941176470588f, 0.7392156862745098f,
-                            0.8431372549019608f, 0.9372549019607843f}
-            ),
-            new TonalPalette(
-                    new float[] {0.469f, 0.46732026143790845f, 0.4718614718614719f,
-                            0.4793650793650794f, 0.48071625344352614f, 0.4829683698296837f,
-                            0.484375f, 0.4841269841269842f, 0.48444444444444457f,
-                            0.48518518518518516f, 0.4907407407407408f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 0.6274509803921569f, 0.41832669322709176f,
-                            0.41899441340782106f, 0.4128440366972478f, 0.4090909090909088f},
-                    new float[] {0.07f, 0.1f, 0.15098039215686274f, 0.20588235294117646f,
-                            0.2372549019607843f, 0.26862745098039215f, 0.4f, 0.5078431372549019f,
-                            0.6490196078431372f, 0.7862745098039216f, 0.9137254901960784f}
-            ),
-            new TonalPalette(
-                    new float[] {0.542f, 0.5444444444444444f, 0.5555555555555556f,
-                            0.5555555555555556f, 0.553763440860215f, 0.5526315789473684f,
-                            0.5555555555555556f, 0.5555555555555555f, 0.5555555555555556f,
-                            0.5512820512820514f, 0.5666666666666667f},
-                    new float[] {0.25f, 0.24590163934426232f, 0.19148936170212766f,
-                            0.1791044776119403f, 0.18343195266272191f, 0.18446601941747576f,
-                            0.1538461538461539f, 0.15625000000000003f, 0.15328467153284678f,
-                            0.15662650602409653f, 0.151515151515151f},
-                    new float[] {0.05f, 0.1196078431372549f, 0.1843137254901961f,
-                            0.2627450980392157f,
-                            0.33137254901960783f, 0.403921568627451f, 0.5411764705882354f,
-                            0.6235294117647059f, 0.7313725490196079f, 0.8372549019607843f,
-                            0.9352941176470588f}
-            ),
-            new TonalPalette(
-                    new float[] {0.022222222222222223f, 0.02469135802469136f, 0.031249999999999997f,
-                            0.03947368421052631f, 0.04166666666666668f,
-                            0.043650793650793655f, 0.04411764705882352f, 0.04166666666666652f,
-                            0.04444444444444459f, 0.05555555555555529f},
-                    new float[] {0.33333333333333337f, 0.2783505154639175f, 0.2580645161290323f,
-                            0.25675675675675674f, 0.2528735632183908f, 0.17500000000000002f,
-                            0.15315315315315312f, 0.15189873417721522f,
-                            0.15789473684210534f, 0.15789473684210542f},
-                    new float[] {0.08823529411764705f, 0.19019607843137254f, 0.2431372549019608f,
-                            0.2901960784313725f, 0.3411764705882353f, 0.47058823529411764f,
-                            0.5647058823529412f, 0.6901960784313725f, 0.8137254901960784f,
-                            0.9254901960784314f}
-            ),
-            new TonalPalette(
-                    new float[] {0.027f, 0.03f, 0.038f, 0.044f, 0.050884955752212385f,
-                            0.07254901960784313f, 0.0934640522875817f,
-                            0.10457516339869281f, 0.11699346405228758f,
-                            0.1255813953488372f, 0.1268939393939394f, 0.12533333333333332f,
-                            0.12500000000000003f, 0.12777777777777777f},
-                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
-                    new float[] {0.25f, 0.3f, 0.35f, 0.4f, 0.44313725490196076f, 0.5f, 0.5f, 0.5f,
-                            0.5f, 0.5784313725490196f,
-                            0.6549019607843137f, 0.7549019607843137f, 0.8509803921568627f,
-                            0.9411764705882353f}
-            )
-    };
-
-    private static final TonalPalette GREY_PALETTE = new TonalPalette(
-            new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
-            new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
-            new float[]{0.08f, 0.11f, 0.14901960784313725f, 0.2f, 0.2980392156862745f, 0.4f,
-                    0.4980392156862745f, 0.6196078431372549f, 0.7176470588235294f,
-                    0.8196078431372549f, 0.9176470588235294f, 0.9490196078431372f}
-    );
-
-    @SuppressWarnings("WeakerAccess")
-    static final ColorRange[] DISALLOWED_COLORS = new ColorRange[] {
-
-            // Red
-            new ColorRange(
-                    new Range<>(0f, 20f) /* H */,
-                    new Range<>(0.7f, 1f) /* S */,
-                    new Range<>(0.21f, 0.79f)) /* L */,
-            new ColorRange(
-                    new Range<>(0f, 20f),
-                    new Range<>(0.3f, 0.7f),
-                    new Range<>(0.355f, 0.653f)),
-
-            // Red Orange
-            new ColorRange(
-                    new Range<>(20f, 40f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.28f, 0.643f)),
-            new ColorRange(
-                    new Range<>(20f, 40f),
-                    new Range<>(0.3f, 0.7f),
-                    new Range<>(0.414f, 0.561f)),
-            new ColorRange(
-                    new Range<>(20f, 40f),
-                    new Range<>(0f, 3f),
-                    new Range<>(0.343f, 0.584f)),
-
-            // Orange
-            new ColorRange(
-                    new Range<>(40f, 60f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.173f, 0.349f)),
-            new ColorRange(
-                    new Range<>(40f, 60f),
-                    new Range<>(0.3f, 0.7f),
-                    new Range<>(0.233f, 0.427f)),
-            new ColorRange(
-                    new Range<>(40f, 60f),
-                    new Range<>(0f, 0.3f),
-                    new Range<>(0.231f, 0.484f)),
-
-            // Yellow 60
-            new ColorRange(
-                    new Range<>(60f, 80f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.488f, 0.737f)),
-            new ColorRange(
-                    new Range<>(60f, 80f),
-                    new Range<>(0.3f, 0.7f),
-                    new Range<>(0.673f, 0.837f)),
-
-            // Yellow Green 80
-            new ColorRange(
-                    new Range<>(80f, 100f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.469f, 0.61f)),
-
-            // Yellow green 100
-            new ColorRange(
-                    new Range<>(100f, 120f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.388f, 0.612f)),
-            new ColorRange(
-                    new Range<>(100f, 120f),
-                    new Range<>(0.3f, 0.7f),
-                    new Range<>(0.424f, 0.541f)),
-
-            // Green
-            new ColorRange(
-                    new Range<>(120f, 140f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.375f, 0.52f)),
-            new ColorRange(
-                    new Range<>(120f, 140f),
-                    new Range<>(0.3f, 0.7f),
-                    new Range<>(0.435f, 0.524f)),
-
-            // Green Blue 140
-            new ColorRange(
-                    new Range<>(140f, 160f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.496f, 0.641f)),
-
-            // Seafoam
-            new ColorRange(
-                    new Range<>(160f, 180f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.496f, 0.567f)),
-
-            // Cyan
-            new ColorRange(
-                    new Range<>(180f, 200f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.52f, 0.729f)),
-
-            // Blue
-            new ColorRange(
-                    new Range<>(220f, 240f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.396f, 0.571f)),
-            new ColorRange(
-                    new Range<>(220f, 240f),
-                    new Range<>(0.3f, 0.7f),
-                    new Range<>(0.425f, 0.551f)),
-
-            // Blue Purple 240
-            new ColorRange(
-                    new Range<>(240f, 260f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.418f, 0.639f)),
-            new ColorRange(
-                    new Range<>(220f, 240f),
-                    new Range<>(0.3f, 0.7f),
-                    new Range<>(0.441f, 0.576f)),
-
-            // Blue Purple 260
-            new ColorRange(
-                    new Range<>(260f, 280f),
-                    new Range<>(0.3f, 1f), // Bigger range
-                    new Range<>(0.461f, 0.553f)),
-
-            // Fuchsia
-            new ColorRange(
-                    new Range<>(300f, 320f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.484f, 0.588f)),
-            new ColorRange(
-                    new Range<>(300f, 320f),
-                    new Range<>(0.3f, 0.7f),
-                    new Range<>(0.48f, 0.592f)),
-
-            // Pink
-            new ColorRange(
-                    new Range<>(320f, 340f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.466f, 0.629f)),
-
-            // Soft red
-            new ColorRange(
-                    new Range<>(340f, 360f),
-                    new Range<>(0.7f, 1f),
-                    new Range<>(0.437f, 0.596f))
-    };
-
-    /**
-     * Representation of an HSL color range.
-     * <ul>
-     * <li>hsl[0] is Hue [0 .. 360)</li>
-     * <li>hsl[1] is Saturation [0...1]</li>
-     * <li>hsl[2] is Lightness [0...1]</li>
-     * </ul>
-     */
-    static class ColorRange {
-        private Range<Float> mHue;
-        private Range<Float> mSaturation;
-        private Range<Float> mLightness;
-
-        ColorRange(Range<Float> hue, Range<Float> saturation, Range<Float> lightness) {
-            mHue = hue;
-            mSaturation = saturation;
-            mLightness = lightness;
-        }
-
-        boolean containsColor(float h, float s, float l) {
-            if (!mHue.contains(h)) {
-                return false;
-            } else if (!mSaturation.contains(s)) {
-                return false;
-            } else if (!mLightness.contains(l)) {
-                return false;
-            }
-            return true;
-        }
-
-        float[] getCenter() {
-            return new float[] {
-                    mHue.getLower() + (mHue.getUpper() - mHue.getLower()) / 2f,
-                    mSaturation.getLower() + (mSaturation.getUpper() - mSaturation.getLower()) / 2f,
-                    mLightness.getLower() + (mLightness.getUpper() - mLightness.getLower()) / 2f
-            };
-        }
-
-        @Override
-        public String toString() {
-            return String.format("H: %s, S: %s, L %s", mHue, mSaturation, mLightness);
-        }
-    }
-
-    private static List<Integer> getMainColors(WallpaperColorsCompat wallpaperColors) {
-        LinkedList<Integer> colors = new LinkedList<>();
-        if (wallpaperColors.getPrimaryColor() != 0) {
-            colors.add(wallpaperColors.getPrimaryColor());
-        }
-        if (wallpaperColors.getSecondaryColor() != 0) {
-            colors.add(wallpaperColors.getSecondaryColor());
-        }
-        if (wallpaperColors.getTertiaryColor() != 0) {
-            colors.add(wallpaperColors.getTertiaryColor());
-        }
-        return colors;
-    }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperColorsCompat.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperColorsCompat.java
deleted file mode 100644
index d984a84..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperColorsCompat.java
+++ /dev/null
@@ -1,55 +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.uioverrides.dynamicui;
-
-/**
- * A compatibility layer around platform implementation of WallpaperColors
- */
-public class WallpaperColorsCompat {
-
-    public static final int HINT_SUPPORTS_DARK_TEXT = 0x1;
-    public static final int HINT_SUPPORTS_DARK_THEME = 0x2;
-
-    private final int mPrimaryColor;
-    private final int mSecondaryColor;
-    private final int mTertiaryColor;
-    private final int mColorHints;
-
-    public WallpaperColorsCompat(int primaryColor, int secondaryColor, int tertiaryColor,
-            int colorHints) {
-        mPrimaryColor = primaryColor;
-        mSecondaryColor = secondaryColor;
-        mTertiaryColor = tertiaryColor;
-        mColorHints = colorHints;
-    }
-
-    public int getPrimaryColor() {
-        return mPrimaryColor;
-    }
-
-    public int getSecondaryColor() {
-        return mSecondaryColor;
-    }
-
-    public int getTertiaryColor() {
-        return mTertiaryColor;
-    }
-
-    public int getColorHints() {
-        return mColorHints;
-    }
-
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
deleted file mode 100644
index 9dbe47c..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
+++ /dev/null
@@ -1,61 +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.uioverrides.dynamicui;
-
-import android.content.Context;
-import android.os.Build;
-
-import androidx.annotation.Nullable;
-
-public abstract class WallpaperManagerCompat {
-
-    private static final Object sInstanceLock = new Object();
-    private static WallpaperManagerCompat sInstance;
-
-    public static WallpaperManagerCompat getInstance(Context context) {
-        synchronized (sInstanceLock) {
-            if (sInstance == null) {
-                context = context.getApplicationContext();
-
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
-                    try {
-                        sInstance = new WallpaperManagerCompatVOMR1(context);
-                    } catch (Throwable e) {
-                        // The wallpaper APIs do not yet exist
-                    }
-                }
-                if (sInstance == null) {
-                    sInstance = new WallpaperManagerCompatVL(context);
-                }
-            }
-            return sInstance;
-        }
-    }
-
-
-    public abstract @Nullable WallpaperColorsCompat getWallpaperColors(int which);
-
-    public abstract void addOnColorsChangedListener(OnColorsChangedListenerCompat listener);
-
-    /**
-     * Interface definition for a callback to be invoked when colors change on a wallpaper.
-     */
-    public interface OnColorsChangedListenerCompat {
-
-        void onColorsChanged(WallpaperColorsCompat colors, int which);
-    }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
deleted file mode 100644
index 500fdc3..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
+++ /dev/null
@@ -1,271 +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.uioverrides.dynamicui;
-
-import static android.app.WallpaperManager.FLAG_SYSTEM;
-
-import static com.android.launcher3.Utilities.getDevicePrefs;
-
-import android.app.WallpaperInfo;
-import android.app.WallpaperManager;
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.PermissionInfo;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapRegionDecoder;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.launcher3.icons.ColorExtractor;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-import androidx.annotation.Nullable;
-
-public class WallpaperManagerCompatVL extends WallpaperManagerCompat {
-
-    private static final String TAG = "WMCompatVL";
-
-    private static final String VERSION_PREFIX = "1,";
-    private static final String KEY_COLORS = "wallpaper_parsed_colors";
-    private static final String ACTION_EXTRACTION_COMPLETE =
-            "com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL.EXTRACTION_COMPLETE";
-
-    public static final int WALLPAPER_COMPAT_JOB_ID = 1;
-
-    private final ArrayList<OnColorsChangedListenerCompat> mListeners = new ArrayList<>();
-
-    private final Context mContext;
-    private WallpaperColorsCompat mColorsCompat;
-
-    WallpaperManagerCompatVL(Context context) {
-        mContext = context;
-
-        String colors = getDevicePrefs(mContext).getString(KEY_COLORS, "");
-        int wallpaperId = -1;
-        if (colors.startsWith(VERSION_PREFIX)) {
-            Pair<Integer, WallpaperColorsCompat> storedValue = parseValue(colors);
-            wallpaperId = storedValue.first;
-            mColorsCompat = storedValue.second;
-        }
-
-        if (wallpaperId == -1 || wallpaperId != getWallpaperId(context)) {
-            reloadColors();
-        }
-        context.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                reloadColors();
-            }
-        }, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED));
-
-        // Register a receiver for results
-        String permission = null;
-        // Find a permission which only we can use.
-        try {
-            for (PermissionInfo info : context.getPackageManager().getPackageInfo(
-                    context.getPackageName(),
-                    PackageManager.GET_PERMISSIONS).permissions) {
-                if ((info.protectionLevel & PermissionInfo.PROTECTION_SIGNATURE) != 0) {
-                    permission = info.name;
-                }
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            // Something went wrong. ignore
-            Log.d(TAG, "Unable to get permission info", e);
-        }
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                handleResult(intent.getStringExtra(KEY_COLORS));
-            }
-        }, new IntentFilter(ACTION_EXTRACTION_COMPLETE), permission, new Handler());
-    }
-
-    @Nullable
-    @Override
-    public WallpaperColorsCompat getWallpaperColors(int which) {
-        return which == FLAG_SYSTEM ? mColorsCompat : null;
-    }
-
-    @Override
-    public void addOnColorsChangedListener(OnColorsChangedListenerCompat listener) {
-        mListeners.add(listener);
-    }
-
-    private void reloadColors() {
-        JobInfo job = new JobInfo.Builder(WALLPAPER_COMPAT_JOB_ID,
-                new ComponentName(mContext, ColorExtractionService.class))
-                .setMinimumLatency(0).build();
-        ((JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(job);
-    }
-
-    private void handleResult(String result) {
-        getDevicePrefs(mContext).edit().putString(KEY_COLORS, result).apply();
-        mColorsCompat = parseValue(result).second;
-        for (OnColorsChangedListenerCompat listener : mListeners) {
-            listener.onColorsChanged(mColorsCompat, FLAG_SYSTEM);
-        }
-    }
-
-    private static final int getWallpaperId(Context context) {
-        return context.getSystemService(WallpaperManager.class).getWallpaperId(FLAG_SYSTEM);
-    }
-
-    /**
-     * Parses the stored value and returns the wallpaper id and wallpaper colors.
-     */
-    private static Pair<Integer, WallpaperColorsCompat> parseValue(String value) {
-        String[] parts = value.split(",");
-        Integer wallpaperId = Integer.parseInt(parts[1]);
-        if (parts.length == 2) {
-            // There is no wallpaper color info present, eg when live wallpaper has no preview.
-            return Pair.create(wallpaperId, null);
-        }
-
-        int primary = parts.length > 2 ? Integer.parseInt(parts[2]) : 0;
-        int secondary = parts.length > 3 ? Integer.parseInt(parts[3]) : 0;
-        int tertiary = parts.length > 4 ? Integer.parseInt(parts[4]) : 0;
-
-        return Pair.create(wallpaperId, new WallpaperColorsCompat(primary, secondary, tertiary,
-                0 /* hints */));
-    }
-
-    /**
-     * Intent service to handle color extraction
-     */
-    public static class ColorExtractionService extends JobService implements Runnable {
-        private static final int MAX_WALLPAPER_EXTRACTION_AREA = 112 * 112;
-
-        private HandlerThread mWorkerThread;
-        private Handler mWorkerHandler;
-        private ColorExtractor mColorExtractor;
-
-        @Override
-        public void onCreate() {
-            super.onCreate();
-            mWorkerThread = new HandlerThread("ColorExtractionService");
-            mWorkerThread.start();
-            mWorkerHandler = new Handler(mWorkerThread.getLooper());
-            mColorExtractor = new ColorExtractor();
-        }
-
-        @Override
-        public void onDestroy() {
-            super.onDestroy();
-            mWorkerThread.quit();
-        }
-
-        @Override
-        public boolean onStartJob(final JobParameters jobParameters) {
-            mWorkerHandler.post(this);
-            return true;
-        }
-
-        @Override
-        public boolean onStopJob(JobParameters jobParameters) {
-            mWorkerHandler.removeCallbacksAndMessages(null);
-            return true;
-        }
-
-        /**
-         * Extracts the wallpaper colors and sends the result back through the receiver.
-         */
-        @Override
-        public void run() {
-            int wallpaperId = getWallpaperId(this);
-
-            Bitmap bitmap = null;
-            Drawable drawable = null;
-
-            WallpaperManager wm = WallpaperManager.getInstance(this);
-            WallpaperInfo info = wm.getWallpaperInfo();
-            if (info != null) {
-                // For live wallpaper, extract colors from thumbnail
-                drawable = info.loadThumbnail(getPackageManager());
-            } else {
-                try (ParcelFileDescriptor fd = wm.getWallpaperFile(FLAG_SYSTEM)) {
-                    BitmapRegionDecoder decoder = BitmapRegionDecoder
-                            .newInstance(fd.getFileDescriptor(), false);
-
-                    int requestedArea = decoder.getWidth() * decoder.getHeight();
-                    BitmapFactory.Options options = new BitmapFactory.Options();
-
-                    if (requestedArea > MAX_WALLPAPER_EXTRACTION_AREA) {
-                        double areaRatio =
-                                (double) requestedArea / MAX_WALLPAPER_EXTRACTION_AREA;
-                        double nearestPowOf2 =
-                                Math.floor(Math.log(areaRatio) / (2 * Math.log(2)));
-                        options.inSampleSize = (int) Math.pow(2, nearestPowOf2);
-                    }
-                    Rect region = new Rect(0, 0, decoder.getWidth(), decoder.getHeight());
-                    bitmap = decoder.decodeRegion(region, options);
-                    decoder.recycle();
-                } catch (IOException | NullPointerException e) {
-                    Log.e(TAG, "Fetching partial bitmap failed, trying old method", e);
-                }
-                if (bitmap == null) {
-                    drawable = wm.getDrawable();
-                }
-            }
-
-            if (drawable != null) {
-                // Calculate how big the bitmap needs to be.
-                // This avoids unnecessary processing and allocation inside Palette.
-                final int requestedArea = drawable.getIntrinsicWidth() *
-                        drawable.getIntrinsicHeight();
-                double scale = 1;
-                if (requestedArea > MAX_WALLPAPER_EXTRACTION_AREA) {
-                    scale = Math.sqrt(MAX_WALLPAPER_EXTRACTION_AREA / (double) requestedArea);
-                }
-                bitmap = Bitmap.createBitmap((int) (drawable.getIntrinsicWidth() * scale),
-                        (int) (drawable.getIntrinsicHeight() * scale), Bitmap.Config.ARGB_8888);
-                final Canvas bmpCanvas = new Canvas(bitmap);
-                drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
-                drawable.draw(bmpCanvas);
-            }
-
-            String value = VERSION_PREFIX + wallpaperId;
-
-            if (bitmap != null) {
-                int color = mColorExtractor.findDominantColorByHue(bitmap,
-                        MAX_WALLPAPER_EXTRACTION_AREA);
-                value += "," + color;
-            }
-
-            // Send the result
-            sendBroadcast(new Intent(ACTION_EXTRACTION_COMPLETE)
-                    .setPackage(getPackageName())
-                    .putExtra(KEY_COLORS, value));
-        }
-    }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
deleted file mode 100644
index f34497d..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
+++ /dev/null
@@ -1,85 +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.uioverrides.dynamicui;
-
-import android.annotation.TargetApi;
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
-import android.app.WallpaperManager.OnColorsChangedListener;
-import android.content.Context;
-import android.graphics.Color;
-import android.util.Log;
-
-import java.lang.reflect.Method;
-
-import androidx.annotation.Nullable;
-
-@TargetApi(27)
-public class WallpaperManagerCompatVOMR1 extends WallpaperManagerCompat {
-
-    private static final String TAG = "WMCompatVOMR1";
-
-    private final WallpaperManager mWm;
-    private Method mWCColorHintsMethod;
-
-    WallpaperManagerCompatVOMR1(Context context) throws Throwable {
-        mWm = context.getSystemService(WallpaperManager.class);
-        String className = WallpaperColors.class.getName();
-        try {
-            mWCColorHintsMethod = WallpaperColors.class.getDeclaredMethod("getColorHints");
-        } catch (Exception exc) {
-            Log.e(TAG, "getColorHints not available", exc);
-        }
-    }
-
-    @Nullable
-    @Override
-    public WallpaperColorsCompat getWallpaperColors(int which) {
-        return convertColorsObject(mWm.getWallpaperColors(which));
-    }
-
-    @Override
-    public void addOnColorsChangedListener(final OnColorsChangedListenerCompat listener) {
-        OnColorsChangedListener onChangeListener = new OnColorsChangedListener() {
-            @Override
-            public void onColorsChanged(WallpaperColors colors, int which) {
-                listener.onColorsChanged(convertColorsObject(colors), which);
-            }
-        };
-        mWm.addOnColorsChangedListener(onChangeListener, null);
-    }
-
-    private WallpaperColorsCompat convertColorsObject(WallpaperColors colors) {
-        if (colors == null) {
-            return null;
-        }
-        Color primary = colors.getPrimaryColor();
-        Color secondary = colors.getSecondaryColor();
-        Color tertiary = colors.getTertiaryColor();
-        int primaryVal = primary != null ? primary.toArgb() : 0;
-        int secondaryVal = secondary != null ? secondary.toArgb() : 0;
-        int tertiaryVal = tertiary != null ? tertiary.toArgb() : 0;
-        int colorHints = 0;
-        try {
-            if (mWCColorHintsMethod != null) {
-                colorHints = (Integer) mWCColorHintsMethod.invoke(colors);
-            }
-        } catch (Exception exc) {
-            Log.e(TAG, "error calling color hints", exc);
-        }
-        return new WallpaperColorsCompat(primaryVal, secondaryVal, tertiaryVal, colorHints);
-    }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
index 53748b7..978c321 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
 
 /**
  * Definition for AllApps state
@@ -76,7 +77,7 @@
     }
 
     @Override
-    public float getWorkspaceScrimAlpha(Launcher launcher) {
-        return 1;
+    public int getWorkspaceScrimColor(Launcher launcher) {
+        return Themes.getAttrColor(launcher, R.attr.allAppsScrimColor);
     }
 }
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
index e85e505..d154317 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -19,7 +19,10 @@
 
 import android.content.Context;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
 
 /**
  * Definition for overview state
@@ -56,4 +59,9 @@
     public static OverviewState newSplitSelectState(int id) {
         return new OverviewState(id);
     }
+
+    @Override
+    public int getWorkspaceScrimColor(Launcher launcher) {
+        return Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
+    }
 }