Merge "Fix drop target icons being truncated." into sc-dev
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 1bf3627..33dc6cf 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -422,8 +422,8 @@
 
     @Override
     public Stream<SystemShortcut.Factory> getSupportedShortcuts() {
-        return Stream.concat(super.getSupportedShortcuts(),
-                Stream.of(WellbeingModel.SHORTCUT_FACTORY));
+        return Stream.concat(Stream.of(WellbeingModel.SHORTCUT_FACTORY),
+                super.getSupportedShortcuts());
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index f0b02b3..ec9893c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -192,7 +192,7 @@
     @Override
     public Stream<SystemShortcut.Factory> getSupportedShortcuts() {
         return Stream.concat(
-                super.getSupportedShortcuts(), Stream.of(mHotseatPredictionController));
+                Stream.of(mHotseatPredictionController), super.getSupportedShortcuts());
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index a9dacee..0ebaea2 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -45,8 +45,6 @@
 import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
 import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
 import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
-import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_END;
-import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_START;
 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.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
@@ -248,7 +246,6 @@
 
     private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch;
 
-    private static final long SWIPE_PIP_TO_HOME_DURATION = 425;
     private SwipePipToHomeAnimator mSwipePipToHomeAnimator;
     protected boolean mIsSwipingPipToHome;
 
@@ -1134,17 +1131,14 @@
                     createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
                             runningTaskTarget);
             mIsSwipingPipToHome = homeAnimFactory.supportSwipePipToHome() && appCanEnterPip;
+            final RectFSpringAnim windowAnim;
             if (mIsSwipingPipToHome) {
-                mSwipePipToHomeAnimator = getSwipePipToHomeAnimator(
+                mSwipePipToHomeAnimator = createWindowAnimationToPip(
                         homeAnimFactory, runningTaskTarget, start);
-                mSwipePipToHomeAnimator.setDuration(SWIPE_PIP_TO_HOME_DURATION);
-                mSwipePipToHomeAnimator.setInterpolator(interpolator);
-                mSwipePipToHomeAnimator.setFloatValues(FRACTION_START, FRACTION_END);
-                mSwipePipToHomeAnimator.start();
-                mRunningWindowAnim = RunningWindowAnim.wrap(mSwipePipToHomeAnimator);
+                windowAnim = mSwipePipToHomeAnimator;
             } else {
                 mSwipePipToHomeAnimator = null;
-                RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
+                windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
                 windowAnim.addAnimatorListener(new AnimationSuccessListener() {
                     @Override
                     public void onAnimationSuccess(Animator animator) {
@@ -1158,9 +1152,9 @@
                         mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
                     }
                 });
-                windowAnim.start(mContext, velocityPxPerMs);
-                mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
             }
+            windowAnim.start(mContext, velocityPxPerMs);
+            mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
             homeAnimFactory.setSwipeVelocity(velocityPxPerMs.y);
             homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
             mLauncherTransitionController = null;
@@ -1216,7 +1210,7 @@
         }
     }
 
-    private SwipePipToHomeAnimator getSwipePipToHomeAnimator(HomeAnimationFactory homeAnimFactory,
+    private SwipePipToHomeAnimator createWindowAnimationToPip(HomeAnimationFactory homeAnimFactory,
             RemoteAnimationTargetCompat runningTaskTarget, float startProgress) {
         // Directly animate the app to PiP (picture-in-picture) mode
         final ActivityManager.RunningTaskInfo taskInfo = mGestureState.getRunningTask();
@@ -1229,16 +1223,15 @@
                         runningTaskTarget.taskInfo.pictureInPictureParams,
                         homeRotation,
                         mDp.hotseatBarSizePx);
-        final Rect startBounds = new Rect();
-        updateProgressForStartRect(new Matrix(), startProgress).round(startBounds);
         final SwipePipToHomeAnimator swipePipToHomeAnimator = new SwipePipToHomeAnimator(
+                mContext,
                 runningTaskTarget.taskId,
                 taskInfo.topActivity,
                 runningTaskTarget.leash.getSurfaceControl(),
                 TaskInfoCompat.getPipSourceRectHint(
                         runningTaskTarget.taskInfo.pictureInPictureParams),
                 TaskInfoCompat.getWindowConfigurationBounds(taskInfo),
-                startBounds,
+                updateProgressForStartRect(new Matrix(), startProgress),
                 destinationBounds,
                 mRecentsView.getPipCornerRadius(),
                 mRecentsView);
@@ -1250,7 +1243,7 @@
         }
         AnimatorPlaybackController activityAnimationToHome =
                 homeAnimFactory.createActivityAnimationToHome();
-        swipePipToHomeAnimator.addListener(new AnimatorListenerAdapter() {
+        swipePipToHomeAnimator.addAnimatorListener(new AnimatorListenerAdapter() {
             private boolean mHasAnimationEnded;
             @Override
             public void onAnimationStart(Animator animation) {
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index 4c10822..7eca360 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -27,8 +27,11 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_DISABLED;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_ENABLED;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_DISABLED;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_ENABLED;
 import static com.android.launcher3.model.QuickstepModelDelegate.LAST_PREDICTION_ENABLED_STATE;
 import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
+import static com.android.launcher3.util.Themes.KEY_THEMED_ICONS;
 
 import android.content.Context;
 import android.content.SharedPreferences;
@@ -40,6 +43,7 @@
 
 import com.android.launcher3.AutoInstallsLayout;
 import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.InstanceIdSequence;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
@@ -170,6 +174,13 @@
         if (gridSizeChangedEvent != null) {
             logger.log(gridSizeChangedEvent);
         }
+
+        if (FeatureFlags.ENABLE_THEMED_ICONS.get()) {
+            logger.log(prefs.getBoolean(KEY_THEMED_ICONS, false)
+                    ? LAUNCHER_THEMED_ICON_ENABLED
+                    : LAUNCHER_THEMED_ICON_DISABLED);
+        }
+
         mLoggablePrefs.forEach((key, lp) -> logger.log(() ->
                 prefs.getBoolean(key, lp.defaultValue) ? lp.eventIdOn : lp.eventIdOff));
     }
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 61a2eaf..67a635b 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -20,8 +20,8 @@
 
 import android.animation.Animator;
 import android.animation.RectEvaluator;
-import android.animation.ValueAnimator;
 import android.content.ComponentName;
+import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Rect;
@@ -44,30 +44,24 @@
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 
 /**
- * An {@link Animator} that animates an Activity to PiP (picture-in-picture) window when
- * swiping up (in gesture navigation mode). Note that this class is derived from
- * {@link com.android.wm.shell.pip.PipAnimationController.PipTransitionAnimator}.
- *
- * TODO: consider sharing this class including the animator and leash operations between
- * Launcher and SysUI. Also, there should be one source of truth for the corner radius of the
- * PiP window, which would ideally be on SysUI side as well.
+ * Subclass of {@link RectFSpringAnim} that animates an Activity to PiP (picture-in-picture) window
+ * when swiping up (in gesture navigation mode).
  */
-public class SwipePipToHomeAnimator extends ValueAnimator {
+public class SwipePipToHomeAnimator extends RectFSpringAnim {
     private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName();
 
-    public static final float FRACTION_START = 0f;
-    public static final float FRACTION_END = 1f;
+    private static final float END_PROGRESS = 1.0f;
 
     private final int mTaskId;
     private final ComponentName mComponentName;
     private final SurfaceControl mLeash;
     private final Rect mAppBounds = new Rect();
     private final Rect mStartBounds = new Rect();
+    private final Rect mCurrentBounds = new Rect();
     private final Rect mDestinationBounds = new Rect();
     private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
 
-    /** for calculating the transform in {@link #onAnimationUpdate(ValueAnimator)} */
-    private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
+    /** for calculating transform in {@link #onAnimationUpdate(AppCloseConfig, RectF, float)} */
     private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect());
     private final Rect mSourceHintRectInsets;
     private final Rect mSourceInsets = new Rect();
@@ -90,6 +84,7 @@
     private SurfaceControl mContentOverlay;
 
     /**
+     * @param context {@link Context} provides Launcher resources
      * @param taskId Task id associated with this animator, see also {@link #getTaskId()}
      * @param componentName Component associated with this animator,
      *                      see also {@link #getComponentName()}
@@ -102,20 +97,22 @@
      * @param destinationBounds Bounds of the destination this animator ends to
      * @param cornerRadius Corner radius in pixel value for PiP window
      */
-    public SwipePipToHomeAnimator(int taskId,
+    public SwipePipToHomeAnimator(@NonNull Context context,
+            int taskId,
             @NonNull ComponentName componentName,
             @NonNull SurfaceControl leash,
             @Nullable Rect sourceRectHint,
             @NonNull Rect appBounds,
-            @NonNull Rect startBounds,
+            @NonNull RectF startBounds,
             @NonNull Rect destinationBounds,
             int cornerRadius,
             @NonNull View view) {
+        super(startBounds, new RectF(destinationBounds), context);
         mTaskId = taskId;
         mComponentName = componentName;
         mLeash = leash;
         mAppBounds.set(appBounds);
-        mStartBounds.set(startBounds);
+        startBounds.round(mStartBounds);
         mDestinationBounds.set(destinationBounds);
         mDestinationBoundsTransformed.set(mDestinationBounds);
         mDestinationBoundsAnimation.set(mDestinationBounds);
@@ -151,10 +148,10 @@
             t.reparent(mContentOverlay, mLeash);
             t.apply();
 
-            addUpdateListener(valueAnimator -> {
-                float alpha = valueAnimator.getAnimatedFraction() < 0.5f
+            addOnUpdateListener((values, currentRect, progress) -> {
+                float alpha = progress < 0.5f
                         ? 0
-                        : Utilities.mapToRange(valueAnimator.getAnimatedFraction(), 0.5f, 1f,
+                        : Utilities.mapToRange(Math.min(progress, 1f), 0.5f, 1f,
                                 0f, 1f, Interpolators.FAST_OUT_SLOW_IN);
                 t.setAlpha(mContentOverlay, alpha);
                 t.apply();
@@ -166,7 +163,7 @@
                     appBounds.bottom - sourceRectHint.bottom);
         }
 
-        addListener(new AnimationSuccessListener() {
+        addAnimatorListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationStart(Animator animation) {
                 InteractionJankMonitorWrapper.begin(view, CUJ_APP_CLOSE_TO_PIP);
@@ -191,7 +188,7 @@
                 mHasAnimationEnded = true;
             }
         });
-        addUpdateListener(this::onAnimationUpdate);
+        addOnUpdateListener(this::onAnimationUpdate);
     }
 
     /** sets the from rotation if it's different from the target rotation. */
@@ -219,34 +216,34 @@
                 mAppBounds.top + mDestinationBounds.height());
     }
 
-    private void onAnimationUpdate(ValueAnimator animator) {
+    private void onAnimationUpdate(@Nullable AppCloseConfig values, RectF currentRect,
+            float progress) {
         if (mHasAnimationEnded) return;
         final SurfaceControl.Transaction tx =
                 PipSurfaceTransactionHelper.newSurfaceControlTransaction();
-        onAnimationUpdate(tx, animator.getAnimatedFraction());
+        onAnimationUpdate(tx, currentRect, progress);
         tx.apply();
     }
 
     private PictureInPictureSurfaceTransaction onAnimationUpdate(SurfaceControl.Transaction tx,
-            float fraction) {
-        final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds,
-                mDestinationBoundsAnimation);
+            RectF currentRect, float progress) {
+        currentRect.round(mCurrentBounds);
         final PictureInPictureSurfaceTransaction op;
         if (mSourceHintRectInsets == null) {
             // no source rect hint been set, directly scale the window down
-            op = onAnimationScale(fraction, tx, bounds);
+            op = onAnimationScale(progress, tx, mCurrentBounds);
         } else {
             // scale and crop according to the source rect hint
-            op = onAnimationScaleAndCrop(fraction, tx, bounds);
+            op = onAnimationScaleAndCrop(progress, tx, mCurrentBounds);
         }
         return op;
     }
 
     /** scale the window directly with no source rect hint being set */
     private PictureInPictureSurfaceTransaction onAnimationScale(
-            float fraction, SurfaceControl.Transaction tx, Rect bounds) {
+            float progress, SurfaceControl.Transaction tx, Rect bounds) {
         if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
-            final RotatedPosition rotatedPosition = getRotatedPosition(fraction);
+            final RotatedPosition rotatedPosition = getRotatedPosition(progress);
             return mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds,
                     rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
         } else {
@@ -256,12 +253,12 @@
 
     /** scale and crop the window with source rect hint */
     private PictureInPictureSurfaceTransaction onAnimationScaleAndCrop(
-            float fraction, SurfaceControl.Transaction tx,
+            float progress, SurfaceControl.Transaction tx,
             Rect bounds) {
-        final Rect insets = mInsetsEvaluator.evaluate(fraction, mSourceInsets,
+        final Rect insets = mInsetsEvaluator.evaluate(progress, mSourceInsets,
                 mSourceHintRectInsets);
         if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
-            final RotatedPosition rotatedPosition = getRotatedPosition(fraction);
+            final RotatedPosition rotatedPosition = getRotatedPosition(progress);
             return mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets,
                     rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
         } else {
@@ -291,22 +288,22 @@
         // get the final leash operations but do not apply to the leash.
         final SurfaceControl.Transaction tx =
                 PipSurfaceTransactionHelper.newSurfaceControlTransaction();
-        return onAnimationUpdate(tx, FRACTION_END);
+        return onAnimationUpdate(tx, new RectF(mDestinationBounds), END_PROGRESS);
     }
 
-    private RotatedPosition getRotatedPosition(float fraction) {
+    private RotatedPosition getRotatedPosition(float progress) {
         final float degree, positionX, positionY;
         if (mFromRotation == Surface.ROTATION_90) {
-            degree = -90 * fraction;
-            positionX = fraction * (mDestinationBoundsTransformed.left - mStartBounds.left)
+            degree = -90 * progress;
+            positionX = progress * (mDestinationBoundsTransformed.left - mStartBounds.left)
                     + mStartBounds.left;
-            positionY = fraction * (mDestinationBoundsTransformed.bottom - mStartBounds.top)
+            positionY = progress * (mDestinationBoundsTransformed.bottom - mStartBounds.top)
                     + mStartBounds.top;
         } else {
-            degree = 90 * fraction;
-            positionX = fraction * (mDestinationBoundsTransformed.right - mStartBounds.left)
+            degree = 90 * progress;
+            positionX = progress * (mDestinationBoundsTransformed.right - mStartBounds.left)
                     + mStartBounds.left;
-            positionY = fraction * (mDestinationBoundsTransformed.top - mStartBounds.top)
+            positionY = progress * (mDestinationBoundsTransformed.top - mStartBounds.top)
                     + mStartBounds.top;
         }
         return new RotatedPosition(degree, positionX, positionY);
diff --git a/res/drawable/ic_drag_handle.xml b/res/drawable/ic_drag_handle.xml
index 0181ff1..9db75f4 100644
--- a/res/drawable/ic_drag_handle.xml
+++ b/res/drawable/ic_drag_handle.xml
@@ -19,7 +19,7 @@
         android:height="@dimen/deep_shortcut_drag_handle_size"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"
-        android:tint="?android:attr/textColorHint" >
+        android:tint="?android:attr/textColorPrimary" >
 
     <path
         android:pathData="M20,9H4v2h16V9z M4,15h16v-2H4V15z"
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 6337fae..2cdf1f4 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -45,6 +45,6 @@
         android:layout_height="@dimen/system_shortcut_icon_size"
         android:layout_marginStart="@dimen/system_shortcut_margin_start"
         android:layout_gravity="start|center_vertical"
-        android:backgroundTint="?android:attr/textColorTertiary"/>
+        android:backgroundTint="?android:attr/textColorPrimary"/>
 
 </com.android.launcher3.shortcuts.DeepShortcutView>
diff --git a/res/layout/widget_shortcut_container.xml b/res/layout/widget_shortcut_container.xml
new file mode 100644
index 0000000..a4d8eb4
--- /dev/null
+++ b/res/layout/widget_shortcut_container.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/system_shortcut_full"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/system_shortcut_header_height"
+    android:orientation="horizontal"
+    android:gravity="end|center_vertical"
+    android:elevation="@dimen/deep_shortcuts_elevation"
+    android:tag="@string/popup_container_iterate_children"
+    android:clipToPadding="true">
+</LinearLayout>
diff --git a/res/layout/widgets_table_container.xml b/res/layout/widgets_table_container.xml
index c6b70aa..4f70a05 100644
--- a/res/layout/widgets_table_container.xml
+++ b/res/layout/widgets_table_container.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<TableLayout
+<com.android.launcher3.widget.picker.WidgetsListTableView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/widgets_table"
     android:layout_width="match_parent"
diff --git a/res/layout/work_apps_edu.xml b/res/layout/work_apps_edu.xml
index 2c58907..ffbf962 100644
--- a/res/layout/work_apps_edu.xml
+++ b/res/layout/work_apps_edu.xml
@@ -16,30 +16,38 @@
 <com.android.launcher3.allapps.WorkEduCard xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:padding="@dimen/work_edu_card_margin"
-    android:orientation="vertical"
-    android:background="@drawable/work_card"
     android:gravity="center">
 
-    <TextView
-        style="@style/PrimaryHeadline"
-        android:textColor="?android:attr/textColorPrimary"
-        android:id="@+id/work_apps_paused_title"
-        android:layout_width="wrap_content"
+    <LinearLayout
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="8dp"
-        android:layout_marginBottom="8dp"
-        android:text="@string/work_profile_edu_work_apps"
-        android:textAlignment="center"
-        android:textSize="20sp" />
+        android:orientation="vertical"
+        android:padding="@dimen/work_edu_card_margin"
+        android:background="@drawable/work_card"
+        android:layout_gravity="center_horizontal"
+        android:gravity="center"
+        android:id="@+id/wrapper">
 
-    <Button
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:id="@+id/action_btn"
-        android:textColor="?attr/workProfileOverlayTextColor"
-        android:text="@string/work_profile_edu_accept"
-        android:textAlignment="center"
-        android:background="@drawable/work_card_btn"
-        android:textSize="14sp" />
+        <TextView
+            style="@style/PrimaryHeadline"
+            android:textColor="?android:attr/textColorPrimary"
+            android:id="@+id/work_apps_paused_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:layout_marginBottom="8dp"
+            android:text="@string/work_profile_edu_work_apps"
+            android:textAlignment="center"
+            android:textSize="20sp" />
+
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/action_btn"
+            android:textColor="?attr/workProfileOverlayTextColor"
+            android:text="@string/work_profile_edu_accept"
+            android:textAlignment="center"
+            android:background="@drawable/work_card_btn"
+            android:textSize="14sp" />
+    </LinearLayout>
 </com.android.launcher3.allapps.WorkEduCard>
\ No newline at end of file
diff --git a/res/layout/work_apps_paused.xml b/res/layout/work_apps_paused.xml
index 7f1107f..14dcb8c 100644
--- a/res/layout/work_apps_paused.xml
+++ b/res/layout/work_apps_paused.xml
@@ -12,11 +12,10 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.allapps.WorkPausedCard xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="?attr/allAppsScrimColor"
-    android:padding="48dp"
+    android:layout_height="wrap_content"
+    android:padding="@dimen/work_edu_card_margin"
     android:orientation="vertical"
     android:gravity="center">
 
@@ -39,5 +38,16 @@
         android:textColor="?attr/workProfileOverlayTextColor"
         android:text="@string/work_apps_paused_body"
         android:textAlignment="center"
+        android:layout_marginBottom="8dp"
         android:textSize="16sp" />
-</LinearLayout>
\ No newline at end of file
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/enable_work_apps"
+        android:textColor="?attr/workProfileOverlayTextColor"
+        android:text="@string/work_apps_enable_btn_text"
+        android:textAlignment="center"
+        android:background="@drawable/work_card_btn"
+        android:textSize="14sp" />
+</com.android.launcher3.allapps.WorkPausedCard>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index e8d3212..12f50e5 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -94,7 +94,7 @@
     <dimen name="all_apps_background_canvas_height">475dp</dimen>
     <dimen name="all_apps_header_pill_height">48dp</dimen>
     <dimen name="all_apps_header_pill_corner_radius">18dp</dimen>
-    <dimen name="all_apps_header_pills_width">320dp</dimen>
+    <dimen name="all_apps_header_pills_width">348dp</dimen>
     <dimen name="all_apps_header_tab_height">48dp</dimen>
     <dimen name="all_apps_tabs_indicator_height">2dp</dimen>
     <dimen name="all_apps_header_top_padding">36dp</dimen>
@@ -140,7 +140,6 @@
 
     <dimen name="widget_list_top_bottom_corner_radius">28dp</dimen>
     <dimen name="widget_list_content_corner_radius">4dp</dimen>
-    <dimen name="widget_list_content_joined_corner_radius">0dp</dimen>
 
     <dimen name="widget_list_header_view_vertical_padding">20dp</dimen>
     <dimen name="widget_list_entry_bottom_margin">2dp</dimen>
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index 84a03d5..4e2a508 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -107,7 +107,10 @@
                 /* iconClickListener= */ view -> {},
                 /* iconLongClickListener= */ view -> false);
         mViewHolderBinder = new WidgetsListHeaderViewHolderBinder(
-                LayoutInflater.from(mTestActivity), mOnHeaderClickListener, widgetsListAdapter);
+                LayoutInflater.from(mTestActivity),
+                mOnHeaderClickListener,
+                new WidgetsListDrawableFactory(mTestActivity),
+                widgetsListAdapter);
     }
 
     @After
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
index 075c58d..d6aea55 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
@@ -107,7 +107,10 @@
                 /* iconClickListener= */ view -> {},
                 /* iconLongClickListener= */ view -> false);
         mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder(
-                LayoutInflater.from(mTestActivity), mOnHeaderClickListener, widgetsListAdapter);
+                LayoutInflater.from(mTestActivity),
+                mOnHeaderClickListener,
+                new WidgetsListDrawableFactory(mTestActivity),
+                widgetsListAdapter);
     }
 
     @After
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 0c6e717..2f1326f 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -118,6 +118,7 @@
                 mOnIconClickListener,
                 mOnLongClickListener,
                 mWidgetPreviewLoader,
+                new WidgetsListDrawableFactory(mTestActivity),
                 widgetsListAdapter);
     }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index d749e02..7003df1 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -23,7 +23,6 @@
 
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -494,15 +493,6 @@
         }
     }
 
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        View overlay = mAH[AdapterHolder.WORK].getOverlayView();
-        int v = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ? GONE : VISIBLE;
-        overlay.findViewById(R.id.work_apps_paused_title).setVisibility(v);
-        overlay.findViewById(R.id.work_apps_paused_content).setVisibility(v);
-    }
-
     private void replaceRVContainer(boolean showTabs) {
         for (int i = 0; i < mAH.length; i++) {
             if (mAH[i].recyclerView != null) {
@@ -544,9 +534,6 @@
                     && mAllAppsStore.hasModelFlag(
                     FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION));
         }
-        if (mSearchUiManager != null && mSearchUiManager.getEditText() != null) {
-            mSearchUiManager.getEditText().hideKeyboard();
-        }
     }
 
     // Used by tests only
@@ -704,7 +691,9 @@
         mHeaderPaint.setColor(mHeaderColor);
         mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor)));
         if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) {
-            canvas.drawRect(0, 0, getWidth(), mSearchContainer.getTop() + getTranslationY(),
+            int bottom = mUsingTabs && mHeader.mHeaderCollapsed ? mHeader.getVisibleBottomBound()
+                    : mSearchContainer.getBottom();
+            canvas.drawRect(0, 0, getWidth(), bottom + getTranslationY(),
                     mHeaderPaint);
         }
     }
@@ -781,13 +770,6 @@
             mAH[AdapterHolder.MAIN].recyclerView.setVerticalFadingEdgeEnabled(!mUsingTabs
                     && verticalFadingEdge);
         }
-
-        private View getOverlayView() {
-            if (mOverlay == null) {
-                mOverlay = mLauncher.getLayoutInflater().inflate(R.layout.work_apps_paused, null);
-            }
-            return mOverlay;
-        }
     }
 
 
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 5bbd02b..4ad694b 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -447,4 +447,14 @@
     public boolean hasOverlappingRendering() {
         return false;
     }
+
+    /**
+     * Returns distance between left and right app icons
+     */
+    public int getTabWidth() {
+        DeviceProfile grid = BaseDraggingActivity.fromContext(getContext()).getDeviceProfile();
+        int totalWidth = (grid.availableWidthPx - getPaddingLeft() - getPaddingRight());
+        int iconPadding = totalWidth / grid.numShownAllAppsColumns - grid.allAppsIconSizePx;
+        return totalWidth - iconPadding;
+    }
 }
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 450d2e2..f1381e9 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -72,8 +72,13 @@
                     }
 
                     int current = -mCurrentRV.getCurrentScrollY();
+                    boolean headerCollapsed = mHeaderCollapsed;
                     moved(current);
                     applyVerticalMove();
+                    if (headerCollapsed != mHeaderCollapsed) {
+                        AllAppsContainerView parent = (AllAppsContainerView) getParent();
+                        parent.invalidateHeader();
+                    }
                 }
             };
 
@@ -219,6 +224,8 @@
 
         mTabsHidden = tabsHidden;
         mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE);
+        mTabLayout.getLayoutParams().width =
+                mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView.getTabWidth();
         mMainRV = setupRV(mMainRV, mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView);
         mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView);
         mParent = (ViewGroup) mMainRV.getParent();
@@ -429,6 +436,13 @@
         }
         return null;
     }
+
+    /**
+     * Returns visible height of FloatingHeaderView contents
+     */
+    public int getVisibleBottomBound() {
+        return getBottom() + mTranslationY;
+    }
 }
 
 
diff --git a/src/com/android/launcher3/allapps/WorkEduCard.java b/src/com/android/launcher3/allapps/WorkEduCard.java
index 29a42f8..9db7bf0 100644
--- a/src/com/android/launcher3/allapps/WorkEduCard.java
+++ b/src/com/android/launcher3/allapps/WorkEduCard.java
@@ -21,7 +21,7 @@
 import android.view.ViewGroup;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
@@ -29,7 +29,7 @@
 /**
  * Work profile toggle switch shown at the bottom of AllApps work tab
  */
-public class WorkEduCard extends LinearLayout implements View.OnClickListener,
+public class WorkEduCard extends FrameLayout implements View.OnClickListener,
         Animation.AnimationListener {
 
     private final Launcher mLauncher;
@@ -52,11 +52,24 @@
         mDismissAnim.setAnimationListener(this);
     }
 
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mDismissAnim.reset();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mDismissAnim.cancel();
+    }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         findViewById(R.id.action_btn).setOnClickListener(this);
+        MarginLayoutParams lp = ((MarginLayoutParams) findViewById(R.id.wrapper).getLayoutParams());
+        lp.width = mLauncher.getAppsView().getActiveRecyclerView().getTabWidth();
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index c22cd63..866694f 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -31,7 +31,6 @@
 import androidx.annotation.RequiresApi;
 
 import com.android.launcher3.Insettable;
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.pm.UserCache;
 
@@ -79,7 +78,9 @@
         clearAnimation();
         if (workTabVisible) {
             setEnabled(true);
-            setVisibility(VISIBLE);
+            if (mWorkEnabled) {
+                setVisibility(VISIBLE);
+            }
             setAlpha(0);
             animate().alpha(1).start();
         } else {
@@ -91,7 +92,7 @@
     public void onClick(View view) {
         if (Utilities.ATLEAST_P) {
             setEnabled(false);
-            UI_HELPER_EXECUTOR.post(() -> setToState(!mWorkEnabled));
+            UI_HELPER_EXECUTOR.post(() -> setWorkProfileEnabled(getContext(), false));
         }
     }
 
@@ -101,20 +102,18 @@
     public void updateCurrentState(boolean active) {
         mWorkEnabled = active;
         setEnabled(true);
-        setCompoundDrawablesRelativeWithIntrinsicBounds(
-                active ? R.drawable.ic_corp_off : R.drawable.ic_corp, 0, 0, 0);
-        setText(active ? R.string.work_apps_pause_btn_text : R.string.work_apps_enable_btn_text);
+        setVisibility(active ? VISIBLE : GONE);
     }
 
     @RequiresApi(Build.VERSION_CODES.P)
-    protected Boolean setToState(boolean toState) {
-        UserManager userManager = getContext().getSystemService(UserManager.class);
+    public static Boolean setWorkProfileEnabled(Context context, boolean enabled) {
+        UserManager userManager = context.getSystemService(UserManager.class);
         boolean showConfirm = false;
-        for (UserHandle userProfile : UserCache.INSTANCE.get(getContext()).getUserProfiles()) {
+        for (UserHandle userProfile : UserCache.INSTANCE.get(context).getUserProfiles()) {
             if (Process.myUserHandle().equals(userProfile)) {
                 continue;
             }
-            showConfirm |= !userManager.requestQuietModeEnabled(!toState, userProfile);
+            showConfirm |= !userManager.requestQuietModeEnabled(!enabled, userProfile);
         }
         return showConfirm;
     }
diff --git a/src/com/android/launcher3/allapps/WorkPausedCard.java b/src/com/android/launcher3/allapps/WorkPausedCard.java
new file mode 100644
index 0000000..3955a9a
--- /dev/null
+++ b/src/com/android/launcher3/allapps/WorkPausedCard.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 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.allapps;
+
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
+/**
+ * Work profile toggle switch shown at the bottom of AllApps work tab
+ */
+public class WorkPausedCard extends LinearLayout implements View.OnClickListener {
+
+    private final Launcher mLauncher;
+    private Button mBtn;
+
+    public WorkPausedCard(Context context) {
+        this(context, null, 0);
+    }
+
+    public WorkPausedCard(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public WorkPausedCard(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mLauncher = Launcher.getLauncher(getContext());
+    }
+
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mBtn = findViewById(R.id.enable_work_apps);
+        mBtn.setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (Utilities.ATLEAST_P) {
+            setEnabled(false);
+            UI_HELPER_EXECUTOR.post(() -> WorkModeSwitch.setWorkProfileEnabled(getContext(), true));
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int orientation = getResources().getConfiguration().orientation;
+        getLayoutParams().height = orientation == Configuration.ORIENTATION_PORTRAIT
+                ? LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
+        super.onLayout(changed, l, t, r, b);
+    }
+}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 418e46d..345a2ac 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -473,7 +473,13 @@
         LAUNCHER_WIDGET_RESIZE_COMPLETED(824),
 
         @UiEvent(doc = "User reconfigured a widget on their home screen.")
-        LAUNCHER_WIDGET_RECONFIGURED(821)
+        LAUNCHER_WIDGET_RECONFIGURED(821),
+
+        @UiEvent(doc = "User enabled themed icons option in wallpaper & style settings.")
+        LAUNCHER_THEMED_ICON_ENABLED(836),
+
+        @UiEvent(doc = "User disabled themed icons option in wallpaper & style settings.")
+        LAUNCHER_THEMED_ICON_DISABLED(837)
         ;
 
         // ADD MORE
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 3be2c3a..365cab1 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -130,8 +130,9 @@
                             packageName);
 
                     if (!packageInstaller.verifySessionInfo(sessionInfo)) {
-                        FileLog.d(LOG, "Item info failed session info verification: "
-                                + workspaceInfo);
+                        FileLog.d(LOG, "Item info failed session info verification. "
+                                + "Skipping : " + workspaceInfo);
+                        continue;
                     }
 
                     List<LauncherActivityInfo> activities = launcherApps
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 5255490..2bd9ba0 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -217,7 +217,8 @@
     void tryQueuePromiseAppIcon(PackageInstaller.SessionInfo sessionInfo) {
         if (FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()
                 && SessionCommitReceiver.isEnabled(mAppContext)
-                && verifySessionInfo(sessionInfo)) {
+                && verifySessionInfo(sessionInfo)
+                && !promiseIconAddedForId(sessionInfo.getSessionId())) {
             FileLog.d(LOG, "Adding package name to install queue: "
                     + sessionInfo.getAppPackageName());
 
@@ -234,25 +235,28 @@
                 && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
                 && sessionInfo.getAppIcon() != null
                 && !TextUtils.isEmpty(sessionInfo.getAppLabel())
-                && !promiseIconAddedForId(sessionInfo.getSessionId())
                 && !new PackageManagerHelper(mAppContext).isAppInstalled(
                         sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
 
         if (sessionInfo != null) {
             Bitmap appIcon = sessionInfo.getAppIcon();
 
-            FileLog.d(LOG, String.format(
-                    "Verifying session info. Valid: %b, Session verified: %b, Install reason valid:"
-                            + " %b, App icon: %s, App label: %s, Promise icon added: %b, "
-                            + "App installed: %b.",
-                    validSessionInfo,
-                    verify(sessionInfo) != null,
-                    sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER,
-                    appIcon == null ? "null" : IOUtils.toBase64String(appIcon),
-                    sessionInfo.getAppLabel(),
-                    promiseIconAddedForId(sessionInfo.getSessionId()),
-                    new PackageManagerHelper(mAppContext).isAppInstalled(
-                            sessionInfo.getAppPackageName(), getUserHandle(sessionInfo))));
+            if (Utilities.IS_DEBUG_DEVICE) {
+                FileLog.d(LOG, String.format(
+                        "Verifying session info. Valid: %b,"
+                                + " Session verified: %b,"
+                                + " Install reason valid: %b,"
+                                + " App icon: %s,"
+                                + " App label: %s,"
+                                + " App installed: %b.",
+                        validSessionInfo,
+                        verify(sessionInfo) != null,
+                        sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER,
+                        appIcon == null ? "null" : IOUtils.toBase64String(appIcon),
+                        sessionInfo.getAppLabel(),
+                        new PackageManagerHelper(mAppContext).isAppInstalled(
+                                sessionInfo.getAppPackageName(), getUserHandle(sessionInfo))));
+            }
         } else {
             FileLog.d(LOG, "Verifying session info failed: session info null.");
         }
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 332390d..2ae12ac 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -96,6 +96,8 @@
     private int mNumNotifications;
     private ViewGroup mNotificationContainer;
 
+    private ViewGroup mWidgetContainer;
+
     private ViewGroup mDeepShortcutContainer;
 
     private ViewGroup mSystemShortcutContainer;
@@ -234,7 +236,7 @@
 
     @Override
     protected List<View> getChildrenForColorExtraction() {
-        return Arrays.asList(mSystemShortcutContainer, mDeepShortcutContainer,
+        return Arrays.asList(mSystemShortcutContainer, mWidgetContainer, mDeepShortcutContainer,
                 mNotificationContainer);
     }
 
@@ -298,10 +300,24 @@
             updateHiddenShortcuts();
 
             if (!systemShortcuts.isEmpty()) {
-                mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);
                 for (SystemShortcut shortcut : systemShortcuts) {
-                    initializeSystemShortcut(
-                            R.layout.system_shortcut_icon_only, mSystemShortcutContainer, shortcut);
+                    if (shortcut instanceof SystemShortcut.Widgets) {
+                        if (mWidgetContainer == null) {
+                            mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container,
+                                    this);
+                        }
+                        initializeSystemShortcut(R.layout.system_shortcut, mWidgetContainer,
+                                shortcut);
+                    }
+                }
+                mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);
+
+                for (SystemShortcut shortcut : systemShortcuts) {
+                    if (!(shortcut instanceof SystemShortcut.Widgets)) {
+                        initializeSystemShortcut(
+                                R.layout.system_shortcut_icon_only, mSystemShortcutContainer,
+                                shortcut);
+                    }
                 }
             }
         } else {
@@ -524,25 +540,34 @@
             mLauncher.getPopupDataProvider().setChangeListener(null);
         }
 
+        private View getWidgetsView(ViewGroup container) {
+            for (int i = container.getChildCount() - 1; i >= 0; --i) {
+                View systemShortcutView = container.getChildAt(i);
+                if (systemShortcutView.getTag() instanceof SystemShortcut.Widgets) {
+                    return systemShortcutView;
+                }
+            }
+            return null;
+        }
+
         @Override
         public void onWidgetsBound() {
             ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag();
             SystemShortcut widgetInfo = SystemShortcut.WIDGETS.getShortcut(mLauncher, itemInfo);
-            View widgetsView = null;
-            int count = mSystemShortcutContainer.getChildCount();
-            for (int i = 0; i < count; i++) {
-                View systemShortcutView = mSystemShortcutContainer.getChildAt(i);
-                if (systemShortcutView.getTag() instanceof SystemShortcut.Widgets) {
-                    widgetsView = systemShortcutView;
-                    break;
-                }
+            View widgetsView = getWidgetsView(PopupContainerWithArrow.this);
+            if (widgetsView == null && mWidgetContainer != null) {
+                widgetsView = getWidgetsView(mWidgetContainer);
             }
 
             if (widgetInfo != null && widgetsView == null) {
                 // We didn't have any widgets cached but now there are some, so enable the shortcut.
                 if (mSystemShortcutContainer != PopupContainerWithArrow.this) {
-                    initializeSystemShortcut(R.layout.system_shortcut_icon_only,
-                            mSystemShortcutContainer, widgetInfo);
+                    if (mWidgetContainer == null) {
+                        mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container,
+                                PopupContainerWithArrow.this);
+                    }
+                    initializeSystemShortcut(R.layout.system_shortcut, mWidgetContainer,
+                            widgetInfo);
                 } else {
                     // If using the expanded system shortcut (as opposed to just the icon), we need
                     // to reopen the container to ensure measurements etc. all work out. While this
@@ -554,8 +579,10 @@
                 }
             } else if (widgetInfo == null && widgetsView != null) {
                 // No widgets exist, but we previously added the shortcut so remove it.
-                if (mSystemShortcutContainer != PopupContainerWithArrow.this) {
-                    mSystemShortcutContainer.removeView(widgetsView);
+                if (mSystemShortcutContainer
+                        != PopupContainerWithArrow.this
+                        && mWidgetContainer != null) {
+                    mWidgetContainer.removeView(widgetsView);
                 } else {
                     close(false);
                     PopupContainerWithArrow.showForIcon(mOriginalIcon);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index e89aea7..6863c60 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -103,18 +103,25 @@
             OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) {
         mLauncher = Launcher.getLauncher(context);
         mDiffReporter = new WidgetsDiffReporter(iconCache, this);
+        WidgetsListDrawableFactory listDrawableFactory = new WidgetsListDrawableFactory(context);
         mWidgetsListTableViewHolderBinder = new WidgetsListTableViewHolderBinder(context,
                 layoutInflater, iconClickListener, iconLongClickListener,
-                widgetPreviewLoader, /* listAdapter= */ this);
+                widgetPreviewLoader, listDrawableFactory, /* listAdapter= */ this);
         mViewHolderBinders.put(VIEW_TYPE_WIDGETS_LIST, mWidgetsListTableViewHolderBinder);
         mViewHolderBinders.put(
                 VIEW_TYPE_WIDGETS_HEADER,
                 new WidgetsListHeaderViewHolderBinder(
-                        layoutInflater, /* onHeaderClickListener= */this, /* listAdapter= */ this));
+                        layoutInflater,
+                        /* onHeaderClickListener= */ this,
+                        listDrawableFactory,
+                        /* listAdapter= */ this));
         mViewHolderBinders.put(
                 VIEW_TYPE_WIDGETS_SEARCH_HEADER,
                 new WidgetsListSearchHeaderViewHolderBinder(
-                        layoutInflater, /*onHeaderClickListener=*/ this, /* listAdapter= */ this));
+                        layoutInflater,
+                        /* onHeaderClickListener= */ this,
+                        listDrawableFactory,
+                        /* listAdapter= */ this));
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListDrawableFactory.java b/src/com/android/launcher3/widget/picker/WidgetsListDrawableFactory.java
new file mode 100644
index 0000000..c61e3a4
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetsListDrawableFactory.java
@@ -0,0 +1,113 @@
+/*
+ * 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.launcher3.widget.picker;
+
+import static com.android.launcher3.widget.picker.WidgetsListDrawableState.FIRST;
+import static com.android.launcher3.widget.picker.WidgetsListDrawableState.FIRST_EXPANDED;
+import static com.android.launcher3.widget.picker.WidgetsListDrawableState.LAST;
+import static com.android.launcher3.widget.picker.WidgetsListDrawableState.MIDDLE;
+import static com.android.launcher3.widget.picker.WidgetsListDrawableState.MIDDLE_EXPANDED;
+import static com.android.launcher3.widget.picker.WidgetsListDrawableState.SINGLE;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.RippleDrawable;
+import android.graphics.drawable.StateListDrawable;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
+
+/** Factory for creating drawables to use as background for list elements. */
+final class WidgetsListDrawableFactory {
+
+    private final float mTopBottomCornerRadius;
+    private final float mMiddleCornerRadius;
+    private final ColorStateList mSurfaceColor;
+    private final ColorStateList mRippleColor;
+
+    WidgetsListDrawableFactory(Context context) {
+        Resources res = context.getResources();
+        mTopBottomCornerRadius = res.getDimension(R.dimen.widget_list_top_bottom_corner_radius);
+        mMiddleCornerRadius = res.getDimension(R.dimen.widget_list_content_corner_radius);
+        mSurfaceColor = context.getColorStateList(R.color.surface);
+        mRippleColor = ColorStateList.valueOf(
+                Themes.getAttrColor(context, android.R.attr.colorControlHighlight));
+    }
+
+    /**
+     * Creates a drawable for widget header list items. This drawable supports all positions
+     * in {@link WidgetsListDrawableState}.
+     */
+    Drawable createHeaderBackgroundDrawable() {
+        StateListDrawable stateList = new StateListDrawable();
+        stateList.addState(
+                SINGLE.mStateSet,
+                createRoundedRectDrawable(mTopBottomCornerRadius, mTopBottomCornerRadius));
+        stateList.addState(
+                FIRST_EXPANDED.mStateSet,
+                createRoundedRectDrawable(mTopBottomCornerRadius, 0));
+        stateList.addState(
+                FIRST.mStateSet,
+                createRoundedRectDrawable(mTopBottomCornerRadius, mMiddleCornerRadius));
+        stateList.addState(
+                MIDDLE_EXPANDED.mStateSet,
+                createRoundedRectDrawable(mMiddleCornerRadius, 0));
+        stateList.addState(
+                MIDDLE.mStateSet,
+                createRoundedRectDrawable(mMiddleCornerRadius, mMiddleCornerRadius));
+        stateList.addState(
+                LAST.mStateSet,
+                createRoundedRectDrawable(mMiddleCornerRadius, mTopBottomCornerRadius));
+        return new RippleDrawable(mRippleColor, /* content= */ stateList, /* mask= */ stateList);
+    }
+
+    /**
+     * Creates a drawable for widget content list items. This state list supports the middle and
+     * last states.
+     */
+    Drawable createContentBackgroundDrawable() {
+        StateListDrawable stateList = new StateListDrawable();
+        stateList.addState(
+                MIDDLE.mStateSet,
+                createRoundedRectDrawable(0, mMiddleCornerRadius));
+        stateList.addState(
+                LAST.mStateSet,
+                createRoundedRectDrawable(0, mTopBottomCornerRadius));
+        return new RippleDrawable(mRippleColor, /* content= */ stateList, /* mask= */ stateList);
+    }
+
+    /** Creates a rounded-rect drawable with the specified radii. */
+    private Drawable createRoundedRectDrawable(float topRadius, float bottomRadius) {
+        GradientDrawable backgroundMask = new GradientDrawable();
+        backgroundMask.setColor(mSurfaceColor);
+        backgroundMask.setShape(GradientDrawable.RECTANGLE);
+        backgroundMask.setCornerRadii(
+                new float[]{
+                        topRadius,
+                        topRadius,
+                        topRadius,
+                        topRadius,
+                        bottomRadius,
+                        bottomRadius,
+                        bottomRadius,
+                        bottomRadius
+                });
+        return backgroundMask;
+    }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListDrawableState.java b/src/com/android/launcher3/widget/picker/WidgetsListDrawableState.java
new file mode 100644
index 0000000..94f292b
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetsListDrawableState.java
@@ -0,0 +1,44 @@
+/*
+ * 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.launcher3.widget.picker;
+
+/**
+ * Different possible list position states for an item in the widgets list to have. Note that only
+ * headers use the expanded state.
+ */
+enum WidgetsListDrawableState {
+    FIRST(new int[]{android.R.attr.state_first}),
+    FIRST_EXPANDED(new int[]{android.R.attr.state_first, android.R.attr.state_expanded}),
+    MIDDLE(new int[]{android.R.attr.state_middle}),
+    MIDDLE_EXPANDED(new int[]{android.R.attr.state_middle, android.R.attr.state_expanded}),
+    LAST(new int[]{android.R.attr.state_last}),
+    SINGLE(new int[]{android.R.attr.state_single});
+
+    final int[] mStateSet;
+
+    WidgetsListDrawableState(int[] stateSet) {
+        mStateSet = stateSet;
+    }
+
+    static WidgetsListDrawableState obtain(boolean isFirst, boolean isLast, boolean isExpanded) {
+        if (isFirst && isLast) return SINGLE;
+        if (isFirst && isExpanded) return FIRST_EXPANDED;
+        if (isFirst) return FIRST;
+        if (isLast) return LAST;
+        if (isExpanded) return MIDDLE_EXPANDED;
+        return MIDDLE;
+    }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListDrawables.java b/src/com/android/launcher3/widget/picker/WidgetsListDrawables.java
deleted file mode 100644
index b3bb544..0000000
--- a/src/com/android/launcher3/widget/picker/WidgetsListDrawables.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.launcher3.widget.picker;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.RippleDrawable;
-
-import com.android.launcher3.R;
-import com.android.launcher3.util.Themes;
-
-/** Helper class for creating drawables to use as background for list elements. */
-final class WidgetsListDrawables {
-
-    private WidgetsListDrawables() {}
-
-    /** Creates a list background drawable with the specified radii. */
-    static Drawable createListBackgroundDrawable(
-            Context context,
-            float topRadius,
-            float bottomRadius) {
-        GradientDrawable backgroundMask = new GradientDrawable();
-        backgroundMask.setColor(context.getColorStateList(R.color.surface));
-        backgroundMask.setShape(GradientDrawable.RECTANGLE);
-
-        backgroundMask.setCornerRadii(
-                new float[]{
-                        topRadius,
-                        topRadius,
-                        topRadius,
-                        topRadius,
-                        bottomRadius,
-                        bottomRadius,
-                        bottomRadius,
-                        bottomRadius
-                });
-
-        return new RippleDrawable(
-                /* color= */ ColorStateList.valueOf(
-                        Themes.getAttrColor(context, android.R.attr.colorControlHighlight)),
-                /* content= */ backgroundMask,
-                /* mask= */ backgroundMask);
-    }
-
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index fece359..cdab964 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -60,9 +60,6 @@
     @Nullable private Drawable mIconDrawable;
     private final int mIconSize;
     private final int mBottomMarginSize;
-    private final float mTopBottomCornerRadius;
-    private final float mMiddleCornerRadius;
-    private final float mJoinedCornerRadius;
 
     private ImageView mAppIcon;
     private TextView mTitle;
@@ -70,6 +67,7 @@
 
     private CheckBox mExpandToggle;
     private boolean mIsExpanded = false;
+    @Nullable private WidgetsListDrawableState mListDrawableState;
 
     public WidgetsListHeader(Context context) {
         this(context, /* attrs= */ null);
@@ -90,12 +88,6 @@
                 grid.iconSizePx);
         mBottomMarginSize =
                 getResources().getDimensionPixelSize(R.dimen.widget_list_entry_bottom_margin);
-        mTopBottomCornerRadius =
-                getResources().getDimension(R.dimen.widget_list_top_bottom_corner_radius);
-        mMiddleCornerRadius =
-                getResources().getDimension(R.dimen.widget_list_content_corner_radius);
-        mJoinedCornerRadius =
-                getResources().getDimension(R.dimen.widget_list_content_joined_corner_radius);
     }
 
     @Override
@@ -163,6 +155,14 @@
         }
     }
 
+    /** Sets the {@link WidgetsListDrawableState} and refreshes the background drawable. */
+    @UiThread
+    public void setListDrawableState(WidgetsListDrawableState state) {
+        if (state == mListDrawableState) return;
+        this.mListDrawableState = state;
+        refreshDrawableState();
+    }
+
     /** Apply app icon, labels and tag using a generic {@link WidgetsListHeaderEntry}. */
     @UiThread
     public void applyFromItemInfoWithIcon(WidgetsListHeaderEntry entry) {
@@ -263,20 +263,6 @@
         verifyHighRes();
     }
 
-    /** Updates the list to have a background drawable with the appropriate corner radii. */
-    @UiThread
-    public void updateListBackground(boolean isFirst, boolean isLast, boolean isExpanded) {
-        float topRadius = isFirst ? mTopBottomCornerRadius : mMiddleCornerRadius;
-        float bottomRadius = isLast
-                ? mTopBottomCornerRadius
-                : isExpanded
-                        ? mJoinedCornerRadius
-                        : mMiddleCornerRadius;
-        setBackground(
-                WidgetsListDrawables.createListBackgroundDrawable(
-                        getContext(), topRadius, bottomRadius));
-    }
-
     private void setTitles(WidgetsListSearchHeaderEntry entry) {
         mTitle.setText(entry.mPkgItem.title);
 
@@ -300,6 +286,17 @@
         }
     }
 
+    @Override
+    protected int[] onCreateDrawableState(int extraSpace) {
+        if (mListDrawableState == null) return super.onCreateDrawableState(extraSpace);
+        // Augment the state set from the super implementation with the custom states from
+        // mListDrawableState.
+        int[] drawableState =
+                super.onCreateDrawableState(extraSpace + mListDrawableState.mStateSet.length);
+        mergeDrawableStates(drawableState, mListDrawableState.mStateSet);
+        return drawableState;
+    }
+
     /** Verifies that the current icon is high-res otherwise posts a request to load the icon. */
     public void verifyHighRes() {
         if (mIconLoadRequest != null) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
index 22d6d22..2f8f1ba 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
@@ -30,13 +30,16 @@
         ViewHolderBinder<WidgetsListHeaderEntry, WidgetsListHeaderHolder> {
     private final LayoutInflater mLayoutInflater;
     private final OnHeaderClickListener mOnHeaderClickListener;
+    private final WidgetsListDrawableFactory mListDrawableFactory;
     private final WidgetsListAdapter mWidgetsListAdapter;
 
     public WidgetsListHeaderViewHolderBinder(LayoutInflater layoutInflater,
             OnHeaderClickListener onHeaderClickListener,
+            WidgetsListDrawableFactory listDrawableFactory,
             WidgetsListAdapter listAdapter) {
         mLayoutInflater = layoutInflater;
         mOnHeaderClickListener = onHeaderClickListener;
+        mListDrawableFactory = listDrawableFactory;
         mWidgetsListAdapter = listAdapter;
     }
 
@@ -44,7 +47,7 @@
     public WidgetsListHeaderHolder newViewHolder(ViewGroup parent) {
         WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
                 R.layout.widgets_list_row_header, parent, false);
-
+        header.setBackground(mListDrawableFactory.createHeaderBackgroundDrawable());
         return new WidgetsListHeaderHolder(header);
     }
 
@@ -52,12 +55,13 @@
     public void bindViewHolder(WidgetsListHeaderHolder viewHolder, WidgetsListHeaderEntry data,
             int position) {
         WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
-        widgetsListHeader.updateListBackground(
-                /* isFirst= */ position == 0,
-                /* isLast= */ position == mWidgetsListAdapter.getItemCount() - 1,
-                /* isExpanded= */ data.isWidgetListShown());
         widgetsListHeader.applyFromItemInfoWithIcon(data);
         widgetsListHeader.setExpanded(data.isWidgetListShown());
+        widgetsListHeader.setListDrawableState(
+                WidgetsListDrawableState.obtain(
+                        /* isFirst= */ position == 0,
+                        /* isLast= */ position == mWidgetsListAdapter.getItemCount() - 1,
+                        /* isExpanded= */ data.isWidgetListShown()));
         widgetsListHeader.setOnExpandChangeListener(isExpanded ->
                 mOnHeaderClickListener.onHeaderClicked(
                         isExpanded,
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
index d5e03a4..31dd9ee 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
@@ -31,13 +31,16 @@
         ViewHolderBinder<WidgetsListSearchHeaderEntry, WidgetsListSearchHeaderHolder> {
     private final LayoutInflater mLayoutInflater;
     private final OnHeaderClickListener mOnHeaderClickListener;
+    private final WidgetsListDrawableFactory mListDrawableFactory;
     private final WidgetsListAdapter mWidgetsListAdapter;
 
     public WidgetsListSearchHeaderViewHolderBinder(LayoutInflater layoutInflater,
             OnHeaderClickListener onHeaderClickListener,
+            WidgetsListDrawableFactory listDrawableFactory,
             WidgetsListAdapter listAdapter) {
         mLayoutInflater = layoutInflater;
         mOnHeaderClickListener = onHeaderClickListener;
+        mListDrawableFactory = listDrawableFactory;
         mWidgetsListAdapter = listAdapter;
     }
 
@@ -45,7 +48,7 @@
     public WidgetsListSearchHeaderHolder newViewHolder(ViewGroup parent) {
         WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
                 R.layout.widgets_list_row_header, parent, false);
-
+        header.setBackground(mListDrawableFactory.createHeaderBackgroundDrawable());
         return new WidgetsListSearchHeaderHolder(header);
     }
 
@@ -53,12 +56,13 @@
     public void bindViewHolder(WidgetsListSearchHeaderHolder viewHolder,
             WidgetsListSearchHeaderEntry data, int position) {
         WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
-        widgetsListHeader.updateListBackground(
-                /* isFirst= */ position == 0,
-                /* isLast= */ position == mWidgetsListAdapter.getItemCount() - 1,
-                /* isExpanded= */ data.isWidgetListShown());
         widgetsListHeader.applyFromItemInfoWithIcon(data);
         widgetsListHeader.setExpanded(data.isWidgetListShown());
+        widgetsListHeader.setListDrawableState(
+                WidgetsListDrawableState.obtain(
+                        /* isFirst= */ position == 0,
+                        /* isLast= */ position == mWidgetsListAdapter.getItemCount() - 1,
+                        /* isExpanded= */ data.isWidgetListShown()));
         widgetsListHeader.setOnExpandChangeListener(isExpanded ->
                 mOnHeaderClickListener.onHeaderClicked(isExpanded,
                         new PackageUserKey(data.mPkgItem.packageName, data.mPkgItem.user)));
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableView.java b/src/com/android/launcher3/widget/picker/WidgetsListTableView.java
new file mode 100644
index 0000000..d30e7b6
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableView.java
@@ -0,0 +1,59 @@
+/*
+ * 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.launcher3.widget.picker;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.TableLayout;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+
+/**
+ * Extension of {@link TableLayout} to support the drawable states used by
+ * {@link WidgetsListDrawableState}.
+ */
+public class WidgetsListTableView extends TableLayout {
+
+    @Nullable private WidgetsListDrawableState mListDrawableState;
+
+    public WidgetsListTableView(Context context) {
+        super(context);
+    }
+
+    public WidgetsListTableView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    /** Sets the {@link WidgetsListDrawableState} and refreshes the background drawable. */
+    @UiThread
+    public void setListDrawableState(WidgetsListDrawableState state) {
+        if (state == mListDrawableState) return;
+        mListDrawableState = state;
+        refreshDrawableState();
+    }
+
+    @Override
+    protected int[] onCreateDrawableState(int extraSpace) {
+        if (mListDrawableState == null) return super.onCreateDrawableState(extraSpace);
+        // Augment the state set from the super implementation with the custom states from
+        // mListDrawableState.
+        int[] drawableState =
+                super.onCreateDrawableState(extraSpace + mListDrawableState.mStateSet.length);
+        mergeDrawableStates(drawableState, mListDrawableState.mStateSet);
+        return drawableState;
+    }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index 8e310c5..7e8c55b 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -15,8 +15,10 @@
  */
 package com.android.launcher3.widget.picker;
 
+import static com.android.launcher3.widget.picker.WidgetsListDrawableState.LAST;
+import static com.android.launcher3.widget.picker.WidgetsListDrawableState.MIDDLE;
+
 import android.content.Context;
-import android.content.res.Resources;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -51,10 +53,8 @@
     private final OnClickListener mIconClickListener;
     private final OnLongClickListener mIconLongClickListener;
     private final WidgetPreviewLoader mWidgetPreviewLoader;
+    private final WidgetsListDrawableFactory mListDrawableFactory;
     private final WidgetsListAdapter mWidgetsListAdapter;
-    private final float mTopBottomCornerRadius;
-    private final float mMiddleCornerRadius;
-    private final float mJoinedCornerRadius;
     private boolean mApplyBitmapDeferred = false;
 
     public WidgetsListTableViewHolderBinder(
@@ -63,19 +63,14 @@
             OnClickListener iconClickListener,
             OnLongClickListener iconLongClickListener,
             WidgetPreviewLoader widgetPreviewLoader,
+            WidgetsListDrawableFactory listDrawableFactory,
             WidgetsListAdapter listAdapter) {
         mLayoutInflater = layoutInflater;
         mIconClickListener = iconClickListener;
         mIconLongClickListener = iconLongClickListener;
         mWidgetPreviewLoader = widgetPreviewLoader;
+        mListDrawableFactory = listDrawableFactory;
         mWidgetsListAdapter = listAdapter;
-        Resources resources = context.getResources();
-        mTopBottomCornerRadius =
-                resources.getDimension(R.dimen.widget_list_top_bottom_corner_radius);
-        mMiddleCornerRadius =
-                resources.getDimension(R.dimen.widget_list_content_corner_radius);
-        mJoinedCornerRadius =
-                resources.getDimension(R.dimen.widget_list_content_joined_corner_radius);
     }
 
     /**
@@ -97,28 +92,25 @@
             Log.v(TAG, "\nonCreateViewHolder");
         }
 
-        ViewGroup container = (ViewGroup) mLayoutInflater.inflate(
-                R.layout.widgets_table_container, parent, false);
-        return new WidgetsRowViewHolder(container);
+        WidgetsRowViewHolder viewHolder =
+                new WidgetsRowViewHolder(mLayoutInflater.inflate(
+                        R.layout.widgets_table_container, parent, false));
+        viewHolder.mTableContainer.setBackgroundDrawable(
+                mListDrawableFactory.createContentBackgroundDrawable());
+        return viewHolder;
     }
 
     @Override
     public void bindViewHolder(WidgetsRowViewHolder holder, WidgetsListContentEntry entry,
             int position) {
-        TableLayout table = holder.mTableContainer;
+        WidgetsListTableView table = holder.mTableContainer;
         if (DEBUG) {
             Log.d(TAG, String.format("onBindViewHolder [widget#=%d, table.getChildCount=%d]",
                     entry.mWidgets.size(), table.getChildCount()));
         }
 
-        // The content is always joined to an expanded header above.
-        float topRadius = mJoinedCornerRadius;
-        float bottomRadius = position == mWidgetsListAdapter.getItemCount() - 1
-                ? mTopBottomCornerRadius
-                : mMiddleCornerRadius;
-        table.setBackgroundDrawable(
-                WidgetsListDrawables.createListBackgroundDrawable(
-                        holder.itemView.getContext(), topRadius, bottomRadius));
+        table.setListDrawableState(
+                position == mWidgetsListAdapter.getItemCount() - 1 ? LAST : MIDDLE);
 
         List<ArrayList<WidgetItem>> widgetItemsTable =
                 WidgetsTableUtils.groupWidgetItemsIntoTable(entry.mWidgets, mMaxSpansPerRow);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java
index aef1103..618e2cb 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java
@@ -15,8 +15,7 @@
  */
 package com.android.launcher3.widget.picker;
 
-import android.view.ViewGroup;
-import android.widget.TableLayout;
+import android.view.View;
 
 import androidx.recyclerview.widget.RecyclerView.ViewHolder;
 
@@ -25,9 +24,9 @@
 /** A {@link ViewHolder} for showing widgets of an app in the full widget picker. */
 public final class WidgetsRowViewHolder extends ViewHolder {
 
-    public final TableLayout mTableContainer;
+    public final WidgetsListTableView mTableContainer;
 
-    public WidgetsRowViewHolder(ViewGroup v) {
+    public WidgetsRowViewHolder(View v) {
         super(v);
 
         mTableContainer = v.findViewById(R.id.widgets_table);
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 6f47df0..06bc26a 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -293,7 +293,7 @@
         try {
             final AppIconMenu menu = allApps.
                     getAppIcon(APP_NAME).
-                    openMenu();
+                    openDeepShortcutMenu();
 
             executeOnLauncher(
                     launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
@@ -341,7 +341,7 @@
         try {
             final AppIconMenu menu = allApps
                     .getAppIcon(APP_NAME)
-                    .openMenu();
+                    .openDeepShortcutMenu();
             final AppIconMenuItem menuItem0 = menu.getMenuItem(0);
             final AppIconMenuItem menuItem2 = menu.getMenuItem(2);
 
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 56723b1..57fd08a 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -51,6 +51,16 @@
         }
     }
 
+    /**
+     * Long-clicks the icon to open its menu, and looks at the deep shortcuts container only.
+     */
+    public AppIconMenu openDeepShortcutMenu() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            return new AppIconMenu(mLauncher, mLauncher.clickAndGet(
+                    mObject, "deep_shortcuts_container", LONG_CLICK_EVENT));
+        }
+    }
+
     @Override
     protected void addExpectedEventsForLongClick() {
         mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT);