Merge "Update taskbar color in onConfigurationChanged()" into sc-v2-dev
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index e14dbb1..78de300 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -289,9 +289,11 @@
                 mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget);
             }
         } else {
+            int[] taskIds = LauncherSplitScreenListener.INSTANCE.getNoCreate()
+                    .getRunningSplitTaskIds();
             // We're in staged split
-            primaryTaskTarget = targets.apps[0];
-            secondaryTaskTarget = targets.apps[1];
+            primaryTaskTarget = targets.findTask(taskIds[0]);
+            secondaryTaskTarget = targets.findTask(taskIds[1]);
             mStagedSplitBounds = new SplitConfigurationOptions.StagedSplitBounds(
                     primaryTaskTarget.screenSpaceBounds,
                     secondaryTaskTarget.screenSpaceBounds, dividerTarget.screenSpaceBounds);
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 9960fd3..a089e73 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -51,8 +51,8 @@
  */
 public class TaskViewSimulator implements TransformParams.BuilderProxy {
 
-    private final String TAG = "TaskViewSimulator";
-    private final boolean DEBUG = false;
+    private static final String TAG = "TaskViewSimulator";
+    private static final boolean DEBUG = false;
 
     private final Rect mTmpCropRect = new Rect();
     private final RectF mTempRectF = new RectF();
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 1b28c53..ac779b1 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -53,13 +53,15 @@
     @IntDef(flag = true, value = {
             HIDDEN_NON_ZERO_ROTATION,
             HIDDEN_NO_TASKS,
-            HIDDEN_NO_RECENTS})
+            HIDDEN_NO_RECENTS,
+            HIDDEN_FOCUSED_SCROLL})
     @Retention(RetentionPolicy.SOURCE)
     public @interface ActionsHiddenFlags { }
 
     public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 0;
     public static final int HIDDEN_NO_TASKS = 1 << 1;
     public static final int HIDDEN_NO_RECENTS = 1 << 2;
+    public static final int HIDDEN_FOCUSED_SCROLL = 1 << 3;
 
     @IntDef(flag = true, value = {
             DISABLED_SCROLLING,
@@ -76,7 +78,6 @@
     private static final int INDEX_VISIBILITY_ALPHA = 1;
     private static final int INDEX_FULLSCREEN_ALPHA = 2;
     private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
-    private static final int INDEX_SCROLL_ALPHA = 4;
 
     private final MultiValueAlpha mMultiValueAlpha;
     private View mSplitButton;
@@ -196,10 +197,6 @@
         return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
     }
 
-    public AlphaProperty getScrollAlpha() {
-        return mMultiValueAlpha.getProperty(INDEX_SCROLL_ALPHA);
-    }
-
     private void updateHorizontalPadding() {
         setPadding(mInsets.left, 0, mInsets.right, 0);
     }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 8c37644..b690982 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -29,7 +29,6 @@
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
-import static com.android.launcher3.Utilities.boundToRange;
 import static com.android.launcher3.Utilities.mapToRange;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.Utilities.squaredTouchSlop;
@@ -1691,28 +1690,28 @@
 
             // After scrolling, update the visible task's data
             loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
-
-            // After scrolling, update ActionsView's visibility.
-            updateActionsViewScrollAlpha();
         }
 
+        // Update ActionsView's visibility when scroll changes.
+        updateActionsViewFocusedScroll();
+
         // Update the high res thumbnail loader state
         mModel.getThumbnailCache().getHighResLoadingState().setFlingingFast(isFlingingFast);
         return scrolling;
     }
 
-    private void updateActionsViewScrollAlpha() {
-        float scrollAlpha = 1f;
+    private void updateActionsViewFocusedScroll() {
+        boolean hiddenFocusedScroll;
         if (showAsGrid()) {
             TaskView focusedTaskView = getFocusedTaskView();
-            if (focusedTaskView != null) {
-                float scrollDiff = Math.abs(getScrollForPage(indexOfChild(focusedTaskView))
-                        - mOrientationHandler.getPrimaryScroll(this));
-                float delta = (mGridSideMargin - scrollDiff) / (float) mGridSideMargin;
-                scrollAlpha = Utilities.boundToRange(delta, 0, 1);
-            }
+            hiddenFocusedScroll = focusedTaskView == null
+                    || getScrollForPage(indexOfChild(focusedTaskView))
+                    != mOrientationHandler.getPrimaryScroll(this);
+        } else {
+            hiddenFocusedScroll = false;
         }
-        mActionsView.getScrollAlpha().setValue(scrollAlpha);
+        mActionsView.updateHiddenFlags(OverviewActionsView.HIDDEN_FOCUSED_SCROLL,
+                hiddenFocusedScroll);
     }
 
     /**
@@ -1867,7 +1866,7 @@
         setCurrentTask(-1);
         mIgnoreResetTaskId = -1;
         mTaskListChangeId = -1;
-        mFocusedTaskViewId = getTaskViewCount() > 0 ? getTaskViewAt(0).getTaskViewId() : -1;
+        mFocusedTaskViewId = -1;
 
         if (mRecentsAnimationController != null) {
             if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile) {
@@ -3001,6 +3000,10 @@
                                                     : getBottomRowIdArray();
                                     int snappedIndex = taskViewIdArray.indexOf(snappedTaskViewId);
                                     taskViewIdArray.removeValue(dismissedTaskViewId);
+                                    if (finalNextFocusedTaskView != null) {
+                                        taskViewIdArray.removeValue(
+                                                finalNextFocusedTaskView.getTaskViewId());
+                                    }
                                     if (snappedIndex < taskViewIdArray.size()) {
                                         taskViewIdToSnapTo = taskViewIdArray.get(snappedIndex);
                                     } else if (snappedIndex == taskViewIdArray.size()) {
@@ -3089,9 +3092,9 @@
                             }
                         }
                         setCurrentPage(pageToSnapTo);
-                        // Update various scroll depedent UI.
+                        // Update various scroll-dependent UI.
                         dispatchScrollChanged();
-                        updateActionsViewScrollAlpha();
+                        updateActionsViewFocusedScroll();
                         if (isClearAllHidden()) {
                             mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING,
                                     false);
@@ -4560,7 +4563,7 @@
     public void setOverviewGridEnabled(boolean overviewGridEnabled) {
         if (mOverviewGridEnabled != overviewGridEnabled) {
             mOverviewGridEnabled = overviewGridEnabled;
-            updateActionsViewScrollAlpha();
+            updateActionsViewFocusedScroll();
             // Request layout to ensure scroll position is recalculated with updated mGridProgress.
             requestLayout();
         }
diff --git a/res/layout/qsb_preview.xml b/res/layout/qsb_preview.xml
new file mode 100644
index 0000000..801fb04
--- /dev/null
+++ b/res/layout/qsb_preview.xml
@@ -0,0 +1,30 @@
+<?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.qsb.QsbContainerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="0dp"
+    android:id="@id/search_container_workspace"
+    android:padding="0dp" >
+
+    <fragment
+        android:name="com.android.launcher3.qsb.QsbContainerView$QsbFragment"
+        android:layout_width="match_parent"
+        android:tag="qsb_view"
+        android:layout_height="match_parent"/>
+</com.android.launcher3.qsb.QsbContainerView>
\ No newline at end of file
diff --git a/res/raw/downgrade_schema.json b/res/raw/downgrade_schema.json
index bc25cec..14eac9f 100644
--- a/res/raw/downgrade_schema.json
+++ b/res/raw/downgrade_schema.json
@@ -2,8 +2,9 @@
   // Note: Comments are not supported in JSON schema, but android parser is lenient.
 
   // Maximum DB version supported by this schema
-  "version" : 29,
+  "version" : 30,
 
+  "downgrade_to_29" : [],
   "downgrade_to_28" : [
     "ALTER TABLE favorites RENAME TO temp_favorites;",
     "CREATE TABLE favorites(_id INTEGER PRIMARY KEY, title TEXT, intent TEXT, container INTEGER, screen INTEGER, cellX INTEGER, cellY INTEGER, spanX INTEGER, spanY INTEGER, itemType INTEGER, appWidgetId INTEGER NOT NULL DEFAULT - 1, iconPackage TEXT, iconResource TEXT, icon BLOB, appWidgetProvider TEXT, modified INTEGER NOT NULL DEFAULT 0, restored INTEGER NOT NULL DEFAULT 0, profileId INTEGER DEFAULT 0, rank INTEGER NOT NULL DEFAULT 0, options INTEGER NOT NULL DEFAULT 0);",
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 94dbe00..8e1a09c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -600,9 +600,11 @@
 
     private void initDeviceProfile(InvariantDeviceProfile idp) {
         // Load configuration-specific DeviceProfile
-        mDeviceProfile = isInMultiWindowMode()
-                ? mDeviceProfile.getMultiWindowProfile(this, getMultiWindowDisplaySize())
-                : idp.getDeviceProfile(this);
+        mDeviceProfile = idp.getDeviceProfile(this);
+        if (isInMultiWindowMode()) {
+            mDeviceProfile = mDeviceProfile.getMultiWindowProfile(
+                    this, getMultiWindowDisplaySize());
+        }
 
         onDeviceProfileInitiated();
         mModelWriter = mModel.getWriter(getDeviceProfile().isVerticalBarLayout(), true, this);
@@ -877,11 +879,11 @@
         if (dropLayout == null) {
             // it's possible that the add screen was removed because it was
             // empty and a re-bind occurred
-            mWorkspace.addExtraEmptyScreen();
-            return mWorkspace.commitExtraEmptyScreen();
-        } else {
-            return screenId;
+            mWorkspace.addExtraEmptyScreens();
+            IntSet emptyPagesAdded = mWorkspace.commitExtraEmptyScreens();
+            return emptyPagesAdded.isEmpty() ? -1 : emptyPagesAdded.getArray().get(0);
         }
+        return screenId;
     }
 
     @Thunk
@@ -2112,19 +2114,19 @@
             actualIds.add(id);
         }
         int firstId = visibleIds.getArray().get(0);
+        int pairId = mWorkspace.getPagePair(firstId);
+        // Double check that actual screenIds contains the visibleId, as empty screens are hidden
+        // in single panel.
         if (actualIds.contains(firstId)) {
             result.add(firstId);
-
-            if (mDeviceProfile.isTwoPanels) {
-                int index = actualIds.indexOf(firstId);
-                int nextIndex = (index / 2) * 2;
-                if (nextIndex == index) {
-                    nextIndex++;
-                }
-                if (nextIndex < actualIds.size()) {
-                    result.add(actualIds.get(nextIndex));
-                }
+            if (mDeviceProfile.isTwoPanels && actualIds.contains(pairId)) {
+                result.add(pairId);
             }
+        } else if (LauncherAppState.getIDP(this).supportedProfiles.stream().anyMatch(
+                deviceProfile -> deviceProfile.isTwoPanels) && actualIds.contains(pairId)) {
+            // Add the right panel if left panel is hidden when switching display, due to empty
+            // pages being hidden in single panel.
+            result.add(pairId);
         }
         return result;
     }
@@ -2181,7 +2183,7 @@
             orderedScreenIds.add(firstScreenPosition, Workspace.FIRST_SCREEN_ID);
         } else if (!FeatureFlags.QSB_ON_FIRST_SCREEN && orderedScreenIds.isEmpty()) {
             // If there are no screens, we need to have an empty screen
-            mWorkspace.addExtraEmptyScreen();
+            mWorkspace.addExtraEmptyScreens();
         }
         bindAddScreens(orderedScreenIds);
 
@@ -2196,17 +2198,7 @@
             // Some empty pages might have been removed while the phone was in a single panel
             // mode, so we want to add those empty pages back.
             IntSet screenIds = IntSet.wrap(orderedScreenIds);
-            for (int i = 0; i < orderedScreenIds.size(); i++) {
-                int screenId = orderedScreenIds.get(i);
-                // Don't add the page pair if the page is the last one and if the pair is on the
-                // right, because that would cause a bug when adding new pages.
-                // TODO: (b/196376162) remove this when the new screen id logic is fixed for two
-                //  panel in Workspace::commitExtraEmptyScreen
-                if (i == orderedScreenIds.size() - 1 && screenId % 2 == 0) {
-                    continue;
-                }
-                screenIds.add(mWorkspace.getPagePair(screenId));
-            }
+            orderedScreenIds.forEach(screenId -> screenIds.add(mWorkspace.getPagePair(screenId)));
             orderedScreenIds = screenIds.getArray();
         }
 
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 49f20c6..df09f29 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -97,7 +97,7 @@
      * Represents the schema of the database. Changes in scheme need not be backwards compatible.
      * When increasing the scheme version, ensure that downgrade_schema.json is updated
      */
-    public static final int SCHEMA_VERSION = 29;
+    public static final int SCHEMA_VERSION = 30;
 
     public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".settings";
     public static final String KEY_LAYOUT_PROVIDER_AUTHORITY = "KEY_LAYOUT_PROVIDER_AUTHORITY";
@@ -864,6 +864,11 @@
                     }
                 }
                 case 29: {
+                    // Remove widget panel related leftover workspace items
+                    db.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
+                            Favorites.SCREEN, IntArray.wrap(-777, -778)), null);
+                }
+                case 30: {
                     // DB Upgraded successfully
                     return;
                 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index b197e1c..a21c8e3 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -125,6 +125,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -644,18 +645,36 @@
         boolean childOnFinalScreen = false;
 
         if (mDragSourceInternal != null) {
+            int dragSourceChildCount = mDragSourceInternal.getChildCount();
+
+            // If the icon was dragged from Hotseat, there is no page pair
+            if (isTwoPanelEnabled() && !(mDragSourceInternal.getParent() instanceof Hotseat)) {
+                int pagePairScreenId = getPagePair(dragObject.dragInfo.screenId);
+                CellLayout pagePair = mWorkspaceScreens.get(pagePairScreenId);
+                if (pagePair == null) {
+                    // TODO: after http://b/198820019 is fixed, remove this
+                    throw new IllegalStateException("Page pair is null, "
+                            + "dragScreenId: " + dragObject.dragInfo.screenId
+                            + ", pagePairScreenId: " + pagePairScreenId
+                            + ", mScreenOrder: " + mScreenOrder.toConcatString()
+                    );
+                }
+                dragSourceChildCount += pagePair.getShortcutsAndWidgets().getChildCount();
+            }
+
             // When the drag view content is a LauncherAppWidgetHostView, we should increment the
             // drag source child count by 1 because the widget in drag has been detached from its
             // original parent, ShortcutAndWidgetContainer, and reattached to the DragView.
-            int dragSourceChildCount =
-                    dragObject.dragView.getContentView() instanceof LauncherAppWidgetHostView
-                            ? mDragSourceInternal.getChildCount() + 1
-                            : mDragSourceInternal.getChildCount();
+            if (dragObject.dragView.getContentView() instanceof LauncherAppWidgetHostView) {
+                dragSourceChildCount++;
+            }
+
             if (dragSourceChildCount == 1) {
                 lastChildOnScreen = true;
             }
             CellLayout cl = (CellLayout) mDragSourceInternal.getParent();
-            if (indexOfChild(cl) == getChildCount() - 1) {
+            if (getLeftmostVisiblePageForIndex(indexOfChild(cl))
+                    == getLeftmostVisiblePageForIndex(getPageCount() - 1)) {
                 childOnFinalScreen = true;
             }
         }
@@ -664,40 +683,83 @@
         if (lastChildOnScreen && childOnFinalScreen) {
             return;
         }
-        if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {
-            insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);
+
+        forEachExtraEmptyPageId(extraEmptyPageId -> {
+            if (!mWorkspaceScreens.containsKey(extraEmptyPageId)) {
+                insertNewWorkspaceScreen(extraEmptyPageId);
+            }
+        });
+    }
+
+    /**
+     * Inserts extra empty pages to the end of the existing workspaces.
+     * Usually we add one extra empty screen, but when two panel home is enabled we add
+     * two extra screens.
+     **/
+    public void addExtraEmptyScreens() {
+        forEachExtraEmptyPageId(extraEmptyPageId -> {
+            if (!mWorkspaceScreens.containsKey(extraEmptyPageId)) {
+                insertNewWorkspaceScreen(extraEmptyPageId);
+            }
+        });
+    }
+
+    /**
+     * Calls the consumer with all the necessary extra empty page IDs.
+     * On a normal one panel Workspace that means only EXTRA_EMPTY_SCREEN_ID,
+     * but in a two panel scenario this also includes EXTRA_EMPTY_SCREEN_SECOND_ID.
+     */
+    private void forEachExtraEmptyPageId(Consumer<Integer> callback) {
+        callback.accept(EXTRA_EMPTY_SCREEN_ID);
+        if (isTwoPanelEnabled()) {
+            callback.accept(EXTRA_EMPTY_SCREEN_SECOND_ID);
         }
     }
 
-    public boolean addExtraEmptyScreen() {
-        if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {
-            insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);
-            return true;
-        }
-        return false;
-    }
-
+    /**
+     * If two panel home is enabled we convert the last two screens that are visible at the same
+     * time. In other cases we only convert the last page.
+     */
     private void convertFinalScreenToEmptyScreenIfNecessary() {
         if (mLauncher.isWorkspaceLoading()) {
             // Invalid and dangerous operation if workspace is loading
             return;
         }
 
-        if (hasExtraEmptyScreen() || mScreenOrder.size() == 0) return;
-        int finalScreenId = mScreenOrder.get(mScreenOrder.size() - 1);
+        int panelCount = getPanelCount();
+        if (hasExtraEmptyScreens() || mScreenOrder.size() < panelCount) {
+            return;
+        }
 
-        CellLayout finalScreen = mWorkspaceScreens.get(finalScreenId);
+        SparseArray<CellLayout> finalScreens = new SparseArray<>();
 
-        // If the final screen is empty, convert it to the extra empty screen
-        if (finalScreen != null
-                && finalScreen.getShortcutsAndWidgets().getChildCount() == 0
-                && !finalScreen.isDropPending()) {
-            mWorkspaceScreens.remove(finalScreenId);
-            mScreenOrder.removeValue(finalScreenId);
+        int pageCount = mScreenOrder.size();
+        // First we add the last page(s) to the finalScreens collection. The number of final pages
+        // depends on the panel count.
+        for (int pageIndex = pageCount - panelCount; pageIndex < pageCount; pageIndex++) {
+            int screenId = mScreenOrder.get(pageIndex);
+            CellLayout screen = mWorkspaceScreens.get(screenId);
+            if (screen == null || screen.getShortcutsAndWidgets().getChildCount() != 0
+                    || screen.isDropPending()) {
+                // Final screen doesn't exist or it isn't empty or there's a pending drop
+                return;
+            }
+            finalScreens.append(screenId, screen);
+        }
 
-            // if this is the last screen, convert it to the empty screen
-            mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, finalScreen);
-            mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);
+        // Then we remove the final screens from the collections (but not from the view hierarchy)
+        // and we store them as extra empty screens.
+        for (int i = 0; i < finalScreens.size(); i++) {
+            int screenId = finalScreens.keyAt(i);
+            CellLayout screen = finalScreens.get(screenId);
+
+            mWorkspaceScreens.remove(screenId);
+            mScreenOrder.removeValue(screenId);
+
+            int newScreenId = mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)
+                    ? EXTRA_EMPTY_SCREEN_SECOND_ID : EXTRA_EMPTY_SCREEN_ID;
+            mWorkspaceScreens.put(newScreenId, screen);
+            mScreenOrder.add(newScreenId);
         }
     }
 
@@ -705,6 +767,23 @@
         removeExtraEmptyScreenDelayed(0, stripEmptyScreens, null);
     }
 
+    /**
+     * The purpose of this method is to remove empty pages from Workspace.
+     * Empty page(s) from the end of mWorkspaceScreens will always be removed. The pages with
+     * ID = Workspace.EXTRA_EMPTY_SCREEN_IDS will be removed if there are other non-empty pages.
+     * If there are no more non-empty pages left, extra empty page(s) will either stay or get added.
+     *
+     * If stripEmptyScreens is true, all empty pages (not just the ones on the end) will be removed
+     * from the Workspace, and if there are no more pages left then extra empty page(s) will be
+     * added.
+     *
+     * The number of extra empty pages is equal to what getPanelCount() returns.
+     *
+     * After the method returns the possible pages are:
+     * stripEmptyScreens = true : [non-empty pages, extra empty page(s) alone]
+     * stripEmptyScreens = false : [non-empty pages, empty pages (not in the end),
+     *                             extra empty page(s) alone]
+     */
     public void removeExtraEmptyScreenDelayed(
             int delay, boolean stripEmptyScreens, Runnable onComplete) {
         if (mLauncher.isWorkspaceLoading()) {
@@ -718,18 +797,26 @@
             return;
         }
 
+        // First we convert the last page to an extra page if the last page is empty
+        // and we don't already have an extra page.
         convertFinalScreenToEmptyScreenIfNecessary();
-        if (hasExtraEmptyScreen()) {
-            removeView(mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID));
+        // Then we remove the extra page(s) if they are not the only pages left in Workspace.
+        if (hasExtraEmptyScreens()) {
+            forEachExtraEmptyPageId(extraEmptyPageId -> {
+                removeView(mWorkspaceScreens.get(extraEmptyPageId));
+                mWorkspaceScreens.remove(extraEmptyPageId);
+                mScreenOrder.removeValue(extraEmptyPageId);
+            });
+
             setCurrentPage(getNextPage());
-            mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
-            mScreenOrder.removeValue(EXTRA_EMPTY_SCREEN_ID);
 
             // Update the page indicator to reflect the removed page.
             showPageIndicatorAtCurrentScroll();
         }
 
         if (stripEmptyScreens) {
+            // This will remove all empty pages from the Workspace. If there are no more pages left,
+            // it will add extra page(s) so that users can put items on at least one page.
             stripEmptyScreens();
         }
 
@@ -738,27 +825,56 @@
         }
     }
 
-    public boolean hasExtraEmptyScreen() {
-        return mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID) && getChildCount() > 1;
+    public boolean hasExtraEmptyScreens() {
+        return mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)
+                && getChildCount() > getPanelCount()
+                && (!isTwoPanelEnabled()
+                || mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_SECOND_ID));
     }
 
-    public int commitExtraEmptyScreen() {
+    /**
+     *  Commits the extra empty pages then returns the screen ids of those new screens.
+     *  Usually there's only one extra empty screen, but when two panel home is enabled we commit
+     *  two extra screens.
+     *
+     *  Returns an empty IntSet in case we cannot commit any new screens.
+     */
+    public IntSet commitExtraEmptyScreens() {
         if (mLauncher.isWorkspaceLoading()) {
             // Invalid and dangerous operation if workspace is loading
-            return -1;
+            return new IntSet();
         }
 
-        CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);
-        mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
-        mScreenOrder.removeValue(EXTRA_EMPTY_SCREEN_ID);
+        IntSet extraEmptyPageIds = new IntSet();
+        forEachExtraEmptyPageId(extraEmptyPageId ->
+                extraEmptyPageIds.add(commitExtraEmptyScreen(extraEmptyPageId)));
 
-        int newId = LauncherSettings.Settings.call(getContext().getContentResolver(),
+        return extraEmptyPageIds;
+    }
+
+    private int commitExtraEmptyScreen(int emptyScreenId) {
+        CellLayout cl = mWorkspaceScreens.get(emptyScreenId);
+        mWorkspaceScreens.remove(emptyScreenId);
+        mScreenOrder.removeValue(emptyScreenId);
+
+        int newScreenId = LauncherSettings.Settings.call(getContext().getContentResolver(),
                 LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
                 .getInt(LauncherSettings.Settings.EXTRA_VALUE);
-        mWorkspaceScreens.put(newId, cl);
-        mScreenOrder.add(newId);
 
-        return newId;
+
+        // When two panel home is enabled and the last page (the page on the right) doesn't
+        // have any items, then Launcher database doesn't know about this page because it was added
+        // by Launcher::bindAddScreens but wasn't inserted into the database. LauncherSettings's
+        // generate new screen ID method will return the ID for the left page,
+        // so we need to increment it.
+        if (isTwoPanelEnabled() && emptyScreenId == EXTRA_EMPTY_SCREEN_ID && newScreenId % 2 == 1) {
+            newScreenId++;
+        }
+
+        mWorkspaceScreens.put(newScreenId, cl);
+        mScreenOrder.add(newScreenId);
+
+        return newScreenId;
     }
 
     @Override
@@ -805,12 +921,8 @@
 
     /**
      * Returns the page that is shown together with the given page when two panel is enabled.
-     * @throws IllegalStateException if called while two panel home isn't enabled.
      */
     public int getPagePair(int page) {
-        if (!isTwoPanelEnabled()) {
-            throw new IllegalStateException("Two panel home isn't enabled.");
-        }
         if (page % 2 == 0) {
             return page + 1;
         } else {
@@ -859,9 +971,10 @@
             }
         }
 
-        // We enforce at least one page to add new items to. In the case that we remove the last
-        // such screen, we convert the last screen to the empty screen
-        int minScreens = 1;
+        // We enforce at least one page (two pages on two panel home) to add new items to.
+        // In the case that we remove the last such screen(s), we convert the last screen(s)
+        // to the empty screen(s)
+        int minScreens = getPanelCount();
 
         int pageShift = 0;
         for (int i = 0; i < removeScreens.size(); i++) {
@@ -871,14 +984,21 @@
             mScreenOrder.removeValue(id);
 
             if (getChildCount() > minScreens) {
+                // If this isn't the last page, just remove it
                 if (indexOfChild(cl) < currentPage) {
                     pageShift++;
                 }
                 removeView(cl);
             } else {
-                // if this is the last screen, convert it to the empty screen
-                mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, cl);
-                mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);
+                // The last page(s) should be converted into extra empty page(s)
+                int extraScreenId = isTwoPanelEnabled() && id % 2 == 1
+                        // This is the right panel in a two panel scenario
+                        ? EXTRA_EMPTY_SCREEN_SECOND_ID
+                        // This is either the last screen in a one panel scenario, or the left panel
+                        // in a two panel scenario when there are only two empty pages left
+                        : EXTRA_EMPTY_SCREEN_ID;
+                mWorkspaceScreens.put(extraScreenId, cl);
+                mScreenOrder.add(extraScreenId);
             }
         }
 
@@ -1656,8 +1776,8 @@
         }
 
         int screenId = getIdForScreen(dropTargetLayout);
-        if (screenId == EXTRA_EMPTY_SCREEN_ID) {
-            commitExtraEmptyScreen();
+        if (Workspace.EXTRA_EMPTY_SCREEN_IDS.contains(screenId)) {
+            commitExtraEmptyScreens();
         }
 
         return true;
diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java
index 44a5536..7e6e1b6 100644
--- a/src/com/android/launcher3/WorkspaceLayoutManager.java
+++ b/src/com/android/launcher3/WorkspaceLayoutManager.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.touch.ItemLongClickListener;
+import com.android.launcher3.util.IntSet;
 
 public interface WorkspaceLayoutManager {
 
@@ -30,6 +31,12 @@
 
     // The screen id used for the empty screen always present at the end.
     int EXTRA_EMPTY_SCREEN_ID = -201;
+    // The screen id used for the second empty screen always present at the end for two panel home.
+    int EXTRA_EMPTY_SCREEN_SECOND_ID = -200;
+    // The screen ids used for the empty screens at the end of the workspaces.
+    IntSet EXTRA_EMPTY_SCREEN_IDS =
+            IntSet.wrap(EXTRA_EMPTY_SCREEN_ID, EXTRA_EMPTY_SCREEN_SECOND_ID);
+
     // The is the first screen. It is always present, even if its empty.
     int FIRST_SCREEN_ID = 0;
     // This is the second page. On two panel home it is always present, even if its empty.
@@ -81,9 +88,9 @@
                 return;
             }
         }
-        if (screenId == EXTRA_EMPTY_SCREEN_ID) {
+        if (EXTRA_EMPTY_SCREEN_IDS.contains(screenId)) {
             // This should never happen
-            throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID");
+            throw new RuntimeException("Screen id should not be extra empty screen: " + screenId);
         }
 
         final CellLayout layout;
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 9faac5b..2032b26 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -45,6 +45,7 @@
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.ShortcutUtil;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.views.OptionsPopupView;
@@ -221,6 +222,9 @@
         } else if (action == ADD_TO_WORKSPACE) {
             final int[] coordinates = new int[2];
             final int screenId = findSpaceOnWorkspace(item, coordinates);
+            if (screenId == -1) {
+                return false;
+            }
             mLauncher.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
                 if (item instanceof AppInfo) {
                     WorkspaceItemInfo info = ((AppInfo) item).makeWorkspaceItem();
@@ -250,6 +254,9 @@
 
             final int[] coordinates = new int[2];
             final int screenId = findSpaceOnWorkspace(item, coordinates);
+            if (screenId == -1) {
+                return false;
+            }
             mLauncher.getModelWriter().moveItemInDatabase(info,
                     Favorites.CONTAINER_DESKTOP,
                     screenId, coordinates[0], coordinates[1]);
@@ -489,8 +496,14 @@
             return screenId;
         }
 
-        workspace.addExtraEmptyScreen();
-        screenId = workspace.commitExtraEmptyScreen();
+        workspace.addExtraEmptyScreens();
+        IntSet emptyScreenIds = workspace.commitExtraEmptyScreens();
+        if (emptyScreenIds.isEmpty()) {
+            // Couldn't create extra empty screens for some reason (e.g. Workspace is loading)
+            return -1;
+        }
+
+        screenId = emptyScreenIds.getArray().get(0);
         layout = workspace.getScreenWithId(screenId);
         found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY);
 
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index f96afa8..bf5a24b 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -68,6 +68,9 @@
             final WorkspaceItemInfo info = ((DeepShortcutView) host.getParent()).getFinalInfo();
             final int[] coordinates = new int[2];
             final int screenId = findSpaceOnWorkspace(item, coordinates);
+            if (screenId == -1) {
+                return false;
+            }
             mLauncher.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
                 mLauncher.getModelWriter().addItemToDatabase(info,
                         LauncherSettings.Favorites.CONTAINER_DESKTOP,
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 7a8b5d8..94fc708 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -473,8 +473,8 @@
         // Add first page QSB
         if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
             CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID);
-            View qsb = mHomeElementInflater.inflate(
-                    R.layout.search_container_workspace, firstScreen, false);
+            View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen,
+                    false);
             CellLayout.LayoutParams lp =
                     new CellLayout.LayoutParams(0, 0, firstScreen.getCountX(), 1);
             lp.canReorder = false;
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 7091d2b..4fdc412 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -232,9 +232,9 @@
      * Write the fields of this item to the DB
      */
     public void onAddToDatabase(ContentWriter writer) {
-        if (screenId == Workspace.EXTRA_EMPTY_SCREEN_ID) {
+        if (Workspace.EXTRA_EMPTY_SCREEN_IDS.contains(screenId)) {
             // We should never persist an item on the extra empty screen.
-            throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID");
+            throw new RuntimeException("Screen id should not be extra empty screen: " + screenId);
         }
 
         writeToValues(writer);
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index ab35bd6..4b86f65 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -17,7 +17,6 @@
 package com.android.launcher3.pm;
 
 import static com.android.launcher3.Utilities.getPrefs;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -25,7 +24,6 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
-import android.os.Build;
 import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -238,24 +236,12 @@
     }
 
     public InstallSessionTracker registerInstallTracker(InstallSessionTracker.Callback callback) {
-        InstallSessionTracker tracker = new InstallSessionTracker(this, callback);
-
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
-            mInstaller.registerSessionCallback(tracker, MODEL_EXECUTOR.getHandler());
-        } else {
-            mLauncherApps.registerPackageInstallerSessionCallback(MODEL_EXECUTOR, tracker);
-        }
+        InstallSessionTracker tracker = new InstallSessionTracker(
+                this, callback, mInstaller, mLauncherApps);
+        tracker.register();
         return tracker;
     }
 
-    void unregister(InstallSessionTracker tracker) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
-            mInstaller.unregisterSessionCallback(tracker);
-        } else {
-            mLauncherApps.unregisterPackageInstallerSessionCallback(tracker);
-        }
-    }
-
     public static UserHandle getUserHandle(SessionInfo info) {
         return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle();
     }
diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java
index b0b907a..e1b3c1a 100644
--- a/src/com/android/launcher3/pm/InstallSessionTracker.java
+++ b/src/com/android/launcher3/pm/InstallSessionTracker.java
@@ -18,9 +18,12 @@
 import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle;
 import static com.android.launcher3.pm.PackageInstallInfo.STATUS_FAILED;
 import static com.android.launcher3.pm.PackageInstallInfo.STATUS_INSTALLED;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
+import android.content.pm.LauncherApps;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
+import android.os.Build;
 import android.os.UserHandle;
 import android.util.SparseArray;
 
@@ -28,35 +31,53 @@
 
 import com.android.launcher3.util.PackageUserKey;
 
+import java.lang.ref.WeakReference;
+
 @WorkerThread
 public class InstallSessionTracker extends PackageInstaller.SessionCallback {
 
     // Lazily initialized
     private SparseArray<PackageUserKey> mActiveSessions = null;
 
-    private final InstallSessionHelper mInstallerCompat;
-    private final Callback mCallback;
+    private final WeakReference<InstallSessionHelper> mWeakHelper;
+    private final WeakReference<Callback> mWeakCallback;
+    private final PackageInstaller mInstaller;
+    private final LauncherApps mLauncherApps;
 
-    InstallSessionTracker(InstallSessionHelper installerCompat, Callback callback) {
-        mInstallerCompat = installerCompat;
-        mCallback = callback;
+
+    InstallSessionTracker(InstallSessionHelper installerCompat, Callback callback,
+            PackageInstaller installer, LauncherApps launcherApps) {
+        mWeakHelper = new WeakReference<>(installerCompat);
+        mWeakCallback = new WeakReference<>(callback);
+        mInstaller = installer;
+        mLauncherApps = launcherApps;
     }
 
     @Override
     public void onCreated(int sessionId) {
-        SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId);
+        InstallSessionHelper helper = mWeakHelper.get();
+        Callback callback = mWeakCallback.get();
+        if (callback == null || helper == null) {
+            return;
+        }
+        SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback);
         if (sessionInfo != null) {
-            mCallback.onInstallSessionCreated(PackageInstallInfo.fromInstallingState(sessionInfo));
+            callback.onInstallSessionCreated(PackageInstallInfo.fromInstallingState(sessionInfo));
         }
 
-        mInstallerCompat.tryQueuePromiseAppIcon(sessionInfo);
+        helper.tryQueuePromiseAppIcon(sessionInfo);
     }
 
     @Override
     public void onFinished(int sessionId, boolean success) {
+        InstallSessionHelper helper = mWeakHelper.get();
+        Callback callback = mWeakCallback.get();
+        if (callback == null || helper == null) {
+            return;
+        }
         // For a finished session, we can't get the session info. So use the
         // packageName from our local cache.
-        SparseArray<PackageUserKey> activeSessions = getActiveSessionMap();
+        SparseArray<PackageUserKey> activeSessions = getActiveSessionMap(helper);
         PackageUserKey key = activeSessions.get(sessionId);
         activeSessions.remove(sessionId);
 
@@ -65,21 +86,26 @@
             PackageInstallInfo info = PackageInstallInfo.fromState(
                     success ? STATUS_INSTALLED : STATUS_FAILED,
                     packageName, key.mUser);
-            mCallback.onPackageStateChanged(info);
+            callback.onPackageStateChanged(info);
 
-            if (!success && mInstallerCompat.promiseIconAddedForId(sessionId)) {
-                mCallback.onSessionFailure(packageName, key.mUser);
+            if (!success && helper.promiseIconAddedForId(sessionId)) {
+                callback.onSessionFailure(packageName, key.mUser);
                 // If it is successful, the id is removed in the the package added flow.
-                mInstallerCompat.removePromiseIconId(sessionId);
+                helper.removePromiseIconId(sessionId);
             }
         }
     }
 
     @Override
     public void onProgressChanged(int sessionId, float progress) {
-        SessionInfo session = mInstallerCompat.getVerifiedSessionInfo(sessionId);
+        InstallSessionHelper helper = mWeakHelper.get();
+        Callback callback = mWeakCallback.get();
+        if (callback == null || helper == null) {
+            return;
+        }
+        SessionInfo session = helper.getVerifiedSessionInfo(sessionId);
         if (session != null && session.getAppPackageName() != null) {
-            mCallback.onPackageStateChanged(PackageInstallInfo.fromInstallingState(session));
+            callback.onPackageStateChanged(PackageInstallInfo.fromInstallingState(session));
         }
     }
 
@@ -88,35 +114,53 @@
 
     @Override
     public void onBadgingChanged(int sessionId) {
-        SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId);
+        InstallSessionHelper helper = mWeakHelper.get();
+        Callback callback = mWeakCallback.get();
+        if (callback == null || helper == null) {
+            return;
+        }
+        SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback);
         if (sessionInfo != null) {
-            mInstallerCompat.tryQueuePromiseAppIcon(sessionInfo);
+            helper.tryQueuePromiseAppIcon(sessionInfo);
         }
     }
 
-    private SessionInfo pushSessionDisplayToLauncher(int sessionId) {
-        SessionInfo session = mInstallerCompat.getVerifiedSessionInfo(sessionId);
+    private SessionInfo pushSessionDisplayToLauncher(
+            int sessionId, InstallSessionHelper helper, Callback callback) {
+        SessionInfo session = helper.getVerifiedSessionInfo(sessionId);
         if (session != null && session.getAppPackageName() != null) {
             PackageUserKey key =
                     new PackageUserKey(session.getAppPackageName(), getUserHandle(session));
-            getActiveSessionMap().put(session.getSessionId(), key);
-            mCallback.onUpdateSessionDisplay(key, session);
+            getActiveSessionMap(helper).put(session.getSessionId(), key);
+            callback.onUpdateSessionDisplay(key, session);
             return session;
         }
         return null;
     }
 
-    private SparseArray<PackageUserKey> getActiveSessionMap() {
+    private SparseArray<PackageUserKey> getActiveSessionMap(InstallSessionHelper helper) {
         if (mActiveSessions == null) {
             mActiveSessions = new SparseArray<>();
-            mInstallerCompat.getActiveSessions().forEach(
+            helper.getActiveSessions().forEach(
                     (key, si) -> mActiveSessions.put(si.getSessionId(), key));
         }
         return mActiveSessions;
     }
 
+    void register() {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+            mInstaller.registerSessionCallback(this, MODEL_EXECUTOR.getHandler());
+        } else {
+            mLauncherApps.registerPackageInstallerSessionCallback(MODEL_EXECUTOR, this);
+        }
+    }
+
     public void unregister() {
-        mInstallerCompat.unregister(this);
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+            mInstaller.unregisterSessionCallback(this);
+        } else {
+            mLauncherApps.unregisterPackageInstallerSessionCallback(this);
+        }
     }
 
     public interface Callback {
diff --git a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
index c51f66f..8a7cae9 100644
--- a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
+++ b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
@@ -150,8 +150,8 @@
      */
     private int getNumPagesExcludingEmpty() {
         int numOfPages = mWorkspace.getChildCount();
-        if (numOfPages >= MIN_PARALLAX_PAGE_SPAN && mWorkspace.hasExtraEmptyScreen()) {
-            return numOfPages - 1;
+        if (numOfPages >= MIN_PARALLAX_PAGE_SPAN && mWorkspace.hasExtraEmptyScreens()) {
+            return numOfPages - mWorkspace.getPanelCount();
         } else {
             return numOfPages;
         }
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index a5694fc..ccbb662 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -42,7 +42,6 @@
 import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
 import com.android.launcher3.util.Wait;
 import com.android.launcher3.util.Wait.Condition;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
 import com.android.launcher3.util.rule.ShellCommandRule;
 
 import org.junit.Before;
@@ -78,7 +77,6 @@
     public void testEmpty() throws Throwable { /* needed while the broken tests are being fixed */ }
 
     @Test
-    @ScreenRecord  //b/192010616
     public void testPinWidgetNoConfig() throws Throwable {
         runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo &&
                 ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
index c9b63ae..59966ee 100644
--- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -66,7 +66,6 @@
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.testing.TestInformationProvider;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
-import com.android.launcher3.util.MainThreadInitializedObject.ObjectProvider;
 import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
 import com.android.launcher3.widget.custom.CustomWidgetManager;
 
@@ -533,12 +532,6 @@
             super.onDestroy();
         }
 
-
-        @Override
-        protected <T> T createObject(ObjectProvider<T> provider) {
-            return spy(provider.get(this));
-        }
-
         @Override
         public PackageManager getPackageManager() {
             return mPm;
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index e3f35e1..98d081b 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1561,6 +1561,7 @@
     float getWindowCornerRadius() {
         final Resources resources = getResources();
         if (!supportsRoundedCornersOnWindows(resources)) {
+            Log.d(TAG, "No rounded corners");
             return 0f;
         }
 
@@ -1579,7 +1580,8 @@
 
         // Always use the smallest radius to make sure the rounded corners will
         // completely cover the display.
-        return Math.min(topRadius, bottomRadius);
+        Log.d(TAG, "Rounded corners top: " + topRadius + " bottom: " + bottomRadius);
+        return Math.max(topRadius, bottomRadius);
     }
 
     private static boolean supportsRoundedCornersOnWindows(Resources resources) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index db2e250..288c853 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -83,9 +83,9 @@
                             + mLauncher.getTouchSlop());
 
             mLauncher.swipeToState(
-                    0,
+                    windowCornerRadius,
                     startY,
-                    0,
+                    windowCornerRadius,
                     startY - swipeHeight - mLauncher.getTouchSlop(),
                     12,
                     ALL_APPS_STATE_ORDINAL, LauncherInstrumentation.GestureScope.INSIDE);