Merge "Overlay property instead of style" into sc-dev
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index b4c6138..fe81b4c 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -29,6 +29,8 @@
     Shortcut shortcut = 3;
     Widget widget = 4;
     FolderIcon folder_icon = 9;
+    Slice slice = 10;
+    SearchActionItem search_action_item = 11;
   }
   // When used for launch event, stores the global predictive rank
   optional int32 rank = 5;
@@ -169,6 +171,17 @@
   optional string label_info = 4;
 }
 
+// Contains Slice details for logging.
+message Slice{
+  optional string uri = 1;
+}
+
+// Represents SearchAction with in launcher
+message SearchActionItem{
+  optional string package_name = 1;
+  optional string title = 2;
+}
+
 //////////////////////////////////////////////
 // Containers
 
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index a0e87cf..e46eb9e 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -122,13 +122,13 @@
     <dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
 
     <!-- Taskbar -->
-    <dimen name="taskbar_size">48dp</dimen>
-    <dimen name="taskbar_icon_size">32dp</dimen>
+    <dimen name="taskbar_size">60dp</dimen>
+    <dimen name="taskbar_icon_size">44dp</dimen>
     <dimen name="taskbar_icon_touch_size">48dp</dimen>
     <dimen name="taskbar_icon_drag_icon_size">54dp</dimen>
     <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
-    <dimen name="taskbar_icon_spacing">14dp</dimen>
+    <dimen name="taskbar_icon_spacing">8dp</dimen>
     <dimen name="taskbar_divider_thickness">1dp</dimen>
-    <dimen name="taskbar_divider_height">24dp</dimen>
+    <dimen name="taskbar_divider_height">32dp</dimen>
     <dimen name="taskbar_folder_margin">16dp</dimen>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index d1fa2fd..5b30143 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -222,7 +222,7 @@
             mTaskbarController.cleanup();
             mTaskbarController = null;
         }
-        if (FeatureFlags.ENABLE_TASKBAR.get() && mDeviceProfile.isTablet) {
+        if (mDeviceProfile.isTaskbarPresent) {
             TaskbarActivityContext taskbarActivityContext = new TaskbarActivityContext(this);
             mTaskbarController = new TaskbarController(this,
                     taskbarActivityContext.getTaskbarContainerView());
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index f53a5ef..7d494c2 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -130,7 +130,7 @@
 
         if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
             mDecorationHandler = new AllAppsSectionDecorator.SectionDecorationHandler(getContext(),
-                    false);
+                    false, 0, true, true);
         }
 
         updateVisibility();
@@ -164,7 +164,7 @@
             for (int i = 0; i < childrenCount; i++) {
                 mDecorationHandler.extendBounds(getChildAt(i));
             }
-            mDecorationHandler.onDraw(canvas);
+            mDecorationHandler.onGroupDraw(canvas);
             mDecorationHandler.onFocusDraw(canvas, getFocusedChild());
             mLauncher.getAppsView().getActiveRecyclerView().invalidateItemDecorations();
         }
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 225823e..2ea8bd2 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -148,10 +148,13 @@
                         ? (FolderInfo) itemsIdMap.get(info.container) : null;
                 StatsLogCompatManager.writeSnapshot(info.buildProto(parent), instanceId);
             }
+            additionalSnapshotEvents(instanceId);
             prefs.edit().putLong(LAST_SNAPSHOT_TIME_MILLIS, now).apply();
         }
     }
 
+    protected void additionalSnapshotEvents(InstanceId snapshotInstanceId){}
+
     @Override
     public void validateData() {
         super.validateData();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
index ab05fbf..5dddaf3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
@@ -89,8 +89,7 @@
         mTaskbarView = mTaskbarContainerView.findViewById(R.id.taskbar_view);
         mTaskbarView.construct(createTaskbarViewCallbacks());
         mWindowManager = mLauncher.getWindowManager();
-        mTaskbarSize = new Point(MATCH_PARENT,
-                mLauncher.getResources().getDimensionPixelSize(R.dimen.taskbar_size));
+        mTaskbarSize = new Point(MATCH_PARENT, mLauncher.getDeviceProfile().taskbarSize);
         mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
         mTaskbarVisibilityController = new TaskbarVisibilityController(mLauncher,
                 createTaskbarVisibilityControllerCallbacks());
@@ -233,14 +232,10 @@
     }
 
     private void removeFromWindowManager() {
-        if (mTaskbarContainerView.isAttachedToWindow()) {
-            mWindowManager.removeViewImmediate(mTaskbarContainerView);
-        }
+        mWindowManager.removeViewImmediate(mTaskbarContainerView);
     }
 
     private void addToWindowManager() {
-        removeFromWindowManager();
-
         final int gravity = Gravity.BOTTOM;
 
         mWindowLayoutParams = new WindowManager.LayoutParams(
@@ -378,7 +373,8 @@
      * @return Whether the given View is in the same window as Taskbar.
      */
     public boolean isViewInTaskbar(View v) {
-        return mTaskbarContainerView.getWindowId().equals(v.getWindowId());
+        return mTaskbarContainerView.isAttachedToWindow()
+                && mTaskbarContainerView.getWindowId().equals(v.getWindowId());
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 73f4ff2..c60e257 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -49,6 +49,7 @@
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 
 /**
  * Touch controller for handling various state transitions in portrait UI.
@@ -319,4 +320,44 @@
             return baseInterpolator.getInterpolation(v);
         }
     }
+
+    @Override
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                InteractionJankMonitorWrapper.begin(
+                        mLauncher.getRootView(), InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                InteractionJankMonitorWrapper.cancel(
+                        InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+                break;
+        }
+        return super.onControllerInterceptTouchEvent(ev);
+
+    }
+
+    @Override
+    protected void onReinitToState(LauncherState newToState) {
+        super.onReinitToState(newToState);
+        if (newToState != ALL_APPS) {
+            InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+        }
+    }
+
+    @Override
+    protected void onReachedFinalState(LauncherState toState) {
+        super.onReinitToState(toState);
+        if (toState == ALL_APPS) {
+            InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+        }
+    }
+
+    @Override
+    protected void clearState() {
+        super.clearState();
+        InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 70b4f20..1c5dc4c 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -191,6 +191,7 @@
             } else {
                 task = new Task(taskKey);
             }
+            task.setLastSnapshotData(rawTask);
             allTasks.add(task);
         }
 
@@ -200,9 +201,7 @@
     private ArrayList<Task> copyOf(ArrayList<Task> tasks) {
         ArrayList<Task> newTasks = new ArrayList<>();
         for (int i = 0; i < tasks.size(); i++) {
-            Task t = tasks.get(i);
-            newTasks.add(new Task(t.key, t.colorPrimary, t.colorBackground, t.isDockable,
-                    t.isLocked, t.taskDescription, t.topActivity));
+            newTasks.add(new Task(tasks.get(i)));
         }
         return newTasks;
     }
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index f9283a4..a762cb7 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -16,6 +16,9 @@
 
 package com.android.quickstep.logging;
 
+import static androidx.core.util.Preconditions.checkNotNull;
+import static androidx.core.util.Preconditions.checkState;
+
 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS;
 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.SEARCH_RESULT_CONTAINER;
@@ -29,7 +32,9 @@
 import android.content.Context;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.WorkerThread;
+import androidx.slice.SliceItem;
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.Utilities;
@@ -140,6 +145,7 @@
         private Optional<FromState> mFromState = Optional.empty();
         private Optional<ToState> mToState = Optional.empty();
         private Optional<String> mEditText = Optional.empty();
+        private SliceItem mSliceItem;
 
         @Override
         public StatsLogger withItemInfo(ItemInfo itemInfo) {
@@ -177,10 +183,8 @@
 
         @Override
         public StatsLogger withContainerInfo(ContainerInfo containerInfo) {
-            if (mItemInfo != DEFAULT_ITEM_INFO) {
-                throw new IllegalArgumentException(
+            checkState(mItemInfo == DEFAULT_ITEM_INFO,
                         "ItemInfo and ContainerInfo are mutual exclusive; cannot log both.");
-            }
             this.mContainerInfo = Optional.of(containerInfo);
             return this;
         }
@@ -204,12 +208,34 @@
         }
 
         @Override
+        public StatsLogger withSliceItem(@NonNull SliceItem sliceItem) {
+            this.mSliceItem = checkNotNull(sliceItem, "expected valid sliceItem but received null");
+            checkState(mItemInfo == DEFAULT_ITEM_INFO,
+                    "ItemInfo and SliceItem are mutual exclusive; cannot log both.");
+            return this;
+        }
+
+        @Override
         public void log(EventEnum event) {
             if (!Utilities.ATLEAST_R) {
                 return;
             }
 
             LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
+
+            if (mSliceItem != null) {
+                Executors.MODEL_EXECUTOR.execute(
+                        () -> {
+                            LauncherAtom.ItemInfo.Builder itemInfoBuilder =
+                                    LauncherAtom.ItemInfo.newBuilder().setSlice(
+                                            LauncherAtom.Slice.newBuilder().setUri(
+                                                    mSliceItem.getSlice().getUri().toString()));
+                            mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo);
+                            write(event, applyOverwrites(itemInfoBuilder.build()));
+                        });
+                return;
+            }
+
             if (mItemInfo.container < 0 || appState == null) {
                 // Write log on the model thread so that logs do not go out of order
                 // (for eg: drop comes after drag)
@@ -327,6 +353,8 @@
                 return info.getWidget().getPackageName();
             case TASK:
                 return info.getTask().getPackageName();
+            case SEARCH_ACTION_ITEM:
+                return info.getSearchActionItem().getPackageName();
             default:
                 return null;
         }
@@ -342,6 +370,10 @@
                 return info.getWidget().getComponentName();
             case TASK:
                 return info.getTask().getComponentName();
+            case SEARCH_ACTION_ITEM:
+                return info.getSearchActionItem().getTitle();
+            case SLICE:
+                return info.getSlice().getUri();
             default:
                 return null;
         }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5d492ac..deb1388 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -646,9 +646,9 @@
 
     public TaskView getTaskView(int taskId) {
         for (int i = 0; i < getTaskViewCount(); i++) {
-            TaskView tv = getTaskViewAt(i);
-            if (tv.getTask() != null && tv.getTask().key != null && tv.getTask().key.id == taskId) {
-                return tv;
+            TaskView taskView = getTaskViewAt(i);
+            if (taskView.hasTaskId(taskId)) {
+                return taskView;
             }
         }
         return null;
@@ -808,6 +808,7 @@
             final Task task = tasks.get(i);
             final TaskView taskView = (TaskView) getChildAt(pageIndex);
             taskView.bind(task, mOrientationState);
+            taskView.updateTaskSize(!taskView.hasTaskId(mRunningTaskId));
         }
 
         if (mNextPage == INVALID_PAGE) {
@@ -942,7 +943,8 @@
         // Force TaskView to update size from thumbnail
         final int taskCount = getTaskViewCount();
         for (int i = 0; i < taskCount; i++) {
-            getTaskViewAt(i).updateTaskSize();
+            TaskView taskView = getTaskViewAt(i);
+            taskView.updateTaskSize(!taskView.hasTaskId(mRunningTaskId));
         }
     }
 
@@ -1252,6 +1254,7 @@
             // gesture and the task list is loaded and applied
             mTmpRunningTask = Task.from(new TaskKey(runningTaskInfo), runningTaskInfo, false);
             taskView.bind(mTmpRunningTask, mOrientationState);
+            taskView.updateTaskSize(false);
 
             // Measure and layout immediately so that the scroll values is updated instantly
             // as the user might be quick-switching
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 3bd883d..f2f4bc1 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -111,9 +111,6 @@
     private boolean mOverlayEnabled;
     private OverviewScreenshotActions mOverviewScreenshotActionsPlugin;
 
-    // TODO(b/179466077): Remove when proper API is ready.
-    private Float mThumbnailRatio = null;
-
     public TaskThumbnailView(Context context) {
         this(context, null);
     }
@@ -454,31 +451,6 @@
         return mThumbnailData.isRealSnapshot;
     }
 
-    // TODO(b/179466077): Remove when proper API is ready.
-    public float getThumbnailRatio() {
-        // API is ready.
-        if (mThumbnailRatio != null) {
-            return mThumbnailRatio;
-        }
-
-        if (mThumbnailData == null || mThumbnailData.thumbnail == null) {
-            final float[] thumbnailRatios =
-                    new float[]{0.8882452f, 1.2834098f, 0.5558415f, 2.15625f};
-            // Use key's hash code to return a deterministic thumbnail ratio.
-            mThumbnailRatio = thumbnailRatios[mTask.key.hashCode() % thumbnailRatios.length];
-            return mThumbnailRatio;
-        }
-
-        float surfaceWidth = mThumbnailData.thumbnail.getWidth() / mThumbnailData.scale;
-        float surfaceHeight = mThumbnailData.thumbnail.getHeight() / mThumbnailData.scale;
-        float availableWidth = surfaceWidth
-                - (mThumbnailData.insets.left + mThumbnailData.insets.right);
-        float availableHeight = surfaceHeight
-                - (mThumbnailData.insets.top + mThumbnailData.insets.bottom);
-        mThumbnailRatio = availableWidth / availableHeight;
-        return mThumbnailRatio;
-    }
-
     /**
      * Utility class to position the thumbnail in the TaskView
      */
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index a1b5533..e891c95 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -48,6 +48,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Outline;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
@@ -449,7 +450,6 @@
         cancelPendingLoadTasks();
         mTask = task;
         mSnapshotView.bind(task);
-        updateTaskSize();
         setOrientationState(orientedState);
     }
 
@@ -457,6 +457,10 @@
         return mTask;
     }
 
+    public boolean hasTaskId(int taskId) {
+        return mTask != null && mTask.key != null && mTask.key.id == taskId;
+    }
+
     public TaskThumbnailView getThumbnail() {
         return mSnapshotView;
     }
@@ -1077,9 +1081,11 @@
                 previewPositionHelper);
     }
 
-    void updateTaskSize() {
+    void updateTaskSize(boolean variableWidth) {
         ViewGroup.LayoutParams params = getLayoutParams();
-        if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+        float thumbnailRatio = mTask != null ? mTask.getVisibleThumbnailRatio() : 0f;
+        if (variableWidth && mActivity.getDeviceProfile().isTablet
+                && FeatureFlags.ENABLE_OVERVIEW_GRID.get() && thumbnailRatio != 0f) {
             final int thumbnailPadding = (int) getResources().getDimension(
                     R.dimen.task_thumbnail_top_margin);
 
@@ -1087,7 +1093,6 @@
             int taskWidth = lastComputedTaskSize.width();
             int taskHeight = lastComputedTaskSize.height();
             int boxLength = Math.max(taskWidth, taskHeight);
-            float thumbnailRatio = mSnapshotView.getThumbnailRatio();
 
             int expectedWidth;
             int expectedHeight;
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 0041c9a..8ed16c7 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -40,35 +40,7 @@
 
         <include layout="@layout/floating_header_content" />
 
-        <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
-            android:id="@+id/tabs"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/all_apps_header_tab_height"
-            android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
-            android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
-            android:orientation="horizontal"
-            style="@style/TextHeadline">
-
-            <Button
-                android:id="@+id/tab_personal"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:background="?android:attr/selectableItemBackground"
-                android:text="@string/all_apps_personal_tab"
-                android:textColor="@color/all_apps_tab_text"
-                android:textSize="14sp" />
-
-            <Button
-                android:id="@+id/tab_work"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:background="?android:attr/selectableItemBackground"
-                android:text="@string/all_apps_work_tab"
-                android:textColor="@color/all_apps_tab_text"
-                android:textSize="14sp" />
-        </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
+        <include layout="@layout/personal_work_tabs" />
     </com.android.launcher3.allapps.FloatingHeaderView>
 
     <include
diff --git a/res/layout/live_preview_widget_cell.xml b/res/layout/live_preview_widget_cell.xml
new file mode 100644
index 0000000..7a42d19
--- /dev/null
+++ b/res/layout/live_preview_widget_cell.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.dragndrop.LivePreviewWidgetCell
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:orientation="vertical"
+    android:focusable="true"
+    android:background="?android:attr/colorPrimaryDark"
+    android:gravity="center_horizontal">
+
+    <include layout="@layout/widget_cell_content"  />
+
+</com.android.launcher3.dragndrop.LivePreviewWidgetCell>
\ No newline at end of file
diff --git a/res/layout/personal_work_tabs.xml b/res/layout/personal_work_tabs.xml
new file mode 100644
index 0000000..8f29997
--- /dev/null
+++ b/res/layout/personal_work_tabs.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+-->
+
+<com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tabs"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/all_apps_header_tab_height"
+    android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
+    android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
+    android:orientation="horizontal"
+    style="@style/TextHeadline">
+
+    <Button
+        android:id="@+id/tab_personal"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:background="?android:attr/selectableItemBackground"
+        android:text="@string/all_apps_personal_tab"
+        android:textColor="@color/all_apps_tab_text"
+        android:textSize="14sp" />
+
+    <Button
+        android:id="@+id/tab_work"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:background="?android:attr/selectableItemBackground"
+        android:text="@string/all_apps_work_tab"
+        android:textColor="@color/all_apps_tab_text"
+        android:textSize="14sp" />
+</com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip>
\ No newline at end of file
diff --git a/res/layout/secondary_launcher.xml b/res/layout/secondary_launcher.xml
index fdf4446..e3c60ec 100644
--- a/res/layout/secondary_launcher.xml
+++ b/res/layout/secondary_launcher.xml
@@ -67,7 +67,7 @@
             android:paddingTop="@dimen/all_apps_header_top_padding"
             android:orientation="vertical" >
 
-            <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
+            <com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
                 android:id="@+id/tabs"
                 android:layout_width="match_parent"
                 android:layout_height="@dimen/all_apps_header_tab_height"
@@ -97,7 +97,7 @@
                     android:textAllCaps="true"
                     android:textColor="@color/all_apps_tab_text"
                     android:textSize="14sp" />
-            </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
+            </com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip>
         </com.android.launcher3.allapps.FloatingHeaderView>
 
         <com.android.launcher3.allapps.search.AppsSearchContainerLayout
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index 923352e..c230dad 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -27,8 +27,8 @@
         android:clipToPadding="false"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingLeft="8dp"
-        android:paddingRight="8dp"
+        android:paddingLeft="16dp"
+        android:paddingRight="16dp"
         android:paddingTop="16dp"
         launcher:pageIndicator="@+id/folder_page_indicator" />
 
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index 6e7cf0f..28a8c6f 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -27,12 +27,6 @@
         android:background="?android:attr/colorPrimary"
         android:elevation="4dp">
 
-        <com.android.launcher3.widget.picker.WidgetsRecyclerView
-            android:id="@+id/widgets_list_view"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:clipToPadding="false" />
-
         <!-- Fast scroller popup -->
         <TextView
             android:id="@+id/fast_scroller_popup"
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
new file mode 100644
index 0000000..cfbb6dd
--- /dev/null
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto">
+
+    <include layout="@layout/personal_work_tabs" />
+
+    <com.android.launcher3.workprofile.PersonalWorkPagedView
+        android:id="@+id/widgets_view_pager"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_below="@+id/tabs"
+        android:clipToPadding="false"
+        android:descendantFocusability="afterDescendants"
+        launcher:pageIndicator="@+id/tabs">
+
+        <com.android.launcher3.widget.picker.WidgetsRecyclerView
+            android:id="@+id/primary_widgets_list_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:clipToPadding="false" />
+
+        <com.android.launcher3.widget.picker.WidgetsRecyclerView
+            android:id="@+id/work_widgets_list_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:clipToPadding="false" />
+
+    </com.android.launcher3.workprofile.PersonalWorkPagedView>
+
+</merge>
\ No newline at end of file
diff --git a/res/layout/widgets_full_sheet_recyclerview.xml b/res/layout/widgets_full_sheet_recyclerview.xml
new file mode 100644
index 0000000..fbe559c
--- /dev/null
+++ b/res/layout/widgets_full_sheet_recyclerview.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.widget.picker.WidgetsRecyclerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/primary_widgets_list_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:clipToPadding="false" />
\ No newline at end of file
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index b8600a6..6baf39e 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -17,17 +17,17 @@
 */
 -->
 <resources>
-    <color name="popup_color_primary_light">@android:color/system_main_50</color>
-    <color name="popup_color_secondary_light">@android:color/system_main_100</color>
-    <color name="popup_color_tertiary_light">@android:color/system_main_300</color>
-    <color name="popup_color_primary_dark">@android:color/system_main_800</color>
-    <color name="popup_color_secondary_dark">@android:color/system_main_900</color>
-    <color name="popup_color_tertiary_dark">@android:color/system_main_700</color>
+    <color name="popup_color_primary_light">@android:color/system_primary_50</color>
+    <color name="popup_color_secondary_light">@android:color/system_primary_100</color>
+    <color name="popup_color_tertiary_light">@android:color/system_primary_300</color>
+    <color name="popup_color_primary_dark">@android:color/system_primary_800</color>
+    <color name="popup_color_secondary_dark">@android:color/system_primary_900</color>
+    <color name="popup_color_tertiary_dark">@android:color/system_primary_700</color>
 
-    <color name="workspace_text_color_light">@android:color/system_main_50</color>
-    <color name="workspace_text_color_dark">@android:color/system_main_900</color>
+    <color name="workspace_text_color_light">@android:color/system_primary_50</color>
+    <color name="workspace_text_color_dark">@android:color/system_primary_900</color>
 
-    <color name="text_color_primary_dark">@android:color/system_main_50</color>
-    <color name="text_color_secondary_dark">@android:color/system_main_200</color>
-    <color name="text_color_tertiary_dark">@android:color/system_main_400</color>
+    <color name="text_color_primary_dark">@android:color/system_primary_50</color>
+    <color name="text_color_secondary_dark">@android:color/system_primary_200</color>
+    <color name="text_color_tertiary_dark">@android:color/system_primary_400</color>
 </resources>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 1ce7840..acc6466 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -149,9 +149,9 @@
     <dimen name="folder_cell_x_padding">9dp</dimen>
     <dimen name="folder_cell_y_padding">6dp</dimen>
     <dimen name="folder_child_text_size">13sp</dimen>
-    <dimen name="folder_label_padding_top">4dp</dimen>
+    <dimen name="folder_label_padding_top">12dp</dimen>
     <dimen name="folder_label_padding_bottom">12dp</dimen>
-    <dimen name="folder_label_text_size">14sp</dimen>
+    <dimen name="folder_label_text_size">16sp</dimen>
 
 <!-- Sizes for managed profile badges -->
     <dimen name="profile_badge_size">24dp</dimen>
@@ -170,7 +170,8 @@
 
 <!-- Deep shortcuts -->
     <dimen name="deep_shortcuts_elevation">9dp</dimen>
-    <dimen name="bg_popup_item_width">260dp</dimen>
+    <!-- also update deep_shortcuts_divider_width -->
+    <dimen name="bg_popup_item_width">234dp</dimen>
     <dimen name="bg_popup_item_height">56dp</dimen>
     <dimen name="bg_popup_item_condensed_height">48dp</dimen>
     <dimen name="pre_drag_view_scale">6dp</dimen>
@@ -193,7 +194,7 @@
     <!-- popup_padding_start + icon_size + 10dp -->
     <dimen name="deep_shortcuts_text_padding_start">56dp</dimen>
     <!-- popup_item_width - deep_shortcuts_text_padding_start -->
-    <dimen name="deep_shortcuts_divider_width">164dp</dimen>
+    <dimen name="deep_shortcuts_divider_width">178dp</dimen>
     <dimen name="system_shortcut_icon_size">24dp</dimen>
     <!-- popup_arrow_center_start - system_shortcut_icon_size / 2 -->
     <dimen name="system_shortcut_margin_start">16dp</dimen>
@@ -253,10 +254,15 @@
 
     <!-- Search related -->
     <dimen name="search_hero_title_size">16sp</dimen>
-    <dimen name="search_hero_subtitle_size">15sp</dimen>
+    <dimen name="search_hero_subtitle_size">14sp</dimen>
     <dimen name="search_hero_inline_button_size">12sp</dimen>
     <dimen name="search_settings_icon_size">36dp</dimen>
     <dimen name="search_settings_icon_vertical_offset">16dp</dimen>
     <dimen name="search_line_spacing">4dp</dimen>
+    <dimen name="search_decoration_corner_radius">28dp</dimen>
+    <dimen name="search_decoration_padding">1dp</dimen>
+
+<!-- Taskbar related (placeholders to compile in Launcher3 without Quickstep) -->
+    <dimen name="taskbar_size">0dp</dimen>
 
 </resources>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index e5a4335..ee4d7ec 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -53,7 +53,6 @@
 
 import com.android.launcher3.Launcher.OnResumeCallback;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
-import com.android.launcher3.allapps.AllAppsSectionDecorator;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dot.DotInfo;
 import com.android.launcher3.dragndrop.DraggableView;
@@ -84,7 +83,7 @@
  * too aggressive.
  */
 public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback,
-        IconLabelDotView, DraggableView, Reorderable, AllAppsSectionDecorator.SelfDecoratingView {
+        IconLabelDotView, DraggableView, Reorderable {
 
     private static final int DISPLAY_WORKSPACE = 0;
     private static final int DISPLAY_ALL_APPS = 1;
@@ -954,16 +953,4 @@
             setCompoundDrawables(null, newIcon, null, null);
         }
     }
-
-    @Override
-    public void decorate(int color) {
-        mHighlightColor = color;
-        invalidate();
-    }
-
-    @Override
-    public void removeDecoration() {
-        mHighlightColor = Color.TRANSPARENT;
-        invalidate();
-    }
 }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 19397b9..947388b 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -19,6 +19,7 @@
 import static android.animation.ValueAnimator.areAnimatorsEnabled;
 
 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_FOUR_COLUMNS;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -599,7 +600,9 @@
         if (child instanceof BubbleTextView) {
             BubbleTextView bubbleChild = (BubbleTextView) child;
             bubbleChild.setTextVisibility(mContainerType != HOTSEAT);
-            bubbleChild.setCenterVertically(mContainerType != HOTSEAT);
+            if (ENABLE_FOUR_COLUMNS.get()) {
+                bubbleChild.setCenterVertically(mContainerType != HOTSEAT);
+            }
         }
 
         child.setScaleX(mChildScale);
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 83a7d77..634093c 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -25,9 +25,12 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.view.Surface;
+import android.view.WindowInsets;
+import android.view.WindowManager;
 
 import com.android.launcher3.CellLayout.ContainerType;
 import com.android.launcher3.DevicePaddings.DevicePadding;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.IconShape;
 import com.android.launcher3.icons.DotRenderer;
 import com.android.launcher3.icons.IconNormalizer;
@@ -149,6 +152,10 @@
     public DotRenderer mDotRendererWorkSpace;
     public DotRenderer mDotRendererAllApps;
 
+     // Taskbar
+    public boolean isTaskbarPresent;
+    public int taskbarSize;
+
     DeviceProfile(Context context, InvariantDeviceProfile inv, Info info,
             Point minSize, Point maxSize, int width, int height, boolean isLandscape,
             boolean isMultiWindowMode, boolean transposeLayoutWithOrientation,
@@ -163,12 +170,13 @@
         // Determine sizes.
         widthPx = width;
         heightPx = height;
+        int nonFinalAvailableHeightPx;
         if (isLandscape) {
             availableWidthPx = maxSize.x;
-            availableHeightPx = minSize.y;
+            nonFinalAvailableHeightPx = minSize.y;
         } else {
             availableWidthPx = minSize.x;
-            availableHeightPx = maxSize.y;
+            nonFinalAvailableHeightPx = maxSize.y;
         }
 
         mInfo = info;
@@ -192,6 +200,22 @@
                 : Configuration.ORIENTATION_PORTRAIT);
         final Resources res = context.getResources();
 
+        isTaskbarPresent = isTablet && FeatureFlags.ENABLE_TASKBAR.get();
+        if (isTaskbarPresent) {
+            // Taskbar will be added later, but provides bottom insets that we should subtract
+            // from availableHeightPx.
+            taskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_size);
+            WindowInsets windowInsets = DisplayController.INSTANCE.get(context).getHolder(mInfo.id)
+                    .getDisplayContext().getSystemService(WindowManager.class)
+                    .getCurrentWindowMetrics().getWindowInsets();
+            int nonOverlappingTaskbarInset =
+                    taskbarSize - windowInsets.getSystemWindowInsetBottom();
+            if (nonOverlappingTaskbarInset > 0) {
+                nonFinalAvailableHeightPx -= nonOverlappingTaskbarInset;
+            }
+        }
+        availableHeightPx = nonFinalAvailableHeightPx;
+
         edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
         desiredWorkspaceLeftRightMarginPx = isVerticalBarLayout() ? 0 : edgeMarginPx;
 
@@ -648,8 +672,13 @@
     public boolean updateIsSeascape(Context context) {
         if (isVerticalBarLayout()) {
             // Check an up-to-date info.
-            boolean isSeascape = DisplayController.getDefaultDisplay(context)
-                    .createInfoForContext(context).rotation == Surface.ROTATION_270;
+            DisplayController.Info displayInfo = DisplayController.getDefaultDisplay(context)
+                    .createInfoForContext(context);
+            if (displayInfo == null) {
+                return false;
+            }
+
+            boolean isSeascape = displayInfo.rotation == Surface.ROTATION_270;
             if (mIsSeascape != isSeascape) {
                 mIsSeascape = isSeascape;
                 return true;
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index ada297f..af2d94a 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -96,6 +96,8 @@
     private static final int MIN_FLING_VELOCITY = 250;
 
     private boolean mFreeScroll = false;
+    /** If {@code false}, disable swipe gesture to switch between pages. */
+    private boolean mSwipeGestureEnabled = true;
 
     protected final int mFlingThresholdVelocity;
     protected final int mEasyFlingThresholdVelocity;
@@ -858,6 +860,14 @@
     }
 
     /**
+     * If {@code enableSwipeGesture} is {@code true}, enables swipe gesture to navigate between
+     * pages. Otherwise, disables the navigation gesture.
+     */
+    public void setSwipeGestureEnabled(boolean swipeGestureEnabled) {
+        mSwipeGestureEnabled = swipeGestureEnabled;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -879,6 +889,8 @@
          * scrolling there.
          */
 
+        if (!mSwipeGestureEnabled) return false;
+
         // Skip touch handling if there are no pages to swipe
         if (getChildCount() <= 0) return false;
 
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 51d8e66..c440303 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -605,7 +605,6 @@
                 outObj[0] = activityInfo;
                 return activityInfo.getFullResIcon(appState.getIconCache());
             }
-            if (info.getIntent() == null || info.getIntent().getPackage() == null) return null;
             List<ShortcutInfo> si = ShortcutKey.fromItemInfo(info)
                     .buildRequest(launcher)
                     .query(ShortcutRequest.ALL);
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 505e6d8..746bfba 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -67,12 +67,13 @@
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.RecyclerViewFastScroller;
 import com.android.launcher3.views.SpringRelativeLayout;
+import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
 
 /**
  * The all apps view container.
  */
 public class AllAppsContainerView extends SpringRelativeLayout implements DragSource,
-        Insettable, OnDeviceProfileChangeListener {
+        Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener {
 
     private static final float FLING_VELOCITY_MULTIPLIER = 135f;
     // Starts the springs after at least 55% of the animation has passed.
@@ -434,7 +435,7 @@
                     .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.MAIN));
             findViewById(R.id.tab_work)
                     .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.WORK));
-            onTabChanged(mViewPager.getNextPage());
+            onActivePageChanged(mViewPager.getNextPage());
         } else {
             mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
             mAH[AdapterHolder.WORK].recyclerView = null;
@@ -483,7 +484,7 @@
         if (showTabs) {
             mViewPager = (AllAppsPagedView) newView;
             mViewPager.initParentViews(this);
-            mViewPager.getPageIndicator().setContainerView(this);
+            mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
         } else {
             mViewPager = null;
         }
@@ -493,14 +494,15 @@
         return mViewPager != null ? mViewPager : findViewById(R.id.apps_list_view);
     }
 
-    public void onTabChanged(int pos) {
-        mHeader.setMainActive(pos == 0);
-        if (mAH[pos].recyclerView != null) {
-            mAH[pos].recyclerView.bindFastScrollbar();
+    @Override
+    public void onActivePageChanged(int currentActivePage) {
+        mHeader.setMainActive(currentActivePage == 0);
+        if (mAH[currentActivePage].recyclerView != null) {
+            mAH[currentActivePage].recyclerView.bindFastScrollbar();
         }
         reset(true /* animate */);
         if (mWorkModeSwitch != null) {
-            mWorkModeSwitch.setWorkTabVisible(pos == AdapterHolder.WORK
+            mWorkModeSwitch.setWorkTabVisible(currentActivePage == AdapterHolder.WORK
                     && mAllAppsStore.hasModelFlag(
                     FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION));
         }
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 715c142..5030c5e 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -42,8 +42,7 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
-import com.android.launcher3.allapps.search.SearchSectionInfo;
-import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.allapps.search.SectionDecorationInfo;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.util.PackageManagerHelper;
 
@@ -109,7 +108,7 @@
         // The index of this app not including sections
         public int appIndex = -1;
         // Search section associated to result
-        public SearchSectionInfo searchSectionInfo = null;
+        public SectionDecorationInfo sectionDecorationInfo = null;
 
         /**
          * Factory method for AppIcon AdapterItem
@@ -372,10 +371,6 @@
 
     @Override
     public void onBindViewHolder(ViewHolder holder, int position) {
-        if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()
-                && holder.itemView instanceof AllAppsSectionDecorator.SelfDecoratingView) {
-            ((AllAppsSectionDecorator.SelfDecoratingView) holder.itemView).removeDecoration();
-        }
         switch (holder.getItemViewType()) {
             case VIEW_TYPE_ICON:
                 AdapterItem adapterItem = mApps.getAdapterItems().get(position);
@@ -409,10 +404,6 @@
     @Override
     public void onViewRecycled(@NonNull ViewHolder holder) {
         super.onViewRecycled(holder);
-        if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) return;
-        if (holder.itemView instanceof AllAppsSectionDecorator.SelfDecoratingView) {
-            ((AllAppsSectionDecorator.SelfDecoratingView) holder.itemView).removeDecoration();
-        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/AllAppsPagedView.java b/src/com/android/launcher3/allapps/AllAppsPagedView.java
index e2550f5..647402b 100644
--- a/src/com/android/launcher3/allapps/AllAppsPagedView.java
+++ b/src/com/android/launcher3/allapps/AllAppsPagedView.java
@@ -17,17 +17,17 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
 
 import com.android.launcher3.PagedView;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.workprofile.PersonalWorkPagedView;
 
-public class AllAppsPagedView extends PagedView<PersonalWorkSlidingTabStrip> {
-
-    static final float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
-    static final float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
-    static final float TOUCH_SLOP_DAMPING_FACTOR = 4;
+/**
+ *  A {@link PagedView} for showing different views for the personal and work profile respectively
+ *  in the {@link AllAppsContainerView}.
+ */
+public class AllAppsPagedView extends PersonalWorkPagedView {
 
     public AllAppsPagedView(Context context) {
         this(context, null);
@@ -44,52 +44,4 @@
                         R.dimen.all_apps_header_top_padding);
         setPadding(0, topPadding, 0, 0);
     }
-
-    @Override
-    protected String getCurrentPageDescription() {
-        // Not necessary, tab-bar already has two tabs with their own descriptions.
-        return "";
-    }
-
-    @Override
-    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
-        super.onScrollChanged(l, t, oldl, oldt);
-        mPageIndicator.setScroll(l, mMaxScroll);
-    }
-
-    @Override
-    protected void determineScrollingStart(MotionEvent ev) {
-        float absDeltaX = Math.abs(ev.getX() - getDownMotionX());
-        float absDeltaY = Math.abs(ev.getY() - getDownMotionY());
-
-        if (Float.compare(absDeltaX, 0f) == 0) return;
-
-        float slope = absDeltaY / absDeltaX;
-        float theta = (float) Math.atan(slope);
-
-        if (absDeltaX > mTouchSlop || absDeltaY > mTouchSlop) {
-            cancelCurrentPageLongPress();
-        }
-
-        if (theta > MAX_SWIPE_ANGLE) {
-            return;
-        } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {
-            theta -= START_DAMPING_TOUCH_SLOP_ANGLE;
-            float extraRatio = (float)
-                    Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));
-            super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);
-        } else {
-            super.determineScrollingStart(ev);
-        }
-    }
-
-    @Override
-    public boolean hasOverlappingRendering() {
-        return false;
-    }
-
-    @Override
-    protected boolean canScroll(float absVScroll, float absHScroll) {
-        return (absHScroll > absVScroll) && super.canScroll(absVScroll, absHScroll);
-    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
index 6c95992..9328a3d 100644
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
@@ -18,16 +18,18 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Path;
 import android.graphics.RectF;
 import android.view.View;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.core.graphics.ColorUtils;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager;
-import com.android.launcher3.allapps.search.SearchSectionInfo;
+import com.android.launcher3.allapps.search.SectionDecorationInfo;
 import com.android.launcher3.util.Themes;
 
 import java.util.List;
@@ -45,52 +47,51 @@
 
     @Override
     public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
-        // Iterate through views in recylerview and draw bounds around views in the same section.
-        // Since views in the same section will follow each other, we can skip to a last view in
-        // a section to get the bounds of the section without having to iterate on every item.
-        int itemCount = parent.getChildCount();
         List<AllAppsGridAdapter.AdapterItem> adapterItems = mAppsView.getApps().getAdapterItems();
-        SectionDecorationHandler lastDecorationHandler = null;
-        int i = 0;
-        while (i < itemCount) {
+        boolean drawFallbackFocusedView = true;
+        for (int i = 0; i < parent.getChildCount(); i++) {
             View view = parent.getChildAt(i);
-            if (view instanceof SelfDecoratingView) {
-                ((SelfDecoratingView) view).removeDecoration();
-            }
             int position = parent.getChildAdapterPosition(view);
             AllAppsGridAdapter.AdapterItem adapterItem = adapterItems.get(position);
-            if (adapterItem.searchSectionInfo != null) {
-                SearchSectionInfo sectionInfo = adapterItem.searchSectionInfo;
-                int endIndex = Math.min(i + sectionInfo.getPosEnd() - position, itemCount - 1);
+            if (adapterItem.sectionDecorationInfo != null) {
+                SectionDecorationInfo sectionInfo = adapterItem.sectionDecorationInfo;
                 SectionDecorationHandler decorationHandler = sectionInfo.getDecorationHandler();
-                if (decorationHandler != lastDecorationHandler && lastDecorationHandler != null) {
-                    drawDecoration(c, lastDecorationHandler, parent);
-                }
-                lastDecorationHandler = decorationHandler;
                 if (decorationHandler != null) {
                     decorationHandler.extendBounds(view);
-                }
-
-                if (endIndex > i) {
-                    i = endIndex;
-                    continue;
+                    if (sectionInfo.isFocusedView()) {
+                        decorationHandler.onFocusDraw(c, view);
+                        drawFallbackFocusedView = false;
+                    } else {
+                        decorationHandler.onGroupDraw(c);
+                    }
                 }
             }
-            i++;
         }
-        if (lastDecorationHandler != null) {
-            drawDecoration(c, lastDecorationHandler, parent);
+        // fallback logic in case none of the SearchTarget is labeled as focused item
+        if (drawFallbackFocusedView) {
+            for (int i = 0; i < parent.getChildCount(); i++) {
+                View view = parent.getChildAt(i);
+                int position = parent.getChildAdapterPosition(view);
+                AllAppsGridAdapter.AdapterItem adapterItem = adapterItems.get(position);
+                if (adapterItem.sectionDecorationInfo != null) {
+                    SectionDecorationInfo sectionInfo = adapterItem.sectionDecorationInfo;
+                    SectionDecorationHandler decorationHandler = sectionInfo.getDecorationHandler();
+                    if (decorationHandler != null) {
+                        drawDecoration(c, decorationHandler, parent);
+                    }
+                }
+            }
         }
     }
 
-    private void drawDecoration(Canvas c, SectionDecorationHandler decorationHandler,
-            RecyclerView parent) {
-        if (decorationHandler == null) return;
+    // Fallback logic in case non of the SearchTarget is labeled as focused item.
+    private void drawDecoration(@NonNull Canvas c,
+            @NonNull SectionDecorationHandler decorationHandler,
+            @NonNull RecyclerView parent) {
         if (decorationHandler.mIsFullWidth) {
             decorationHandler.mBounds.left = parent.getPaddingLeft();
             decorationHandler.mBounds.right = parent.getWidth() - parent.getPaddingRight();
         }
-        decorationHandler.onDraw(c);
         if (mAppsView.getFloatingHeaderView().getFocusedChild() == null
                 && mAppsView.getApps().getFocusedChild() != null) {
             int index = mAppsView.getApps().getFocusedChildIndex();
@@ -109,23 +110,41 @@
      * Handles grouping and drawing of items in the same all apps sections.
      */
     public static class SectionDecorationHandler {
-        private static final int FILL_ALPHA = 0;
-
         protected RectF mBounds = new RectF();
         private final boolean mIsFullWidth;
         private final float mRadius;
 
-        protected int mFocusColor;
-        protected int mFillcolor;
+        protected final int mFocusColor; // main focused item color
+        protected final int mFillcolor; // grouping color
+
         private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        private final boolean mIsTopRound;
+        private final boolean mIsBottomRound;
+        private float [] mCorners;
+        private float mFillSpacing;
 
+        public SectionDecorationHandler(Context context, boolean isFullWidth, int fillAlpha,
+                boolean isTopRound, boolean isBottomRound) {
 
-        public SectionDecorationHandler(Context context, boolean isFullWidth) {
             mIsFullWidth = isFullWidth;
             int endScrim = Themes.getColorBackground(context);
-            mFillcolor = ColorUtils.setAlphaComponent(endScrim, FILL_ALPHA);
+            mFillcolor = ColorUtils.setAlphaComponent(endScrim, fillAlpha);
             mFocusColor = endScrim;
-            mRadius = Themes.getDialogCornerRadius(context);
+
+            mIsTopRound = isTopRound;
+            mIsBottomRound = isBottomRound;
+
+            mRadius = context.getResources().getDimensionPixelSize(
+                    R.dimen.search_decoration_corner_radius);
+            mFillSpacing = context.getResources().getDimensionPixelSize(
+                    R.dimen.search_decoration_padding);
+            mCorners = new float[]{
+                    mIsTopRound ? mRadius : 0, mIsTopRound ? mRadius : 0, // Top left radius in px
+                    mIsTopRound ? mRadius : 0, mIsTopRound ? mRadius : 0, // Top right radius in px
+                    mIsBottomRound ? mRadius : 0, mIsBottomRound ? mRadius : 0, // Bottom right
+                    mIsBottomRound ? mRadius : 0, mIsBottomRound ? mRadius : 0  // Bottom left
+            };
+
         }
 
         /**
@@ -147,9 +166,9 @@
         /**
          * Draw bounds onto canvas.
          */
-        public void onDraw(Canvas canvas) {
+        public void onGroupDraw(Canvas canvas) {
             mPaint.setColor(mFillcolor);
-            canvas.drawRoundRect(mBounds, mRadius, mRadius, mPaint);
+            onDraw(canvas);
         }
 
         /**
@@ -159,13 +178,20 @@
             if (view == null) {
                 return;
             }
-            if (view instanceof SelfDecoratingView) {
-                ((SelfDecoratingView) view).decorate(mFocusColor);
-                return;
-            }
             mPaint.setColor(mFocusColor);
-            canvas.drawRoundRect(view.getLeft(), view.getTop(),
-                    view.getRight(), view.getBottom(), mRadius, mRadius, mPaint);
+            mBounds.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+            onDraw(canvas);
+        }
+
+
+        private void onDraw(Canvas canvas) {
+            final Path path = new Path();
+            RectF finalBounds = new RectF(mBounds.left + mFillSpacing,
+                    mBounds.top + mFillSpacing,
+                    mBounds.right - mFillSpacing,
+                    mBounds.bottom - mFillSpacing);
+            path.addRoundRect(finalBounds, mCorners, Path.Direction.CW);
+            canvas.drawPath(path, mPaint);
         }
 
         /**
@@ -175,19 +201,4 @@
             mBounds.setEmpty();
         }
     }
-
-    /**
-     * An interface for a view to draw highlight indicator
-     */
-    public interface SelfDecoratingView {
-        /**
-         * Removes decorations drawing if focus is acquired by another view
-         */
-        void removeDecoration();
-
-        /**
-         * Draws highlight indicator on view.
-         */
-        void decorate(int focusColor);
-    }
 }
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 1dc10fe..fefd97a 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -20,7 +20,7 @@
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
-import com.android.launcher3.allapps.search.SearchSectionInfo;
+import com.android.launcher3.allapps.search.SectionDecorationInfo;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.util.ItemInfoMatcher;
@@ -185,7 +185,7 @@
         if (results == null || mSearchResults != results) {
             boolean same = mSearchResults != null && mSearchResults.equals(results);
             mSearchResults = results;
-            onAppsUpdated();
+            updateAdapterItems();
             return !same;
         }
         return false;
@@ -201,20 +201,11 @@
     }
 
     void updateSearchAdapterItems(ArrayList<AdapterItem> list, int offset) {
-        SearchSectionInfo lastSection = null;
         for (int i = 0; i < list.size(); i++) {
             AdapterItem adapterItem = list.get(i);
             adapterItem.position = offset + i;
             mAdapterItems.add(adapterItem);
-            if (adapterItem.searchSectionInfo != lastSection) {
-                if (adapterItem.searchSectionInfo != null) {
-                    adapterItem.searchSectionInfo.setPosStart(adapterItem.position);
-                }
-                if (lastSection != null) {
-                    lastSection.setPosEnd(adapterItem.position - 1);
-                }
-                lastSection = adapterItem.searchSectionInfo;
-            }
+
             if (adapterItem.isCountedForAccessibility()) {
                 mAccessibilityResultsCount++;
             }
@@ -266,11 +257,13 @@
         }
 
         // Recompose the set of adapter items from the current set of apps
-        updateAdapterItems();
+        if (mSearchResults == null) {
+            updateAdapterItems();
+        }
     }
 
     /**
-     * Updates the set of filtered apps with the current filter.  At this point, we expect
+     * Updates the set of filtered apps with the current filter. At this point, we expect
      * mCachedSectionNames to have been calculated for the set of all apps in mApps.
      */
     private void updateAdapterItems() {
@@ -295,16 +288,16 @@
         mFastScrollerSections.clear();
         mAdapterItems.clear();
 
-        SearchSectionInfo appSection = new SearchSectionInfo();
+        SectionDecorationInfo appSection = new SectionDecorationInfo();
         appSection.setDecorationHandler(
-                new AllAppsSectionDecorator.SectionDecorationHandler(mLauncher, true));
+                new AllAppsSectionDecorator.SectionDecorationHandler(mLauncher, true,
+                        0, false, false));
 
         // Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
         // ordered set of sections
 
         if (!hasFilter()) {
             mAccessibilityResultsCount = mApps.size();
-            appSection.setPosStart(position);
             for (AppInfo info : mApps) {
                 String sectionName = info.sectionName;
 
@@ -321,11 +314,10 @@
                     lastFastScrollerSectionInfo.fastScrollToItem = appItem;
                 }
                 if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
-                    appItem.searchSectionInfo = appSection;
+                    appItem.sectionDecorationInfo = appSection;
                 }
                 mAdapterItems.add(appItem);
             }
-            appSection.setPosEnd(mApps.isEmpty() ? appSection.getPosStart() : position - 1);
         } else {
             updateSearchAdapterItems(mSearchResults, 0);
             if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index 4876298..bc2e66c 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -87,17 +87,18 @@
     }
 
     @Override
-    public void onTabChanged(int pos) {
-        super.onTabChanged(pos);
+    public void onActivePageChanged(int currentActivePage) {
+        super.onActivePageChanged(currentActivePage);
         if (mUsingTabs) {
             // Log tab switches only when the launcher is in AllApps state
             if (mLauncher.getStateManager().getCurrentStableState() == LauncherState.ALL_APPS) {
                 mLauncher.getStatsLogManager().logger()
-                        .log(pos == AdapterHolder.WORK ? LAUNCHER_ALLAPPS_SWITCHED_TO_WORK_TAB
+                        .log(currentActivePage == AdapterHolder.WORK
+                                ? LAUNCHER_ALLAPPS_SWITCHED_TO_WORK_TAB
                                 : LAUNCHER_ALLAPPS_SWITCHED_TO_MAIN_TAB);
             }
 
-            if (pos == AdapterHolder.WORK) {
+            if (currentActivePage == AdapterHolder.WORK) {
                 WorkEduView.showWorkEduIfNeeded(mLauncher);
             } else {
                 mWorkTabListener = WorkEduView.showEduFlowIfNeeded(mLauncher, mWorkTabListener);
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java
index 84688e1..f9fb22e 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java
@@ -37,14 +37,14 @@
 
     private static final int MAX_RESULTS_COUNT = 5;
 
-    private final SearchSectionInfo mSearchSectionInfo;
+    private final SectionDecorationInfo mSearchSectionInfo;
     private final LauncherAppState mLauncherAppState;
 
     public AppsSearchPipeline(Context context, LauncherAppState launcherAppState) {
         mLauncherAppState = launcherAppState;
-        mSearchSectionInfo = new SearchSectionInfo();
+        mSearchSectionInfo = new SectionDecorationInfo();
         mSearchSectionInfo.setDecorationHandler(
-                new SectionDecorationHandler(context, true));
+                new SectionDecorationHandler(context, true, 0, true, true));
     }
 
     @Override
@@ -81,7 +81,7 @@
         ArrayList<AdapterItem> items = new ArrayList<>();
         for (int i = 0; i < matchingApps.size() && i < MAX_RESULTS_COUNT; i++) {
             AdapterItem appItem = AdapterItem.asApp(i, "", matchingApps.get(i), i);
-            appItem.searchSectionInfo = mSearchSectionInfo;
+            appItem.sectionDecorationInfo = mSearchSectionInfo;
             items.add(appItem);
         }
 
diff --git a/src/com/android/launcher3/allapps/search/SearchSectionInfo.java b/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java
similarity index 73%
rename from src/com/android/launcher3/allapps/search/SearchSectionInfo.java
rename to src/com/android/launcher3/allapps/search/SectionDecorationInfo.java
index 464df68..0b64fca 100644
--- a/src/com/android/launcher3/allapps/search/SearchSectionInfo.java
+++ b/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java
@@ -18,37 +18,30 @@
 import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler;
 
 /**
- * Info class for a search section
+ * Info class for a search section that is primarily used for decoration.
  */
-public class SearchSectionInfo {
+public class SectionDecorationInfo {
+
+    public static final int QUICK_LAUNCH = 1 << 0;
+    public static final int GROUPING = 1 << 1;
 
     private String mSectionId;
+    private boolean mFocused;
     private SectionDecorationHandler mDecorationHandler;
 
-    public int getPosStart() {
-        return mPosStart;
+    public boolean isFocusedView() {
+        return mFocused;
     }
 
-    public void setPosStart(int posStart) {
-        mPosStart = posStart;
+    public void setFocusedView(boolean focused) {
+        mFocused = focused;
     }
 
-    public int getPosEnd() {
-        return mPosEnd;
-    }
-
-    public void setPosEnd(int posEnd) {
-        mPosEnd = posEnd;
-    }
-
-    private int mPosStart;
-    private int mPosEnd;
-
-    public SearchSectionInfo() {
+    public SectionDecorationInfo() {
         this(null);
     }
 
-    public SearchSectionInfo(String sectionId) {
+    public SectionDecorationInfo(String sectionId) {
         mSectionId = sectionId;
     }
 
@@ -56,7 +49,6 @@
         mDecorationHandler = sectionDecorationHandler;
     }
 
-
     public SectionDecorationHandler getDecorationHandler() {
         return mDecorationHandler;
     }
diff --git a/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java b/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java
index a9389bc..71e10a8 100644
--- a/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java
+++ b/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java
@@ -10,7 +10,9 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.WidgetPreviewLoader;
 import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.widget.WidgetCell;
 
 /**
@@ -36,6 +38,15 @@
         mPreview = view;
     }
 
+    public RemoteViews getPreview() {
+        return mPreview;
+    }
+
+    /** Resets any resource. This should be called before recycling this view. */
+    public void reset() {
+        mPreview = null;
+    }
+
     @Override
     public void ensurePreview() {
         if (mPreview != null && mActiveRequest == null) {
@@ -49,6 +60,18 @@
         super.ensurePreview();
     }
 
+    @Override
+    public void applyFromCellItem(WidgetItem item, WidgetPreviewLoader loader) {
+        if (mPreview == null
+                && item.widgetInfo != null
+                && item.widgetInfo.previewLayout != View.NO_ID) {
+            mPreview = new RemoteViews(item.widgetInfo.provider.getPackageName(),
+                    item.widgetInfo.previewLayout);
+        }
+
+        super.applyFromCellItem(item, loader);
+    }
+
     /**
      * Generates a bitmap by inflating {@param views}.
      * @see com.android.launcher3.WidgetPreviewLoader#generateWidgetPreview
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 1266bb4..bf420d9 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 
 import androidx.annotation.Nullable;
+import androidx.slice.SliceItem;
 
 import com.android.launcher3.R;
 import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
@@ -31,8 +32,6 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.ResourceBasedOverride;
 
-import java.util.Optional;
-
 /**
  * Handles the user event logging in R+.
  *
@@ -368,6 +367,31 @@
 
         @UiEvent(doc = "User switched to Work tab in AllApps screen.")
         LAUNCHER_ALLAPPS_SWITCHED_TO_WORK_TAB(696),
+
+        @UiEvent(doc = "Default event when dedicated UI event is not available for the user action"
+                + " on slice .")
+        LAUNCHER_SLICE_DEFAULT_ACTION(700),
+
+        @UiEvent(doc = "User toggled-on a Slice item.")
+        LAUNCHER_SLICE_TOGGLE_ON(701),
+
+        @UiEvent(doc = "User toggled-off a Slice item.")
+        LAUNCHER_SLICE_TOGGLE_OFF(702),
+
+        @UiEvent(doc = "User acted on a Slice item with a button.")
+        LAUNCHER_SLICE_BUTTON_ACTION(703),
+
+        @UiEvent(doc = "User acted on a Slice item with a slider.")
+        LAUNCHER_SLICE_SLIDER_ACTION(704),
+
+        @UiEvent(doc = "User tapped on the entire row of a Slice.")
+        LAUNCHER_SLICE_CONTENT_ACTION(705),
+
+        @UiEvent(doc = "User tapped on the see more button of a Slice.")
+        LAUNCHER_SLICE_SEE_MORE_ACTION(706),
+
+        @UiEvent(doc = "User selected from a selection row of Slice.")
+        LAUNCHER_SLICE_SELECTION_ACTION(707),
         ;
 
         // ADD MORE
@@ -475,6 +499,13 @@
         }
 
         /**
+         * Sets logging fields from provided {@link SliceItem}.
+         */
+        default StatsLogger withSliceItem(SliceItem sliceItem) {
+            return this;
+        }
+
+        /**
          * Builds the final message and logs it as {@link EventEnum}.
          */
         default void log(EventEnum event) {
@@ -486,7 +517,9 @@
      */
     public StatsLogger logger() {
         StatsLogger logger = createLogger();
-        Optional.ofNullable(mInstanceId).ifPresent(logger::withInstanceId);
+        if (mInstanceId != null) {
+            return logger.withInstanceId(mInstanceId);
+        }
         return logger;
     }
 
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index e3e4b69..92b5885 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -22,7 +22,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
 import android.os.LocaleList;
@@ -137,7 +136,7 @@
         if (findAppInfo(info.componentName, info.user) != null) {
             return;
         }
-        mIconCache.getTitleAndIcon(info, activityInfo, true /* useLowResIcon */);
+        mIconCache.getTitleAndIcon(info, activityInfo, false /* useLowResIcon */);
         info.sectionName = mIndex.computeSectionName(info.title);
 
         data.add(info);
@@ -145,10 +144,9 @@
     }
 
     public void addPromiseApp(Context context, PackageInstallInfo installInfo) {
-        ApplicationInfo applicationInfo = new PackageManagerHelper(context)
-                .getApplicationInfo(installInfo.packageName, installInfo.user, 0);
         // only if not yet installed
-        if (applicationInfo == null) {
+        if (!new PackageManagerHelper(context)
+                .isAppInstalled(installInfo.packageName, installInfo.user)) {
             AppInfo info = new AppInfo(installInfo);
             mIconCache.getTitleAndIcon(info, info.usingLowResIcon());
             info.sectionName = mIndex.computeSectionName(info.title);
@@ -282,7 +280,7 @@
                 } else {
                     Intent launchIntent = AppInfo.makeLaunchIntent(info);
 
-                    mIconCache.getTitleAndIcon(applicationInfo, info, true /* useLowResIcon */);
+                    mIconCache.getTitleAndIcon(applicationInfo, info, false /* useLowResIcon */);
                     applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title);
                     applicationInfo.setProgressLevel(
                             PackageManagerHelper.getLoadingProgress(info),
diff --git a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
index e3e8769..434776c 100644
--- a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
@@ -15,7 +15,7 @@
  */
 package com.android.launcher3.model;
 
-import android.content.ComponentName;
+import android.content.Intent;
 import android.os.UserHandle;
 
 import com.android.launcher3.LauncherAppState;
@@ -66,8 +66,8 @@
         final ArrayList<WorkspaceItemInfo> updatedWorkspaceItems = new ArrayList<>();
         synchronized (dataModel) {
             dataModel.forAllWorkspaceItemInfos(mUser, si -> {
-                ComponentName cn = si.getTargetComponent();
-                if ((cn != null) && cn.getPackageName().equals(mPackageName)) {
+                Intent intent = si.getIntent();
+                if ((intent != null) && mPackageName.equals(intent.getPackage())) {
                     si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
                     si.setProgressLevel(downloadInfo);
                     updatedWorkspaceItems.add(si);
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 8215edd..1380e9e 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -15,7 +15,7 @@
  */
 package com.android.launcher3.model;
 
-import android.content.ComponentName;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 
@@ -72,9 +72,9 @@
         synchronized (dataModel) {
             final HashSet<ItemInfo> updates = new HashSet<>();
             dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> {
-                ComponentName cn = si.getTargetComponent();
-                if (si.hasPromiseIconUi() && (cn != null)
-                        && cn.getPackageName().equals(mInstallInfo.packageName)) {
+                Intent intent = si.getIntent();
+                if (si.hasPromiseIconUi() && (intent != null)
+                        && mInstallInfo.packageName.equals(intent.getPackage())) {
                     int installProgress = mInstallInfo.progress;
 
                     si.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING);
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index f13a109..7bfa3ef 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -30,6 +30,7 @@
 import android.util.Log;
 
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.BitmapInfo;
@@ -228,7 +229,8 @@
                                 isTargetValid = context.getSystemService(LauncherApps.class)
                                         .isActivityEnabled(cn, mUser);
                             }
-                            if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
+                            if (!isTargetValid && si.hasStatusFlag(
+                                    FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
                                 if (updateWorkspaceItemIntent(context, si, packageName)) {
                                     infoUpdated = true;
                                 } else if (si.hasPromiseIconUi()) {
@@ -250,8 +252,7 @@
                             }
                         }
 
-                        if (isNewApkAvailable
-                                && si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
+                        if (isNewApkAvailable) {
                             List<LauncherActivityInfo> activities = activitiesLists.get(
                                     packageName);
                             si.setProgressLevel(
@@ -260,8 +261,10 @@
                                             : PackageManagerHelper.getLoadingProgress(
                                                     activities.get(0)),
                                     PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
-                            iconCache.getTitleAndIcon(si, si.usingLowResIcon());
-                            infoUpdated = true;
+                            if (si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
+                                iconCache.getTitleAndIcon(si, si.usingLowResIcon());
+                                infoUpdated = true;
+                            }
                         }
 
                         int oldRuntimeFlags = si.runtimeStatusFlags;
@@ -353,6 +356,11 @@
      */
     private boolean updateWorkspaceItemIntent(Context context,
             WorkspaceItemInfo si, String packageName) {
+        if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+            // Do not update intent for deep shortcuts as they contain additional information
+            // about the shortcut.
+            return false;
+        }
         // Try to find the best match activity.
         Intent intent = new PackageManagerHelper(context).getAppLaunchIntent(packageName, mUser);
         if (intent != null) {
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 6fedad1..4296d32 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.util.PackageManagerHelper;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -66,6 +67,14 @@
         }
 
         if (!matchingWorkspaceItems.isEmpty()) {
+            if (mShortcuts.isEmpty()) {
+                // Verify that the app is indeed installed.
+                if (!new PackageManagerHelper(app.getContext())
+                        .isAppInstalled(mPackageName, mUser)) {
+                    // App is not installed, ignoring package events
+                    return;
+                }
+            }
             // Update the workspace to reflect the changes to updated shortcuts residing on it.
             List<String> allLauncherKnownIds = matchingWorkspaceItems.stream()
                     .map(WorkspaceItemInfo::getDeepShortcutId)
diff --git a/src/com/android/launcher3/model/data/PackageItemInfo.java b/src/com/android/launcher3/model/data/PackageItemInfo.java
index b70d0d4..7617d7e 100644
--- a/src/com/android/launcher3/model/data/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/data/PackageItemInfo.java
@@ -60,6 +60,6 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(packageName);
+        return Objects.hash(packageName, user);
     }
 }
diff --git a/src/com/android/launcher3/model/data/SearchActionItemInfo.java b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
index 25355c9..e3b3b09 100644
--- a/src/com/android/launcher3/model/data/SearchActionItemInfo.java
+++ b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
@@ -25,6 +25,9 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.logger.LauncherAtom.ItemInfo;
+import com.android.launcher3.logger.LauncherAtom.SearchActionItem;
+
 /**
  * Represents a SearchAction with in launcher
  */
@@ -39,12 +42,15 @@
     private int mFlags = 0;
     private final Icon mIcon;
 
+    // If true title does not contain any personal info and eligible for logging.
+    private final boolean mIsPersonalTitle;
     private Intent mIntent;
 
     private PendingIntent mPendingIntent;
 
     public SearchActionItemInfo(Icon icon, String packageName, UserHandle user,
-            CharSequence title) {
+            CharSequence title, boolean isPersonalTitle) {
+        mIsPersonalTitle = isPersonalTitle;
         this.user = user == null ? Process.myUserHandle() : user;
         this.title = title;
         this.container = EXTENDED_CONTAINERS;
@@ -59,6 +65,7 @@
         mFlags = info.mFlags;
         title = info.title;
         this.container = EXTENDED_CONTAINERS;
+        this.mIsPersonalTitle = info.mIsPersonalTitle;
     }
 
     /**
@@ -112,4 +119,18 @@
     public ItemInfoWithIcon clone() {
         return new SearchActionItemInfo(this);
     }
+
+    @Override
+    public ItemInfo buildProto(FolderInfo fInfo) {
+        SearchActionItem.Builder itemBuilder = SearchActionItem.newBuilder()
+                .setPackageName(mFallbackPackageName);
+
+        if (!mIsPersonalTitle) {
+            itemBuilder.setTitle(title.toString());
+        }
+        return getDefaultItemInfoBuilder()
+                .setSearchActionItem(itemBuilder)
+                .setContainerInfo(getContainerInfo())
+                .build();
+    }
 }
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index fa25114..0091af1 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -217,8 +217,8 @@
                 && sessionInfo.getAppIcon() != null
                 && !TextUtils.isEmpty(sessionInfo.getAppLabel())
                 && !promiseIconAddedForId(sessionInfo.getSessionId())
-                && new PackageManagerHelper(mAppContext).getApplicationInfo(
-                        sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), 0) == null) {
+                && !new PackageManagerHelper(mAppContext).isAppInstalled(
+                        sessionInfo.getAppPackageName(), getUserHandle(sessionInfo))) {
             ItemInstallQueue.INSTANCE.get(mAppContext)
                     .queueItem(sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
 
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 25ecea5..31adc08 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -124,7 +124,7 @@
     protected abstract boolean canInterceptTouch(MotionEvent ev);
 
     @Override
-    public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             mNoIntercept = !canInterceptTouch(ev);
             if (mNoIntercept) {
@@ -193,6 +193,8 @@
                 : reachedToState ? mToState : mFromState;
         LauncherState newToState = getTargetState(newFromState, isDragTowardPositive);
 
+        onReinitToState(newToState);
+
         if (newFromState == mFromState && newToState == mToState || (newFromState == newToState)) {
             return false;
         }
@@ -231,6 +233,12 @@
         return true;
     }
 
+    protected void onReinitToState(LauncherState newToState) {
+    }
+
+    protected void onReachedFinalState(LauncherState newToState) {
+    }
+
     protected boolean goingBetweenNormalAndOverview(LauncherState fromState,
             LauncherState toState) {
         return (fromState == NORMAL || fromState == OVERVIEW)
@@ -527,6 +535,7 @@
             mAtomicComponentsController.getAnimationPlayer().end();
             mAtomicComponentsController = null;
         }
+        onReachedFinalState(mToState);
         clearState();
         boolean shouldGoToTargetState = mGoingBetweenStates || (mToState != targetState);
         if (shouldGoToTargetState) {
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 2647d6f..098d90d 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
 import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
@@ -272,6 +273,7 @@
                         Toast.LENGTH_SHORT).show();
             }
         }
+        launcher.getStatsLogManager().logger().withItemInfo(itemInfo).log(LAUNCHER_APP_LAUNCH_TAP);
     }
 
     private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 3b7bcc2..d0e8bb1 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -29,6 +29,7 @@
 import android.util.SparseArray;
 import android.view.Display;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.Utilities;
@@ -182,20 +183,30 @@
         }
 
         /** Creates and up-to-date DisplayController.Info for the given context. */
+        @Nullable
         public Info createInfoForContext(Context context) {
-            Display display = Utilities.ATLEAST_R
-                    ? context.getDisplay()
-                    : context
-                        .getSystemService(DisplayManager.class)
-                        .getDisplay(mId);
-            return display == null
-                    ? new Info(context)
-                    : new Info(context, display);
+            Display display = Utilities.ATLEAST_R ? context.getDisplay() : null;
+            if (display == null) {
+                display = context.getSystemService(DisplayManager.class).getDisplay(mId);
+            }
+            if (display == null) {
+                return null;
+            }
+            // Refresh the Context the prevent stale DisplayMetrics.
+            Context displayContext = context.getApplicationContext().createDisplayContext(display);
+            return new Info(displayContext, display);
+        }
+
+        public Context getDisplayContext() {
+            return mDisplayContext;
         }
 
         protected void handleOnChange() {
             Info oldInfo = mInfo;
             Info newInfo = createInfoForContext(mDisplayContext);
+            if (newInfo == null) {
+                return;
+            }
 
             int change = 0;
             if (newInfo.hasDifferentSize(oldInfo)) {
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 7b26427..08ec591 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -92,6 +92,14 @@
     }
 
     /**
+     * Returns whether the target app is installed for a given user
+     */
+    public boolean isAppInstalled(String packageName, UserHandle user) {
+        ApplicationInfo info = getApplicationInfo(packageName, user, 0);
+        return info != null;
+    }
+
+    /**
      * Returns the application info for the provided package or null
      */
     public ApplicationInfo getApplicationInfo(String packageName, UserHandle user, int flags) {
@@ -105,7 +113,7 @@
     }
 
     public boolean isSafeMode() {
-        return mContext.getPackageManager().isSafeMode();
+        return mPm.isSafeMode();
     }
 
     public Intent getAppLaunchIntent(String pkg, UserHandle user) {
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 0cb8c1e..899dcf7 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -158,6 +158,14 @@
      */
     public static ArrayList<OptionItem> getOptions(Launcher launcher) {
         ArrayList<OptionItem> options = new ArrayList<>();
+        options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting,
+                LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS,
+                OptionsPopupView::startSettings));
+        if (!WidgetsModel.GO_DISABLE_WIDGETS) {
+            options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
+                    LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS,
+                    OptionsPopupView::onWidgetsClicked));
+        }
         int resString = Utilities.existsStyleWallpapers(launcher) ?
                 R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text;
         int resDrawable = Utilities.existsStyleWallpapers(launcher) ?
@@ -165,15 +173,6 @@
         options.add(new OptionItem(resString, resDrawable,
                 IGNORE,
                 OptionsPopupView::startWallpaperPicker));
-        if (!WidgetsModel.GO_DISABLE_WIDGETS) {
-            options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
-                    LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS,
-                    OptionsPopupView::onWidgetsClicked));
-        }
-        options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting,
-                LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS,
-                OptionsPopupView::startSettings));
-
         return options;
     }
 
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index a38e90d..15566a4 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -30,6 +30,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.LivePreviewWidgetCell;
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.TestProtocol;
@@ -99,12 +100,16 @@
             return false;
         }
 
+        PendingItemDragHelper dragHelper = new PendingItemDragHelper(v);
+        if (v instanceof LivePreviewWidgetCell) {
+            dragHelper.setPreview(((LivePreviewWidgetCell) v).getPreview());
+        }
+
         int[] loc = new int[2];
         getPopupContainer().getLocationInDragLayer(image, loc);
 
-        new PendingItemDragHelper(v).startDrag(
-                image.getBitmapBounds(), image.getBitmap().getWidth(), image.getWidth(),
-                new Point(loc[0], loc[1]), this, new DragOptions());
+        dragHelper.startDrag(image.getBitmapBounds(), image.getBitmap().getWidth(),
+                image.getWidth(), new Point(loc[0], loc[1]), this, new DragOptions());
         close(true);
         return true;
     }
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 3c11274..8fe42f4 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -25,6 +25,8 @@
 import android.view.View;
 import android.widget.RemoteViews;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.Launcher;
@@ -48,14 +50,14 @@
     private final PendingAddItemInfo mAddInfo;
     private int[] mEstimatedCellSize;
 
-    private RemoteViews mPreview;
+    @Nullable private RemoteViews mPreview;
 
     public PendingItemDragHelper(View view) {
         super(view);
         mAddInfo = (PendingAddItemInfo) view.getTag();
     }
 
-    public void setPreview(RemoteViews preview) {
+    public void setPreview(@Nullable RemoteViews preview) {
         mPreview = preview;
     }
 
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 3585a18..223cda2 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -36,6 +36,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.ResourceUtils;
 import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.dragndrop.LivePreviewWidgetCell;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.PackageUserKey;
@@ -136,8 +137,8 @@
     }
 
     protected WidgetCell addItemCell(ViewGroup parent) {
-        WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext()).inflate(
-                R.layout.widget_cell, parent, false);
+        LivePreviewWidgetCell widget = (LivePreviewWidgetCell) LayoutInflater.from(
+                getContext()).inflate(R.layout.live_preview_widget_cell, parent, false);
 
         widget.setOnClickListener(this);
         widget.setOnLongClickListener(this);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 03623d5..81cd73a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -22,16 +22,22 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
+import android.content.pm.LauncherApps;
 import android.graphics.Rect;
+import android.os.Process;
+import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.Pair;
+import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
@@ -43,30 +49,39 @@
 import com.android.launcher3.views.RecyclerViewFastScroller;
 import com.android.launcher3.views.TopRoundedCornerView;
 import com.android.launcher3.widget.BaseWidgetSheet;
+import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.workprofile.PersonalWorkPagedView;
+import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
+
+import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Popup for showing the full list of available widgets
  */
 public class WidgetsFullSheet extends BaseWidgetSheet
-        implements Insettable, ProviderChangedListener {
+        implements Insettable, ProviderChangedListener, OnActivePageChangedListener {
 
     private static final long DEFAULT_OPEN_DURATION = 267;
     private static final long FADE_IN_DURATION = 150;
     private static final float VERTICAL_START_POSITION = 0.3f;
 
     private final Rect mInsets = new Rect();
+    private final boolean mHasWorkProfile;
+    private final SparseArray<AdapterHolder> mAdapters = new SparseArray();
+    private final UserHandle mCurrentUser = Process.myUserHandle();
+    private final Predicate<WidgetsListBaseEntry> mPrimaryWidgetsFilter = entry ->
+            mCurrentUser.equals(entry.mPkgItem.user);
+    private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter =
+            mPrimaryWidgetsFilter.negate();
 
-    private final WidgetsListAdapter mAdapter;
-
-    private WidgetsRecyclerView mRecyclerView;
+    @Nullable private PersonalWorkPagedView mViewPager;
 
     public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        LauncherAppState apps = LauncherAppState.getInstance(context);
-        mAdapter = new WidgetsListAdapter(context,
-                LayoutInflater.from(context), apps.getWidgetCache(), apps.getIconCache(),
-                this, this);
-
+        mHasWorkProfile = context.getSystemService(LauncherApps.class).getProfiles().size() > 1;
+        mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
+        mAdapters.put(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
     }
 
     public WidgetsFullSheet(Context context, AttributeSet attrs) {
@@ -77,25 +92,51 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mContent = findViewById(R.id.container);
-
-        mRecyclerView = findViewById(R.id.widgets_list_view);
-        mRecyclerView.setAdapter(mAdapter);
-        mAdapter.setApplyBitmapDeferred(true, mRecyclerView);
-
         TopRoundedCornerView springLayout = (TopRoundedCornerView) mContent;
-        springLayout.addSpringView(R.id.widgets_list_view);
-        mRecyclerView.setEdgeEffectFactory(springLayout.createEdgeEffectFactory());
+
+        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+        int contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view
+                : R.layout.widgets_full_sheet_recyclerview;
+        layoutInflater.inflate(contentLayoutRes,  springLayout, true);
+
+        if (mHasWorkProfile) {
+            mViewPager = findViewById(R.id.widgets_view_pager);
+            // Temporarily disable swipe gesture until widgets list horizontal scrollviews per
+            // app are replaced by gird views.
+            mViewPager.setSwipeGestureEnabled(false);
+            mViewPager.initParentViews(this);
+            mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
+            mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.PRIMARY);
+            findViewById(R.id.tab_personal)
+                    .setOnClickListener((View view) -> mViewPager.snapToPage(0));
+            findViewById(R.id.tab_work)
+                    .setOnClickListener((View view) -> mViewPager.snapToPage(1));
+            springLayout.addSpringView(R.id.primary_widgets_list_view);
+            springLayout.addSpringView(R.id.work_widgets_list_view);
+        } else {
+            mViewPager = null;
+            springLayout.addSpringView(R.id.primary_widgets_list_view);
+        }
+
         onWidgetsBound();
     }
 
+    @Override
+    public void onActivePageChanged(int currentActivePage) {
+        mAdapters.get(currentActivePage).mWidgetsRecyclerView.bindFastScrollbar();
+    }
+
     @VisibleForTesting
     public WidgetsRecyclerView getRecyclerView() {
-        return mRecyclerView;
+        if (!mHasWorkProfile || mViewPager.getCurrentPage() == AdapterHolder.PRIMARY) {
+            return mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView;
+        }
+        return mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView;
     }
 
     @Override
     protected Pair<View, String> getAccessibilityTarget() {
-        return Pair.create(mRecyclerView, getContext().getString(
+        return Pair.create(getRecyclerView(), getContext().getString(
                 mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed));
     }
 
@@ -116,9 +157,10 @@
     public void setInsets(Rect insets) {
         mInsets.set(insets);
 
-        mRecyclerView.setPadding(
-                mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(),
-                mRecyclerView.getPaddingRight(), insets.bottom);
+        setBottomPadding(mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView, insets.bottom);
+        if (mHasWorkProfile) {
+            setBottomPadding(mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView, insets.bottom);
+        }
         if (insets.bottom > 0) {
             setupNavBarColor();
         } else {
@@ -129,6 +171,14 @@
         requestLayout();
     }
 
+    private void setBottomPadding(RecyclerView recyclerView, int bottomPadding) {
+        recyclerView.setPadding(
+                recyclerView.getPaddingLeft(),
+                recyclerView.getPaddingTop(),
+                recyclerView.getPaddingRight(),
+                bottomPadding);
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int widthUsed;
@@ -168,7 +218,17 @@
 
     @Override
     public void onWidgetsBound() {
-        mAdapter.setWidgets(mLauncher.getPopupDataProvider().getAllWidgets());
+        List<WidgetsListBaseEntry> allWidgets = mLauncher.getPopupDataProvider().getAllWidgets();
+
+        AdapterHolder primaryUserAdapterHolder = mAdapters.get(AdapterHolder.PRIMARY);
+        primaryUserAdapterHolder.setup(findViewById(R.id.primary_widgets_list_view));
+        primaryUserAdapterHolder.mWidgetsListAdapter.setWidgets(allWidgets);
+        if (mHasWorkProfile) {
+            AdapterHolder workUserAdapterHolder = mAdapters.get(AdapterHolder.WORK);
+            workUserAdapterHolder.setup(findViewById(R.id.work_widgets_list_view));
+            workUserAdapterHolder.mWidgetsListAdapter.setWidgets(allWidgets);
+            onActivePageChanged(mViewPager.getCurrentPage());
+        }
     }
 
     private void open(boolean animate) {
@@ -183,12 +243,9 @@
                     .setDuration(DEFAULT_OPEN_DURATION)
                     .setInterpolator(AnimationUtils.loadInterpolator(
                             getContext(), android.R.interpolator.linear_out_slow_in));
-            mRecyclerView.setLayoutFrozen(true);
             mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    mRecyclerView.setLayoutFrozen(false);
-                    mAdapter.setApplyBitmapDeferred(false, mRecyclerView);
                     mOpenCloseAnimator.removeListener(this);
                 }
             });
@@ -198,7 +255,6 @@
             });
         } else {
             setTranslationShift(TRANSLATION_SHIFT_OPENED);
-            mAdapter.setApplyBitmapDeferred(false, mRecyclerView);
             post(this::announceAccessibilityChanges);
         }
     }
@@ -218,12 +274,12 @@
         // Disable swipe down when recycler view is scrolling
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             mNoIntercept = false;
-            RecyclerViewFastScroller scroller = mRecyclerView.getScrollbar();
+            RecyclerViewFastScroller scroller = getRecyclerView().getScrollbar();
             if (scroller.getThumbOffsetY() >= 0
                     && getPopupContainer().isEventOverView(scroller, ev)) {
                 mNoIntercept = true;
             } else if (getPopupContainer().isEventOverView(mContent, ev)) {
-                mNoIntercept = !mRecyclerView.shouldContainerScroll(ev, getPopupContainer());
+                mNoIntercept = !getRecyclerView().shouldContainerScroll(ev, getPopupContainer());
             }
         }
         return super.onControllerInterceptTouchEvent(ev);
@@ -242,14 +298,14 @@
     /** Gets the {@link WidgetsRecyclerView} which shows all widgets in {@link WidgetsFullSheet}. */
     @VisibleForTesting
     public static WidgetsRecyclerView getWidgetsView(Launcher launcher) {
-        return launcher.findViewById(R.id.widgets_list_view);
+        return launcher.findViewById(R.id.primary_widgets_list_view);
     }
 
     @Override
     public void addHintCloseAnim(
             float distanceToMove, Interpolator interpolator, PendingAnimation target) {
-        target.setFloat(mRecyclerView, VIEW_TRANSLATE_Y, -distanceToMove, interpolator);
-        target.setViewAlpha(mRecyclerView, 0.5f, interpolator);
+        target.setFloat(getRecyclerView(), VIEW_TRANSLATE_Y, -distanceToMove, interpolator);
+        target.setViewAlpha(getRecyclerView(), 0.5f, interpolator);
     }
 
     @Override
@@ -257,4 +313,39 @@
         super.onCloseComplete();
         AccessibilityManagerCompat.sendStateEventToTest(getContext(), NORMAL_STATE_ORDINAL);
     }
+
+    /** A holder class for holding adapters & their corresponding recycler view. */
+    private final class AdapterHolder {
+        static final int PRIMARY = 0;
+        static final int WORK = 1;
+
+        private final int mAdapterType;
+        private final WidgetsListAdapter mWidgetsListAdapter;
+
+        private WidgetsRecyclerView mWidgetsRecyclerView;
+
+        AdapterHolder(int adapterType) {
+            mAdapterType = adapterType;
+
+            Context context = getContext();
+            LauncherAppState apps = LauncherAppState.getInstance(context);
+            mWidgetsListAdapter = new WidgetsListAdapter(
+                    context,
+                    LayoutInflater.from(context),
+                    apps.getWidgetCache(),
+                    apps.getIconCache(),
+                    /* iconClickListener= */ WidgetsFullSheet.this,
+                    /* iconLongClickListener= */ WidgetsFullSheet.this);
+            mWidgetsListAdapter.setFilter(
+                    mAdapterType == PRIMARY ? mPrimaryWidgetsFilter : mWorkWidgetsFilter);
+        }
+
+        void setup(WidgetsRecyclerView recyclerView) {
+            mWidgetsRecyclerView = recyclerView;
+            mWidgetsRecyclerView.setAdapter(mWidgetsListAdapter);
+            mWidgetsRecyclerView.setEdgeEffectFactory(
+                    ((TopRoundedCornerView) mContent).createEdgeEffectFactory());
+            mWidgetsListAdapter.setApplyBitmapDeferred(false, mWidgetsRecyclerView);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 5ec7f3b..72b4a02 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -43,6 +43,7 @@
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 /**
@@ -74,6 +75,11 @@
     private ArrayList<WidgetsListBaseEntry> mVisibleEntries = new ArrayList<>();
     @Nullable private String mWidgetsContentVisiblePackage = null;
 
+    private Predicate<WidgetsListBaseEntry> mHeaderAndSelectedContentFilter = entry ->
+            entry instanceof WidgetsListHeaderEntry
+                    || entry.mPkgItem.packageName.equals(mWidgetsContentVisiblePackage);
+    @Nullable private Predicate<WidgetsListBaseEntry> mFilter = null;
+
     public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
             WidgetPreviewLoader widgetPreviewLoader, IconCache iconCache,
             OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) {
@@ -85,6 +91,10 @@
                 new WidgetsListHeaderViewHolderBinder(layoutInflater, this::onHeaderClicked));
     }
 
+    public void setFilter(Predicate<WidgetsListBaseEntry> filter) {
+        mFilter = filter;
+    }
+
     /**
      * Defers applying bitmap on all the {@link WidgetCell} in the {@param rv}.
      *
@@ -132,8 +142,8 @@
             }
         });
         List<WidgetsListBaseEntry> newVisibleEntries = mAllEntries.stream()
-                .filter(entry -> entry instanceof WidgetsListHeaderEntry
-                        || entry.mPkgItem.packageName.equals(mWidgetsContentVisiblePackage))
+                .filter(entry -> (mFilter == null || mFilter.test(entry))
+                        && mHeaderAndSelectedContentFilter.test(entry))
                 .collect(Collectors.toList());
         mDiffReporter.process(mVisibleEntries, newVisibleEntries, mRowComparator);
     }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListRowViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListRowViewHolderBinder.java
index cec6b80..bd78777 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListRowViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListRowViewHolderBinder.java
@@ -25,6 +25,7 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.WidgetPreviewLoader;
+import com.android.launcher3.dragndrop.LivePreviewWidgetCell;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.recyclerview.ViewHolderBinder;
 import com.android.launcher3.widget.WidgetCell;
@@ -107,8 +108,8 @@
                     mLayoutInflater.inflate(R.layout.widget_list_divider, row);
                 } else {
                     // Add cell for even index
-                    WidgetCell widget = (WidgetCell) mLayoutInflater.inflate(
-                            R.layout.widget_cell, row, false);
+                    LivePreviewWidgetCell widget = (LivePreviewWidgetCell) mLayoutInflater.inflate(
+                            R.layout.live_preview_widget_cell, row, false);
 
                     // set up touch.
                     widget.setOnClickListener(mIconClickListener);
@@ -124,7 +125,8 @@
 
         // Bind the view in the widget horizontal tray region.
         for (int i = 0; i < infoList.size(); i++) {
-            WidgetCell widget = (WidgetCell) row.getChildAt(2 * i);
+            LivePreviewWidgetCell widget = (LivePreviewWidgetCell) row.getChildAt(2 * i);
+            widget.reset();
             widget.applyFromCellItem(infoList.get(i), mWidgetPreviewLoader);
             widget.setApplyBitmapDeferred(mApplyBitmapDeferred);
             widget.ensurePreview();
diff --git a/src/com/android/launcher3/workprofile/PersonalWorkPagedView.java b/src/com/android/launcher3/workprofile/PersonalWorkPagedView.java
new file mode 100644
index 0000000..8b05a0d
--- /dev/null
+++ b/src/com/android/launcher3/workprofile/PersonalWorkPagedView.java
@@ -0,0 +1,92 @@
+/*
+ * 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.workprofile;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.android.launcher3.PagedView;
+
+/**
+ *  A {@link PagedView} for showing different views for the personal and work profile respectively.
+ */
+public class PersonalWorkPagedView extends PagedView<PersonalWorkSlidingTabStrip> {
+
+    static final float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
+    static final float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
+    static final float TOUCH_SLOP_DAMPING_FACTOR = 4;
+
+    public PersonalWorkPagedView(Context context) {
+        this(context, null);
+    }
+
+    public PersonalWorkPagedView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public PersonalWorkPagedView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected String getCurrentPageDescription() {
+        // Not necessary, tab-bar already has two tabs with their own descriptions.
+        return "";
+    }
+
+    @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+        super.onScrollChanged(l, t, oldl, oldt);
+        mPageIndicator.setScroll(l, mMaxScroll);
+    }
+
+    @Override
+    protected void determineScrollingStart(MotionEvent ev) {
+        float absDeltaX = Math.abs(ev.getX() - getDownMotionX());
+        float absDeltaY = Math.abs(ev.getY() - getDownMotionY());
+
+        if (Float.compare(absDeltaX, 0f) == 0) return;
+
+        float slope = absDeltaY / absDeltaX;
+        float theta = (float) Math.atan(slope);
+
+        if (absDeltaX > mTouchSlop || absDeltaY > mTouchSlop) {
+            cancelCurrentPageLongPress();
+        }
+
+        if (theta > MAX_SWIPE_ANGLE) {
+            return;
+        } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {
+            theta -= START_DAMPING_TOUCH_SLOP_ANGLE;
+            float extraRatio = (float)
+                    Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));
+            super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);
+        } else {
+            super.determineScrollingStart(ev);
+        }
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    @Override
+    protected boolean canScroll(float absVScroll, float absHScroll) {
+        return (absHScroll > absVScroll) && super.canScroll(absVScroll, absHScroll);
+    }
+}
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
similarity index 85%
rename from src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
rename to src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
index 2de425e..3a3028f 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.launcher3.allapps;
+package com.android.launcher3.workprofile;
 
 import android.content.Context;
 import android.graphics.Canvas;
@@ -35,9 +35,6 @@
  * Supports two indicator colors, dedicated for personal and work tabs.
  */
 public class PersonalWorkSlidingTabStrip extends LinearLayout implements PageIndicator {
-    private static final int POSITION_PERSONAL = 0;
-    private static final int POSITION_WORK = 1;
-
     private final Paint mSelectedIndicatorPaint;
     private final Paint mDividerPaint;
 
@@ -47,7 +44,7 @@
     private float mScrollOffset;
     private int mSelectedPosition = 0;
 
-    private AllAppsContainerView mContainerView;
+    private OnActivePageChangedListener mOnActivePageChangedListener;
     private int mLastActivePage = 0;
     private boolean mIsRtl;
 
@@ -123,7 +120,7 @@
         float y = getHeight() - mDividerPaint.getStrokeWidth();
         canvas.drawLine(getPaddingLeft(), y, getWidth() - getPaddingRight(), y, mDividerPaint);
         canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
-            mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
+                mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
     }
 
     @Override
@@ -135,15 +132,15 @@
     @Override
     public void setActiveMarker(int activePage) {
         updateTabTextColor(activePage);
-        if (mContainerView != null && mLastActivePage != activePage) {
+        if (mOnActivePageChangedListener != null && mLastActivePage != activePage) {
             updateIndicatorPosition(activePage);
-            mContainerView.onTabChanged(activePage);
+            mOnActivePageChangedListener.onActivePageChanged(activePage);
         }
         mLastActivePage = activePage;
     }
 
-    public void setContainerView(AllAppsContainerView containerView) {
-        mContainerView = containerView;
+    public void setOnActivePageChangedListener(OnActivePageChangedListener listener) {
+        mOnActivePageChangedListener = listener;
     }
 
     @Override
@@ -153,4 +150,12 @@
     public boolean hasOverlappingRendering() {
         return false;
     }
+
+    /**
+     * Interface definition for a callback to be invoked when an active page has been changed.
+     */
+    public interface OnActivePageChangedListener {
+        /** Called when the active page has been changed. */
+        void onActivePageChanged(int currentActivePage);
+    }
 }
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 30c9b5f..a7e3472 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -9,7 +9,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.os.Process;
 import android.os.UserHandle;
 import android.util.Log;
 
@@ -115,7 +114,7 @@
                 widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache(), pm));
                 updatedItems.add(info);
             }
-            setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser);
+            setWidgetsAndShortcuts(widgetsAndShortcuts, app);
         } catch (Exception e) {
             if (!FeatureFlags.IS_STUDIO_BUILD && Utilities.isBinderSizeError(e)) {
                 // the returned value may be incomplete and will not be refreshed until the next
@@ -132,52 +131,28 @@
     }
 
     private synchronized void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts,
-            LauncherAppState app, @Nullable PackageUserKey packageUser) {
+            LauncherAppState app) {
         if (DEBUG) {
             Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
         }
 
         // Temporary list for {@link PackageItemInfos} to avoid having to go through
         // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
-        HashMap<String, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
+        HashMap<PackageUserKey, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
 
         // clear the lists.
-        if (packageUser == null) {
-            mWidgetsList.clear();
-        } else {
-            PackageItemInfo packageItem = mWidgetsList.keySet()
-                    .stream()
-                    .filter(item -> item.packageName.equals(packageUser.mPackageName))
-                    .findFirst()
-                    .orElse(null);
-            if (packageItem != null) {
-                // We want to preserve the user that was on the packageItem previously,
-                // so add it to tmpPackageItemInfos here to avoid creating a new entry.
-                tmpPackageItemInfos.put(packageItem.packageName, packageItem);
-
-                // Add the widgets for other users in the rawList as it only contains widgets for
-                // packageUser
-                List<WidgetItem> otherUserItems = mWidgetsList.remove(packageItem);
-                otherUserItems.removeIf(w -> w.user.equals(packageUser.mUser));
-                rawWidgetsShortcuts.addAll(otherUserItems);
-            }
-        }
-
-        UserHandle myUser = Process.myUserHandle();
-
+        mWidgetsList.clear();
         // add and update.
         mWidgetsList.putAll(rawWidgetsShortcuts.stream()
                 .filter(new WidgetValidityCheck(app))
                 .collect(Collectors.groupingBy(item -> {
-                    String packageName = item.componentName.getPackageName();
-                    PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName);
+                    PackageUserKey packageUserKey = new PackageUserKey(
+                            item.componentName.getPackageName(), item.user);
+                    PackageItemInfo pInfo = tmpPackageItemInfos.get(packageUserKey);
                     if (pInfo == null) {
-                        pInfo = new PackageItemInfo(packageName);
+                        pInfo = new PackageItemInfo(packageUserKey.mPackageName);
                         pInfo.user = item.user;
-                        tmpPackageItemInfos.put(packageName,  pInfo);
-                    } else if (!myUser.equals(pInfo.user)) {
-                        // Keep updating the user, until we get the primary user.
-                        pInfo.user = item.user;
+                        tmpPackageItemInfos.put(packageUserKey,  pInfo);
                     }
                     return pInfo;
                 })));
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 0c8f610..6afadfa 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -153,7 +153,7 @@
     private static final String WORKSPACE_RES_ID = "workspace";
     private static final String APPS_RES_ID = "apps_view";
     private static final String OVERVIEW_RES_ID = "overview_panel";
-    private static final String WIDGETS_RES_ID = "widgets_list_view";
+    private static final String WIDGETS_RES_ID = "primary_widgets_list_view";
     private static final String CONTEXT_MENU_RES_ID = "deep_shortcuts_container";
     public static final int WAIT_TIME_MS = 10000;
     public static final int LONG_WAIT_TIME_MS = 60000;