Merge "Fix wrong widget appearing in widget picker for tablet" into tm-qpr-dev
diff --git a/OWNERS b/OWNERS
index 560b562..962d63a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,31 +4,36 @@
 # People who can approve changes for submission
 #
 
-alexchau@google.com
-andraskloczl@google.com
-patmanning@google.com
 adamcohen@google.com
-hyunyoungs@google.com
-mrcasey@google.com
-sunnygoyal@google.com
+alexchau@google.com
+andonian@google.com
 awickham@google.com
-twickham@google.com
-winsonc@google.com
-zakcohen@google.com
-santie@google.com
-vadimt@google.com
-jonmiranda@google.com
-pinyaoting@google.com
-gwasserman@google.com
-jamesoleary@google.com
-joshtrask@google.com
-mrenouf@google.com
-mkephart@google.com
-hwwang@google.com
-tracyzhou@google.com
-peanutbutter@google.com
-xuqiu@google.com
+brdayauon@google.com
 brianji@google.com
+captaincole@google.com
+charlander@google.com
+fbaron@google.com
+ganjam@google.com
+hwwang@google.com
+hyunyoungs@google.com
+jagrutdesai@google.com
+jeremysim@google.com
+jiuyu@google.com
+jonmiranda@google.com
+kylim@google.com
+patmanning@google.com
+peanutbutter@google.com
+pinyaoting@google.com
+randypfohl@google.com
+saumyaprakash@google.com
+sihua@google.com
+sunnygoyal@google.com
+tracyzhou@google.com
+twickham@google.com
+vadimt@google.com
+victortulias@google.com
+winsonc@google.com
+xuqiu@google.com
 
 per-file FeatureFlags.java, globs = set noparent
-per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, zakcohen@google.com, mrcasey@google.com, adamcohen@google.com, hyunyoungs@google.com
+per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, adamcohen@google.com, hyunyoungs@google.com
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index bd11c1e..1642fd4 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -17,11 +17,14 @@
      file, they need to be loaded at runtime. -->
 <com.android.quickstep.views.TaskView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
     android:defaultFocusHighlightEnabled="false"
-    android:focusable="true">
+    android:focusable="true"
+    launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
 
     <com.android.quickstep.views.TaskThumbnailView
         android:id="@+id/snapshot"
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index ec03c69..a8d5b50 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -22,11 +22,14 @@
 
 <com.android.quickstep.views.GroupedTaskView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
     android:defaultFocusHighlightEnabled="false"
-    android:focusable="true">
+    android:focusable="true"
+    launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
 
     <com.android.quickstep.views.TaskThumbnailView
         android:id="@+id/snapshot"
diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml
index 336fb57..f1d4dab 100644
--- a/quickstep/res/values/attrs.xml
+++ b/quickstep/res/values/attrs.xml
@@ -19,4 +19,13 @@
         <attr name="android:textSize"/>
         <attr name="android:fontFamily"/>
     </declare-styleable>
+
+    <!--
+         TaskView specific attributes. These attributes are used to customize a TaskView view in
+         XML files.
+     -->
+    <declare-styleable name="TaskView">
+        <!-- Border color for a keyboard quick switch task views -->
+        <attr name="borderColor" format="color" />
+    </declare-styleable>
 </resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 3846a9c..fb04cc0 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -328,4 +328,7 @@
     <!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
     <!--     starting_surface_exit_animation_window_shift_length -->
     <dimen name="starting_surface_exit_animation_window_shift_length">20dp</dimen>
+
+    <!-- Keyboard Quick Switch -->
+    <dimen name="keyboard_quick_switch_border_width">4dp</dimen>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 335482c..0b6e5d3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.TaskTransitionSpec;
+import android.view.View;
 import android.view.WindowManagerGlobal;
 
 import androidx.annotation.NonNull;
@@ -49,6 +50,7 @@
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.OnboardingPrefs;
 import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.views.RecentsView;
 
 import java.io.PrintWriter;
@@ -380,6 +382,17 @@
     }
 
     @Override
+    public RecentsView getRecentsView() {
+        return mLauncher.getOverviewPanel();
+    }
+
+    @Override
+    public void launchSplitTasks(View taskView, GroupTask groupTask) {
+        super.launchSplitTasks(taskView, groupTask);
+        mLauncher.launchSplitTasks(taskView, groupTask);
+    }
+
+    @Override
     public void dumpLogs(String prefix, PrintWriter pw) {
         super.dumpLogs(prefix, pw);
 
@@ -399,9 +412,4 @@
 
         mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw);
     }
-
-    @Override
-    public RecentsView getRecentsView() {
-        return mLauncher.getOverviewPanel();
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 74e7375..0f25ba1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -36,6 +38,7 @@
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
+import com.android.systemui.shared.system.QuickStepContract;
 
 import java.io.PrintWriter;
 
@@ -78,6 +81,10 @@
     private float mStartProgressForNextRevealAnim;
     private boolean mWasLastRevealAnimReversed;
 
+    // States that affect whether region sampling is enabled or not
+    private boolean mIsStashed;
+    private boolean mTaskbarHidden;
+
     public StashedHandleViewController(TaskbarActivityContext activity,
             StashedHandleView stashedHandleView) {
         mActivity = activity;
@@ -218,7 +225,8 @@
 
     /** Called when taskbar is stashed or unstashed. */
     public void onIsStashedChanged(boolean isStashed) {
-        mRegionSamplingHelper.setWindowVisible(isStashed);
+        mIsStashed = isStashed;
+        updateRegionSamplingWindowVisibility();
         if (isStashed) {
             mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
             mRegionSamplingHelper.start(mStashedHandleView.getSampledRegion());
@@ -247,6 +255,15 @@
                 homeDisabled ? 0 : 1);
     }
 
+    public void updateStateForSysuiFlags(int systemUiStateFlags) {
+        mTaskbarHidden = (systemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
+        updateRegionSamplingWindowVisibility();
+    }
+
+    private void updateRegionSamplingWindowVisibility() {
+        mRegionSamplingHelper.setWindowVisible(mIsStashed && !mTaskbarHidden);
+    }
+
     public boolean isStashedHandleVisible() {
         return mStashedHandleView.getVisibility() == View.VISIBLE;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index c6d8fce..c0c14a3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -247,6 +247,12 @@
         // Initialize controllers after all are constructed.
         mControllers.init(sharedState);
         updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
+        disableNavBarElements(sharedState.disableNavBarDisplayId, sharedState.disableNavBarState1,
+                sharedState.disableNavBarState2, false /* animate */);
+        onSystemBarAttributesChanged(sharedState.systemBarAttrsDisplayId,
+                sharedState.systemBarAttrsBehavior);
+        onNavButtonsDarkIntensityChanged(sharedState.navButtonsDarkIntensity);
+
 
         if (!mAddedWindow) {
             mWindowManager.addView(mDragLayer, mWindowLayoutParams);
@@ -564,6 +570,7 @@
                         || isNavBarKidsModeActive());
         mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
                 mControllers.navbarButtonsViewController.isHomeDisabled());
+        mControllers.stashedHandleViewController.updateStateForSysuiFlags(systemUiStateFlags);
         mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
         mControllers.taskbarStashController.updateStateForSysuiFlags(
                 systemUiStateFlags, fromInit || !isUserSetupComplete());
@@ -1061,6 +1068,12 @@
         mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
     }
 
+    void notifyUpdateLayoutParams() {
+        if (mDragLayer.isAttachedToWindow()) {
+            mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
+        }
+    }
+
     public void showPopupMenuForIcon(BubbleTextView btv) {
         setTaskbarWindowFullscreen(true);
         btv.post(() -> mControllers.taskbarPopupController.showForIcon(btv));
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 9f24565..571d443 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -18,16 +18,21 @@
 import android.graphics.Insets
 import android.graphics.Region
 import android.view.InsetsFrameProvider
+import android.view.InsetsFrameProvider.SOURCE_DISPLAY
+import android.view.InsetsFrameProvider.SOURCE_FRAME
 import android.view.InsetsState
 import android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES
 import android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT
 import android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR
+import android.view.InsetsState.ITYPE_LEFT_GESTURES
+import android.view.InsetsState.ITYPE_RIGHT_GESTURES
 import android.view.ViewTreeObserver
 import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME
 import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
 import android.view.WindowManager
 import android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD
 import android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION
+import com.android.internal.policy.GestureNavigationSettingsObserver
 import com.android.launcher3.AbstractFloatingView
 import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY
 import com.android.launcher3.DeviceProfile
@@ -45,6 +50,9 @@
     private val deviceProfileChangeListener = { _: DeviceProfile ->
         onTaskbarWindowHeightOrInsetsChanged()
     }
+    private val gestureNavSettingsObserver =
+        GestureNavigationSettingsObserver(context.mainThreadHandler, context,
+            this::onTaskbarWindowHeightOrInsetsChanged)
 
     // Initialized in init.
     private lateinit var controllers: TaskbarControllers
@@ -59,7 +67,16 @@
             intArrayOf(
                 ITYPE_EXTRA_NAVIGATION_BAR,
                 ITYPE_BOTTOM_TAPPABLE_ELEMENT,
-                ITYPE_BOTTOM_MANDATORY_GESTURES
+                ITYPE_BOTTOM_MANDATORY_GESTURES,
+                ITYPE_LEFT_GESTURES,
+                ITYPE_RIGHT_GESTURES,
+            ),
+            intArrayOf(
+                SOURCE_FRAME,
+                SOURCE_FRAME,
+                SOURCE_FRAME,
+                SOURCE_DISPLAY,
+                SOURCE_DISPLAY
             )
         )
 
@@ -67,10 +84,12 @@
 
         windowLayoutParams.insetsRoundedCornerFrame = true
         context.addOnDeviceProfileChangeListener(deviceProfileChangeListener)
+        gestureNavSettingsObserver.registerForCurrentUser()
     }
 
     fun onDestroy() {
         context.removeOnDeviceProfileChangeListener(deviceProfileChangeListener)
+        gestureNavSettingsObserver.unregister()
     }
 
     fun onTaskbarWindowHeightOrInsetsChanged() {
@@ -91,6 +110,22 @@
                 provider.insetsSize = getInsetsByNavMode(contentHeight)
             } else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
                 provider.insetsSize = getInsetsByNavMode(tappableHeight)
+            } else if (provider.type == ITYPE_LEFT_GESTURES) {
+                provider.insetsSize =
+                    Insets.of(
+                        gestureNavSettingsObserver.getLeftSensitivity(context.resources),
+                        0,
+                        0,
+                        0
+                    )
+            } else if (provider.type == ITYPE_RIGHT_GESTURES) {
+                provider.insetsSize =
+                    Insets.of(
+                        0,
+                        0,
+                        gestureNavSettingsObserver.getRightSensitivity(context.resources),
+                        0
+                    )
             }
         }
 
@@ -116,6 +151,7 @@
                 provider.insetsSizeOverrides = insetsSizeOverride
             }
         }
+        context.notifyUpdateLayoutParams()
     }
 
     /**
@@ -140,10 +176,12 @@
      * @param params The window layout params.
      * @param providesInsetsTypes The inset types we would like this layout params to provide.
      */
-    fun setProvidesInsetsTypes(params: WindowManager.LayoutParams, providesInsetsTypes: IntArray) {
+    fun setProvidesInsetsTypes(params: WindowManager.LayoutParams, providesInsetsTypes: IntArray,
+            providesInsetsSources: IntArray) {
         params.providedInsets = arrayOfNulls<InsetsFrameProvider>(providesInsetsTypes.size)
         for (i in providesInsetsTypes.indices) {
-            params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i])
+            params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i],
+                    providesInsetsSources[i], null, null)
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index a58906f..4110822 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -362,18 +362,24 @@
     }
 
     public void disableNavBarElements(int displayId, int state1, int state2, boolean animate) {
+        mSharedState.disableNavBarDisplayId = displayId;
+        mSharedState.disableNavBarState1 = state1;
+        mSharedState.disableNavBarState2 = state2;
         if (mTaskbarActivityContext != null) {
             mTaskbarActivityContext.disableNavBarElements(displayId, state1, state2, animate);
         }
     }
 
     public void onSystemBarAttributesChanged(int displayId, int behavior) {
+        mSharedState.systemBarAttrsDisplayId = displayId;
+        mSharedState.systemBarAttrsBehavior = behavior;
         if (mTaskbarActivityContext != null) {
             mTaskbarActivityContext.onSystemBarAttributesChanged(displayId, behavior);
         }
     }
 
     public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
+        mSharedState.navButtonsDarkIntensity = darkIntensity;
         if (mTaskbarActivityContext != null) {
             mTaskbarActivityContext.onNavButtonsDarkIntensityChanged(darkIntensity);
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index 87b3789..026eff7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -20,8 +20,21 @@
  */
 public class TaskbarSharedState {
 
+    // TaskbarManager#onSystemUiFlagsChanged
     public int sysuiStateFlags;
 
+    // TaskbarManager#disableNavBarElements()
+    public int disableNavBarDisplayId;
+    public int disableNavBarState1;
+    public int disableNavBarState2;
+
+    // TaskbarManager#onSystemBarAttributesChanged()
+    public int systemBarAttrsDisplayId;
+    public int systemBarAttrsBehavior;
+
+    // TaskbarManager#onNavButtonsDarkIntensityChanged()
+    public float navButtonsDarkIntensity;
+
     public boolean setupUIVisible = false;
 
     public boolean allAppsVisible = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index bfdf156..a388388 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -29,6 +29,7 @@
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.SplitConfigurationOptions;
+import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
@@ -228,4 +229,11 @@
                 }
         );
     }
+
+    /**
+     * Launches the focused task in splitscreen.
+     *
+     * No-op if the view is not yet open.
+     */
+    public void launchSplitTasks(View taskview, GroupTask groupTask) { }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index d91b650..ec64128 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -27,17 +27,45 @@
 import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
 
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
 /** Root drag layer for the Taskbar overlay window. */
 public class TaskbarOverlayDragLayer extends
         BaseDragLayer<TaskbarOverlayContext> implements
         ViewTreeObserver.OnComputeInternalInsetsListener {
 
+    private final List<OnClickListener> mOnClickListeners = new CopyOnWriteArrayList<>();
+    private final TouchController mClickListenerTouchController = new TouchController() {
+        @Override
+        public boolean onControllerTouchEvent(MotionEvent ev) {
+            if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+                for (OnClickListener listener : mOnClickListeners) {
+                    listener.onClick(TaskbarOverlayDragLayer.this);
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+            for (int i = 0; i < getChildCount(); i++) {
+                if (isEventOverView(getChildAt(i), ev)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    };
+
     TaskbarOverlayDragLayer(Context context) {
         super(context, null, 1);
         setClipChildren(false);
@@ -58,7 +86,10 @@
 
     @Override
     public void recreateControllers() {
-        mControllers = new TouchController[]{mActivity.getDragController()};
+        mControllers = mOnClickListeners.isEmpty()
+                ? new TouchController[]{mActivity.getDragController()}
+                : new TouchController[] {
+                        mActivity.getDragController(), mClickListenerTouchController};
     }
 
     @Override
@@ -99,6 +130,51 @@
     }
 
     /**
+     * Adds the given callback to clicks to this drag layer.
+     * <p>
+     * Clicks are only accepted on this drag layer if they fall within this drag layer's bounds and
+     * outside the bounds of all child views.
+     * <p>
+     * If the click falls within the bounds of a child view, then this callback does not run and
+     * that child can optionally handle it.
+     */
+    private void addOnClickListener(@NonNull OnClickListener listener) {
+        boolean wasEmpty = mOnClickListeners.isEmpty();
+        mOnClickListeners.add(listener);
+        if (wasEmpty) {
+            recreateControllers();
+        }
+    }
+
+    /**
+     * Removes the given on click callback.
+     * <p>
+     * No-op if the callback was never added.
+     */
+    private void removeOnClickListener(@NonNull OnClickListener listener) {
+        boolean wasEmpty = mOnClickListeners.isEmpty();
+        mOnClickListeners.remove(listener);
+        if (!wasEmpty && mOnClickListeners.isEmpty()) {
+            recreateControllers();
+        }
+    }
+
+    /**
+     * Queues the given callback on the next click on this drag layer.
+     * <p>
+     * Once run, this callback is immediately removed.
+     */
+    public void runOnClickOnce(@NonNull OnClickListener listener) {
+        addOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                listener.onClick(v);
+                removeOnClickListener(this);
+            }
+        });
+    }
+
+    /**
      * Taskbar automatically stashes when opening all apps, but we don't report the insets as
      * changing to avoid moving the underlying app. But internally, the apps view should still
      * layout according to the stashed insets rather than the unstashed insets. So this method
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index fd986e6..80ce369 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -50,6 +50,7 @@
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
 import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
 
@@ -143,6 +144,7 @@
 import com.android.launcher3.util.PendingRequestArgs;
 import com.android.launcher3.util.PendingSplitSelectInfo;
 import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
 import com.android.launcher3.util.TouchController;
@@ -152,6 +154,7 @@
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.TouchInteractionService.TISBinder;
+import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.LauncherUnfoldAnimationController;
 import com.android.quickstep.util.ProxyScreenStatusProvider;
 import com.android.quickstep.util.QuickstepOnboardingPrefs;
@@ -1206,6 +1209,32 @@
                 getDeviceProfile().toSmallString());
     }
 
+    /**
+     * Launches the given {@link GroupTask} in splitscreen.
+     *
+     * If the second split task is missing, launches the first task normally.
+     */
+    public void launchSplitTasks(View taskView, GroupTask groupTask) {
+        if (groupTask.task2 == null) {
+            UI_HELPER_EXECUTOR.execute(() ->
+                    ActivityManagerWrapper.getInstance().startActivityFromRecents(
+                            groupTask.task1.key,
+                            getActivityLaunchOptions(taskView, null).options));
+            return;
+        }
+        mSplitSelectStateController.launchTasks(
+                groupTask.task1.key.id,
+                groupTask.task2.key.id,
+                SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
+                /* callback= */ success -> {},
+                /* freezeTaskList= */ true,
+                groupTask.mSplitBounds == null
+                        ? DEFAULT_SPLIT_RATIO
+                        : groupTask.mSplitBounds.appsStackedVertically
+                                ? groupTask.mSplitBounds.topTaskPercent
+                                : groupTask.mSplitBounds.leftTaskPercent);
+    }
+
     private static final class LauncherTaskViewController extends
             TaskViewTouchController<Launcher> {
 
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 5a09e02..b5240fd 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -24,8 +24,10 @@
 import android.os.Build;
 import android.os.SystemClock;
 import android.os.Trace;
+import android.view.View;
 
 import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
@@ -48,7 +50,7 @@
 public class OverviewCommandHelper {
 
     public static final int TYPE_SHOW = 1;
-    public static final int TYPE_SHOW_NEXT_FOCUS = 2;
+    public static final int TYPE_KEYBOARD_INPUT = 2;
     public static final int TYPE_HIDE = 3;
     public static final int TYPE_TOGGLE = 4;
     public static final int TYPE_HOME = 5;
@@ -66,6 +68,13 @@
     private final TaskAnimationManager mTaskAnimationManager;
     private final ArrayList<CommandInfo> mPendingCommands = new ArrayList<>();
 
+    /**
+     * Index of the TaskView that should be focused when launching Overview. Persisted so that we
+     * do not lose the focus across multiple calls of
+     * {@link OverviewCommandHelper#executeCommand(CommandInfo)} for the same command
+     */
+    private int mTaskFocusIndexOverride = -1;
+
     public OverviewCommandHelper(TouchInteractionService service,
             OverviewComponentObserver observer,
             TaskAnimationManager taskAnimationManager) {
@@ -179,6 +188,7 @@
                     // already visible
                     return true;
                 case TYPE_HIDE: {
+                    mTaskFocusIndexOverride = -1;
                     int currentPage = recents.getNextPage();
                     TaskView tv = (currentPage >= 0 && currentPage < recents.getTaskViewCount())
                             ? (TaskView) recents.getPageAt(currentPage)
@@ -194,15 +204,9 @@
         }
 
         final Runnable completeCallback = () -> {
-            if (cmd.type == TYPE_SHOW_NEXT_FOCUS) {
-                RecentsView rv = activityInterface.getVisibleRecentsView();
-                // When the overview is launched via alt tab (cmd type is TYPE_SHOW_NEXT_FOCUS),
-                // the touch mode somehow is not change to false by the Android framework.
-                // The subsequent tab to go through tasks in overview can only be dispatched to
-                // focuses views, while focus can only be requested in
-                // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
-                // here we launch overview from home.
-                rv.getViewRootImpl().touchModeChanged(false);
+            RecentsView rv = activityInterface.getVisibleRecentsView();
+            if (rv != null && (cmd.type == TYPE_KEYBOARD_INPUT || cmd.type == TYPE_HIDE)) {
+                updateRecentsViewFocus(rv);
             }
             scheduleNextTask(cmd);
         };
@@ -280,40 +284,55 @@
         cmd.removeListener(handler);
         Trace.endAsyncSection(TRANSITION_NAME, 0);
 
-        if (cmd.type == TYPE_SHOW_NEXT_FOCUS) {
-            RecentsView rv =
-                    mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
-            if (rv != null) {
-                // When the overview is launched via alt tab (cmd type is TYPE_SHOW_NEXT_FOCUS),
-                // the touch mode somehow is not change to false by the Android framework.
-                // The subsequent tab to go through tasks in overview can only be dispatched to
-                // focuses views, while focus can only be requested in
-                // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
-                // here we launch overview with live tile.
-                rv.getViewRootImpl().touchModeChanged(false);
-                // Ensure that recents view has focus so that it receives the followup key inputs
-                TaskView taskView = rv.getNextTaskView();
-                if (taskView == null) {
-                    taskView = rv.getTaskViewAt(0);
-                    if (taskView != null) {
-                        taskView.requestFocus();
-                    } else {
-                        rv.requestFocus();
-                    }
-                } else {
-                    taskView.requestFocus();
-                }
-            }
+        RecentsView rv =
+                mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
+        if (rv != null && (cmd.type == TYPE_KEYBOARD_INPUT || cmd.type == TYPE_HIDE)) {
+            updateRecentsViewFocus(rv);
         }
         scheduleNextTask(cmd);
     }
 
+    private void updateRecentsViewFocus(@NonNull RecentsView rv) {
+        // When the overview is launched via alt tab (cmd type is TYPE_KEYBOARD_INPUT),
+        // the touch mode somehow is not change to false by the Android framework.
+        // The subsequent tab to go through tasks in overview can only be dispatched to
+        // focuses views, while focus can only be requested in
+        // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
+        // here we launch overview with live tile.
+        rv.getViewRootImpl().touchModeChanged(false);
+        // Ensure that recents view has focus so that it receives the followup key inputs
+        TaskView taskView = rv.getTaskViewAt(mTaskFocusIndexOverride);
+        if (taskView != null) {
+            requestFocus(taskView);
+            return;
+        }
+        taskView = rv.getNextTaskView();
+        if (taskView != null) {
+            requestFocus(taskView);
+            return;
+        }
+        taskView = rv.getTaskViewAt(0);
+        if (taskView != null) {
+            requestFocus(taskView);
+            return;
+        }
+        requestFocus(rv);
+    }
+
+    private void requestFocus(@NonNull View view) {
+        view.post(() -> {
+            view.requestFocus();
+            view.requestAccessibilityFocus();
+        });
+    }
+
     public void dump(PrintWriter pw) {
         pw.println("OverviewCommandHelper:");
         pw.println("  mPendingCommands=" + mPendingCommands.size());
         if (!mPendingCommands.isEmpty()) {
             pw.println("    pendingCommandType=" + mPendingCommands.get(0).type);
         }
+        pw.println("  mTaskFocusIndexOverride=" + mTaskFocusIndexOverride);
     }
 
     private static class CommandInfo {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 287b468..1b8a93c 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -205,7 +205,7 @@
         public void onOverviewShown(boolean triggeredFromAltTab) {
             if (triggeredFromAltTab) {
                 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
-                mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW_NEXT_FOCUS);
+                mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_KEYBOARD_INPUT);
             } else {
                 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW);
             }
diff --git a/quickstep/src/com/android/quickstep/util/BorderAnimator.java b/quickstep/src/com/android/quickstep/util/BorderAnimator.java
new file mode 100644
index 0000000..532edb2
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/BorderAnimator.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2023 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.util;
+
+import android.animation.Animator;
+import android.annotation.ColorInt;
+import android.annotation.Nullable;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.view.animation.Interpolator;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Px;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.anim.Interpolators;
+
+/**
+ * Utility class for drawing a rounded-rect border around a view.
+ * <p>
+ * To use this class:
+ * 1. Create an instance in the target view.
+ * 2. Override the target view's {@link android.view.View#draw(Canvas)} method and call
+ *      {@link BorderAnimator#drawBorder(Canvas)} after {@code super.draw(canvas)}.
+ * 3. Call {@link BorderAnimator#buildAnimator(boolean)} and start the animation where appropriate.
+ */
+public final class BorderAnimator {
+
+    public static final int DEFAULT_BORDER_COLOR = 0xffffffff;
+
+    private static final long DEFAULT_APPEARANCE_ANIMATION_DURATION_MS = 300;
+    private static final long DEFAULT_DISAPPEARANCE_ANIMATION_DURATION_MS = 133;
+    private static final Interpolator DEFAULT_INTERPOLATOR = Interpolators.EMPHASIZED_DECELERATE;
+
+    @NonNull private final AnimatedFloat mBorderAnimationProgress = new AnimatedFloat(
+            this::updateOutline);
+    @NonNull private final Rect mBorderBounds = new Rect();
+    @NonNull private final BorderBoundsBuilder mBorderBoundsBuilder;
+    @Px private final int mBorderWidthPx;
+    @Px private final int mBorderRadiusPx;
+    @NonNull private final Runnable mInvalidateViewCallback;
+    private final long mAppearanceDurationMs;
+    private final long mDisappearanceDurationMs;
+    @NonNull private final Interpolator mInterpolator;
+    @NonNull private final Paint mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+    private int mAlignmentAdjustment;
+
+    @Nullable private Animator mRunningBorderAnimation;
+
+    public BorderAnimator(
+            @NonNull BorderBoundsBuilder borderBoundsBuilder,
+            int borderWidthPx,
+            int borderRadiusPx,
+            @ColorInt int borderColor,
+            @NonNull Runnable invalidateViewCallback) {
+        this(borderBoundsBuilder,
+                borderWidthPx,
+                borderRadiusPx,
+                borderColor,
+                invalidateViewCallback,
+                DEFAULT_APPEARANCE_ANIMATION_DURATION_MS,
+                DEFAULT_DISAPPEARANCE_ANIMATION_DURATION_MS,
+                DEFAULT_INTERPOLATOR);
+    }
+
+    public BorderAnimator(
+            @NonNull BorderBoundsBuilder borderBoundsBuilder,
+            int borderWidthPx,
+            int borderRadiusPx,
+            @ColorInt int borderColor,
+            @NonNull Runnable invalidateViewCallback,
+            long appearanceDurationMs,
+            long disappearanceDurationMs,
+            @NonNull Interpolator interpolator) {
+        mBorderBoundsBuilder = borderBoundsBuilder;
+        mBorderWidthPx = borderWidthPx;
+        mBorderRadiusPx = borderRadiusPx;
+        mInvalidateViewCallback = invalidateViewCallback;
+        mAppearanceDurationMs = appearanceDurationMs;
+        mDisappearanceDurationMs = disappearanceDurationMs;
+        mInterpolator = interpolator;
+
+        mBorderPaint.setColor(borderColor);
+        mBorderPaint.setStyle(Paint.Style.STROKE);
+        mBorderPaint.setAlpha(0);
+    }
+
+    private void updateOutline() {
+        float interpolatedProgress = mInterpolator.getInterpolation(
+                mBorderAnimationProgress.value);
+        mAlignmentAdjustment = (int) Utilities.mapBoundToRange(
+                mBorderAnimationProgress.value,
+                /* lowerBound= */ 0f,
+                /* upperBound= */ 1f,
+                /* toMin= */ 0f,
+                /* toMax= */ (float) (mBorderWidthPx / 2f),
+                mInterpolator);
+
+        mBorderPaint.setAlpha(Math.round(255 * interpolatedProgress));
+        mBorderPaint.setStrokeWidth(Math.round(mBorderWidthPx * interpolatedProgress));
+        mInvalidateViewCallback.run();
+    }
+
+    /**
+     * Draws the border on the given canvas.
+     * <p>
+     * Call this method in the target view's {@link android.view.View#draw(Canvas)} method after
+     * calling super.
+     */
+    public void drawBorder(Canvas canvas) {
+        canvas.drawRoundRect(
+                /* left= */ mBorderBounds.left + mAlignmentAdjustment,
+                /* top= */ mBorderBounds.top + mAlignmentAdjustment,
+                /* right= */ mBorderBounds.right - mAlignmentAdjustment,
+                /* bottom= */ mBorderBounds.bottom - mAlignmentAdjustment,
+                /* rx= */ mBorderRadiusPx - mAlignmentAdjustment,
+                /* ry= */ mBorderRadiusPx - mAlignmentAdjustment,
+                /* paint= */ mBorderPaint);
+    }
+
+    /**
+     * Builds the border appearance/disappearance animation.
+     */
+    public Animator buildAnimator(boolean isAppearing) {
+        mBorderBoundsBuilder.updateBorderBounds(mBorderBounds);
+        mRunningBorderAnimation = mBorderAnimationProgress.animateToValue(isAppearing ? 1f : 0f);
+        mRunningBorderAnimation.setDuration(
+                isAppearing ? mAppearanceDurationMs : mDisappearanceDurationMs);
+
+        mRunningBorderAnimation.addListener(
+                AnimatorListeners.forEndCallback(() -> mRunningBorderAnimation = null));
+
+        return mRunningBorderAnimation;
+    }
+
+    /**
+     * Callback to update the border bounds when building this animation.
+     */
+    public interface BorderBoundsBuilder {
+
+        /**
+         * Sets the given rect to the most up-to-date bounds.
+         */
+        void updateBorderBounds(Rect rect);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 5cf79ea..e9498fd 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -5,6 +5,7 @@
 
 import android.content.Context;
 import android.graphics.PointF;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -72,6 +73,23 @@
     }
 
     @Override
+    protected void updateBorderBounds(Rect bounds) {
+        if (mSplitBoundsConfig == null) {
+            super.updateBorderBounds(bounds);
+            return;
+        }
+        bounds.set(
+                Math.min(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
+                        mSnapshotView2.getLeft() + Math.round(mSnapshotView2.getTranslationX())),
+                Math.min(mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
+                        mSnapshotView2.getTop() + Math.round(mSnapshotView2.getTranslationY())),
+                Math.max(mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
+                        mSnapshotView2.getRight() + Math.round(mSnapshotView2.getTranslationX())),
+                Math.max(mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()),
+                        mSnapshotView2.getBottom() + Math.round(mSnapshotView2.getTranslationY())));
+    }
+
+    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         mSnapshotView2 = findViewById(R.id.bottomright_snapshot);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index d3c7778..0e2f020 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -31,6 +31,7 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
 import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
+import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -42,6 +43,7 @@
 import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Canvas;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -94,6 +96,7 @@
 import com.android.quickstep.TaskThumbnailCache;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.TaskViewUtils;
+import com.android.quickstep.util.BorderAnimator;
 import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.util.SplitSelectStateController;
@@ -405,6 +408,8 @@
 
     private boolean mIsClickableAsLiveTile = true;
 
+    @Nullable private final BorderAnimator mBorderAnimator;
+
     public TaskView(Context context) {
         this(context, null);
     }
@@ -414,12 +419,46 @@
     }
 
     public TaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public TaskView(
+            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
         mActivity = StatefulActivity.fromContext(context);
         setOnClickListener(this::onClick);
 
         mCurrentFullscreenParams = new FullscreenDrawParams(context);
         mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
+
+        setWillNotDraw(!FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get());
+
+        mBorderAnimator = !FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
+                ? null
+                : new BorderAnimator(
+                        /* borderBoundsBuilder= */ this::updateBorderBounds,
+                        /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
+                                R.dimen.keyboard_quick_switch_border_width),
+                        /* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
+                        /* borderColor= */ attrs == null
+                        ? DEFAULT_BORDER_COLOR
+                        : context.getTheme()
+                                .obtainStyledAttributes(
+                                        attrs,
+                                        R.styleable.TaskView,
+                                        defStyleAttr,
+                                        defStyleRes)
+                                .getColor(
+                                        R.styleable.TaskView_borderColor,
+                                        DEFAULT_BORDER_COLOR),
+                        /* invalidateViewCallback= */ TaskView.this::invalidate);
+    }
+
+    protected void updateBorderBounds(Rect bounds) {
+        bounds.set(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
+                mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
+                mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
+                mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()));
     }
 
     public void setTaskViewId(int id) {
@@ -463,6 +502,22 @@
         mIconTouchDelegate = new TransformingTouchDelegate(mIconView);
     }
 
+    @Override
+    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        if (mBorderAnimator != null) {
+            mBorderAnimator.buildAnimator(gainFocus).start();
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        if (mBorderAnimator != null) {
+            mBorderAnimator.drawBorder(canvas);
+        }
+    }
+
     /**
      * Whether the taskview should take the touch event from parent. Events passed to children
      * that might require special handling.
diff --git a/res/drawable/bg_widgets_content.xml b/res/drawable/bg_widgets_content.xml
new file mode 100644
index 0000000..8060430
--- /dev/null
+++ b/res/drawable/bg_widgets_content.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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">
+
+    <!--
+       L -> large radius
+       s -> small radius
+       0 -> no radiuls
+    -->
+
+    <!-- MIDDLE : 0 0 s s -->
+    <item android:state_middle="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/surface" />
+            <corners
+                android:topLeftRadius="0dp"
+                android:topRightRadius="0dp"
+                android:bottomLeftRadius="@dimen/widget_list_content_corner_radius"
+                android:bottomRightRadius="@dimen/widget_list_content_corner_radius" />
+        </shape>
+    </item>
+
+    <!-- LAST : 0 0 L L -->
+    <item android:state_last="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/surface" />
+            <corners
+                android:topLeftRadius="0dp"
+                android:topRightRadius="0dp"
+                android:bottomLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+                android:bottomRightRadius="@dimen/widget_list_top_bottom_corner_radius" />
+        </shape>
+    </item>
+</selector>
diff --git a/res/drawable/bg_widgets_header.xml b/res/drawable/bg_widgets_header.xml
new file mode 100644
index 0000000..a89aad4
--- /dev/null
+++ b/res/drawable/bg_widgets_header.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetTop="@dimen/widget_list_entry_spacing" >
+    <ripple
+        android:color="?android:attr/colorControlHighlight"
+        android:paddingTop="@dimen/widget_list_header_view_vertical_padding"
+        android:paddingBottom="@dimen/widget_list_header_view_vertical_padding" >
+        <item android:id="@android:id/mask"
+            android:drawable="@drawable/bg_widgets_header_states" />
+        <item android:drawable="@drawable/bg_widgets_header_states" />
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/bg_widgets_header_states.xml b/res/drawable/bg_widgets_header_states.xml
new file mode 100644
index 0000000..f45a7ab
--- /dev/null
+++ b/res/drawable/bg_widgets_header_states.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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">
+
+    <!--
+       L -> large radius
+       s -> small radius
+       0 -> no radiuls
+    -->
+
+    <!-- SINGLE : L L L L -->
+    <item android:state_single="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/surface" />
+            <corners
+                android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+                android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
+                android:bottomLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+                android:bottomRightRadius="@dimen/widget_list_top_bottom_corner_radius" />
+        </shape>
+    </item>
+
+    <!-- FIRST_EXPANDED : L L 0 0 -->
+    <item android:state_first="true" android:state_expanded="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/surface" />
+            <corners
+                android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+                android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
+                android:bottomLeftRadius="0dp"
+                android:bottomRightRadius="0dp" />
+        </shape>
+    </item>
+
+    <!-- FIRST : L L s s -->
+    <item android:state_first="true" >
+        <shape android:shape="rectangle">
+            <solid android:color="@color/surface" />
+            <corners
+                android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+                android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
+                android:bottomLeftRadius="@dimen/widget_list_content_corner_radius"
+                android:bottomRightRadius="@dimen/widget_list_content_corner_radius" />
+        </shape>
+    </item>
+
+    <!-- MIDDLE_EXPANDED : s s 0 0 -->
+    <item android:state_middle="true" android:state_expanded="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/surface" />
+            <corners
+                android:topLeftRadius="@dimen/widget_list_content_corner_radius"
+                android:topRightRadius="@dimen/widget_list_content_corner_radius"
+                android:bottomLeftRadius="0dp"
+                android:bottomRightRadius="0dp" />
+        </shape>
+    </item>
+
+    <!-- MIDDLE : s s s s -->
+    <item android:state_middle="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/surface" />
+            <corners
+                android:topLeftRadius="@dimen/widget_list_content_corner_radius"
+                android:topRightRadius="@dimen/widget_list_content_corner_radius"
+                android:bottomLeftRadius="@dimen/widget_list_content_corner_radius"
+                android:bottomRightRadius="@dimen/widget_list_content_corner_radius" />
+        </shape>
+    </item>
+
+    <!-- LAST : s s L L -->
+    <item android:state_last="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/surface" />
+            <corners
+                android:topLeftRadius="@dimen/widget_list_content_corner_radius"
+                android:topRightRadius="@dimen/widget_list_content_corner_radius"
+                android:bottomLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+                android:bottomRightRadius="@dimen/widget_list_top_bottom_corner_radius" />
+        </shape>
+    </item>
+</selector>
diff --git a/res/drawable/widgets_tray_expand_button.xml b/res/drawable/widgets_tray_expand_button.xml
index 8316e0f..f2e142e 100644
--- a/res/drawable/widgets_tray_expand_button.xml
+++ b/res/drawable/widgets_tray_expand_button.xml
@@ -14,8 +14,8 @@
      limitations under the License.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_checked="true"
+    <item android:state_expanded="true"
         android:drawable="@drawable/ic_expand_less" />
-    <item android:state_checked="false"
+    <item android:state_expanded="false"
         android:drawable="@drawable/ic_expand_more" />
 </selector>
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index 35bea27..6d26ce3 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -23,7 +23,8 @@
     android:importantForAccessibility="yes"
     android:focusable="true"
     launcher:appIconSize="48dp"
-    android:descendantFocusability="afterDescendants">
+    android:descendantFocusability="afterDescendants"
+    android:background="@drawable/bg_widgets_header" >
 
     <ImageView
         android:id="@+id/app_icon"
@@ -65,8 +66,11 @@
 
     <!-- This checkbox is not clickable. The outermost LinearLayout is responsible to handle all
          click event and update the checkbox state. -->
-    <CheckBox
+    <ImageView
+        android:duplicateParentState="true"
         android:id="@+id/toggle"
+        android:alpha=".6"
+        android:src="@drawable/widgets_tray_expand_button"
         android:layout_marginHorizontal="16dp"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -74,7 +78,6 @@
         android:layout_alignParentEnd="true"
         android:enabled="false"
         android:clickable="false"
-        android:importantForAccessibility="no"
-        android:button="@drawable/widgets_tray_expand_button"/>
+        android:importantForAccessibility="no" />
 
 </com.android.launcher3.widget.picker.WidgetsListHeader>
\ No newline at end of file
diff --git a/res/layout/widgets_table_container.xml b/res/layout/widgets_table_container.xml
index ab96b1343..4a32672 100644
--- a/res/layout/widgets_table_container.xml
+++ b/res/layout/widgets_table_container.xml
@@ -16,5 +16,6 @@
 <com.android.launcher3.widget.picker.WidgetsListTableView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/widgets_table"
+    android:background="@drawable/bg_widgets_content"
     android:layout_width="match_parent"
     android:layout_height="wrap_content" />
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index af9ed95..7b0033d 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -356,6 +356,9 @@
             "SECONDARY_DRAG_N_DROP_TO_PIN", false,
             "Enable dragging and dropping to pin apps within secondary display");
 
+    public static final BooleanFlag ENABLE_ICON_IN_TEXT_HEADER = getDebugFlag(
+            "ENABLE_ICON_IN_TEXT_HEADER", false, "Show icon in textheader");
+
     public static final BooleanFlag SHOW_DOT_PAGINATION = getDebugFlag(
             "SHOW_DOT_PAGINATION", false, "Enable showing dot pagination in workspace");
 
@@ -408,6 +411,10 @@
             "Enables receiving unfold animation events from sysui instead of calculating "
                     + "them in launcher process using hinge sensor values.");
 
+    public static final BooleanFlag ENABLE_KEYBOARD_QUICK_SWITCH = getDebugFlag(
+            "ENABLE_KEYBOARD_QUICK_SWITCH", false,
+            "Enables keyboard quick switching");
+
     public static void initialize(Context context) {
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 7c7cdf4..2ce400e 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -274,8 +274,6 @@
             mSuggestedWidgetsHeader = (WidgetsListHeader) layoutInflater.inflate(
                     R.layout.widgets_list_row_header, mSuggestedWidgetsContainer, false);
             mSuggestedWidgetsHeader.setExpanded(true);
-            mSuggestedWidgetsHeader.setBackground(
-                    new WidgetsListDrawableFactory(getContext()).createHeaderBackgroundDrawable());
 
             PackageItemInfo packageItemInfo =  new PackageItemInfo(
                     /* packageName= */ SUGGESTIONS_PACKAGE_NAME,
@@ -311,9 +309,8 @@
                 ? mContent.findViewById(R.id.title)
                 : mSearchScrollView.findViewById(R.id.title);
         mRightPane = mIsTwoPane ? mContent.findViewById(R.id.right_pane) : null;
-        mWidgetsListTableViewHolderBinder =  new WidgetsListTableViewHolderBinder(
-                layoutInflater, this, this,
-                new WidgetsListDrawableFactory(getContext()));
+        mWidgetsListTableViewHolderBinder =
+                new WidgetsListTableViewHolderBinder(layoutInflater, this, this);
         onRecommendedWidgetsBound();
         onWidgetsBound();
 
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 549ac42..b5ff719 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -108,19 +108,15 @@
         mHeaderChangeListener = headerChangeListener;
         mContext = context;
         mDiffReporter = new WidgetsDiffReporter(iconCache, this);
-        WidgetsListDrawableFactory listDrawableFactory = new WidgetsListDrawableFactory(context);
 
         mViewHolderBinders.put(
                 VIEW_TYPE_WIDGETS_LIST,
                 new WidgetsListTableViewHolderBinder(
-                        layoutInflater, iconClickListener, iconLongClickListener,
-                        listDrawableFactory));
+                        layoutInflater, iconClickListener, iconLongClickListener));
         mViewHolderBinders.put(
                 VIEW_TYPE_WIDGETS_HEADER,
                 new WidgetsListHeaderViewHolderBinder(
-                        layoutInflater,
-                        /* onHeaderClickListener= */ this,
-                        listDrawableFactory));
+                        layoutInflater, /* onHeaderClickListener= */ this));
         mViewHolderBinders.put(
                 VIEW_TYPE_WIDGETS_SPACE,
                 new WidgetsSpaceViewHolderBinder(emptySpaceHeightProvider));
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListDrawableFactory.java b/src/com/android/launcher3/widget/picker/WidgetsListDrawableFactory.java
deleted file mode 100644
index 984a274..0000000
--- a/src/com/android/launcher3/widget/picker/WidgetsListDrawableFactory.java
+++ /dev/null
@@ -1,122 +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 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.InsetDrawable;
-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;
-    private final int mVerticalPadding;
-    private final int mHeaderMargin;
-
-    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));
-        mVerticalPadding =
-                res.getDimensionPixelSize(R.dimen.widget_list_header_view_vertical_padding);
-        mHeaderMargin = res.getDimensionPixelSize(R.dimen.widget_list_entry_spacing);
-    }
-
-    /**
-     * 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));
-        RippleDrawable ripple =
-                new RippleDrawable(mRippleColor, /* content= */ stateList, /* mask= */ stateList);
-        ripple.setPadding(0, mVerticalPadding, 0, mVerticalPadding);
-        return new InsetDrawable(ripple, 0, mHeaderMargin, 0, 0);
-    }
-
-    /**
-     * 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/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index a6ef89f..547f39e 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -28,7 +28,6 @@
 import android.util.TypedValue;
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.CheckBox;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -67,7 +66,6 @@
     private TextView mTitle;
     private TextView mSubtitle;
     private GradientDrawable mBackground;
-    private CheckBox mExpandToggle;
     private boolean mEnableIconUpdateAnimation = false;
     private boolean mIsExpanded = false;
 
@@ -101,9 +99,8 @@
         mAppIcon = findViewById(R.id.app_icon);
         mTitle = findViewById(R.id.app_title);
         mSubtitle = findViewById(R.id.app_subtitle);
-        mExpandToggle = findViewById(R.id.toggle);
         if (mIsTwoPane) {
-            mExpandToggle.setVisibility(GONE);
+            findViewById(R.id.toggle).setVisibility(GONE);
         }
         setAccessibilityDelegate(new AccessibilityDelegate() {
 
@@ -153,7 +150,6 @@
     @UiThread
     public void setExpanded(boolean isExpanded) {
         this.mIsExpanded = isExpanded;
-        mExpandToggle.setChecked(isExpanded);
         if (mIsTwoPane) {
             if (Utilities.isDarkTheme(getContext())) {
                 if (mIsExpanded) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
index c6a7285..27a2b1c 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
@@ -32,22 +32,17 @@
         ViewHolderBinder<WidgetsListHeaderEntry, WidgetsListHeaderHolder> {
     private final LayoutInflater mLayoutInflater;
     private final OnHeaderClickListener mOnHeaderClickListener;
-    private final WidgetsListDrawableFactory mListDrawableFactory;
 
     public WidgetsListHeaderViewHolderBinder(LayoutInflater layoutInflater,
-            OnHeaderClickListener onHeaderClickListener,
-            WidgetsListDrawableFactory listDrawableFactory) {
+            OnHeaderClickListener onHeaderClickListener) {
         mLayoutInflater = layoutInflater;
         mOnHeaderClickListener = onHeaderClickListener;
-        mListDrawableFactory = listDrawableFactory;
     }
 
     @Override
     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);
+        return new WidgetsListHeaderHolder((WidgetsListHeader) mLayoutInflater.inflate(
+                R.layout.widgets_list_row_header, parent, false));
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index 8500b9a..4c1f7a9 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -51,17 +51,14 @@
     private final LayoutInflater mLayoutInflater;
     private final OnClickListener mIconClickListener;
     private final OnLongClickListener mIconLongClickListener;
-    private final WidgetsListDrawableFactory mListDrawableFactory;
 
     public WidgetsListTableViewHolderBinder(
             LayoutInflater layoutInflater,
             OnClickListener iconClickListener,
-            OnLongClickListener iconLongClickListener,
-            WidgetsListDrawableFactory listDrawableFactory) {
+            OnLongClickListener iconLongClickListener) {
         mLayoutInflater = layoutInflater;
         mIconClickListener = iconClickListener;
         mIconLongClickListener = iconLongClickListener;
-        mListDrawableFactory = listDrawableFactory;
     }
 
     @Override
@@ -70,12 +67,8 @@
             Log.v(TAG, "\nonCreateViewHolder");
         }
 
-        WidgetsRowViewHolder viewHolder =
-                new WidgetsRowViewHolder(mLayoutInflater.inflate(
+        return new WidgetsRowViewHolder(mLayoutInflater.inflate(
                         R.layout.widgets_table_container, parent, false));
-        viewHolder.tableContainer.setBackgroundDrawable(
-                mListDrawableFactory.createContentBackgroundDrawable());
-        return viewHolder;
     }
 
     @Override
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index f53d15b..612a4c6 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -90,8 +90,7 @@
         }).when(mIconCache).getTitleNoCache(any());
         mViewHolderBinder = new WidgetsListHeaderViewHolderBinder(
                 LayoutInflater.from(mContext),
-                mOnHeaderClickListener,
-                new WidgetsListDrawableFactory(mContext));
+                mOnHeaderClickListener);
     }
 
     @Test
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 7ec4d20..9dc46f1 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -96,8 +96,7 @@
         mViewHolderBinder = new WidgetsListTableViewHolderBinder(
                 LayoutInflater.from(mContext),
                 mOnIconClickListener,
-                mOnLongClickListener,
-                new WidgetsListDrawableFactory(mContext));
+                mOnLongClickListener);
     }
 
     @Test