Merge "Shows AppPairs in previous tasks" into sc-v2-dev
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 834bc55..f9b749e 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -306,7 +306,6 @@
      * Calculates the overview grid size for the provided device configuration.
      */
     public final void calculateGridSize(Context context, DeviceProfile dp, Rect outRect) {
-        Resources res = context.getResources();
         Rect insets = dp.getInsets();
         int topMargin = dp.overviewTaskThumbnailTopMarginPx;
         int bottomMargin = getOverviewActionsHeight(context, dp);
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index f56b70b..eff59e2 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -145,9 +145,10 @@
         RunningTaskInfo runningTaskInfo = runningTaskInfos[0];
         if (mHomeTaskInfo != null && runningTaskInfo != null &&
                 mHomeTaskInfo.taskId == runningTaskInfo.taskId
-                && getTaskViewCount() == 0) {
+                && getTaskViewCount() == 0 && mLoadPlanEverApplied) {
             // Do not add a stub task if we are running over home with empty recents, so that we
             // show the empty recents message instead of showing a stub task and later removing it.
+            // Ignore empty task signal if applyLoadPlan has never run.
             return false;
         }
         return super.shouldAddStubTaskView(runningTaskInfos);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
index 033fd85..71dca66 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -153,10 +153,8 @@
 
         ObjectAnimator anim = mProgress.animateToValue(endValue);
         anim.setDuration(duration).setInterpolator(scrollInterpolatorForVelocity(velocity));
-        if (mRecentsAnimationController != null) {
-            anim.addListener(AnimatorListeners.forSuccessCallback(
-                    () -> mStateCallback.setState(STATE_FLING_FINISHED)));
-        }
+        anim.addListener(AnimatorListeners.forSuccessCallback(
+                () -> mStateCallback.setState(STATE_FLING_FINISHED)));
         anim.start();
     }
 
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 272a9a1..965c1bc 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -136,6 +136,9 @@
     protected void onPause() {
         super.onPause();
         clearBinderOverride();
+        if (mSwipeProgress.value >= 1) {
+            finishAndRemoveTask();
+        }
     }
 
     private void clearBinderOverride() {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 83eaaea..8566720 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -572,6 +572,7 @@
 
     // Keeps track of task id whose visual state should not be reset
     private int mIgnoreResetTaskId = -1;
+    protected boolean mLoadPlanEverApplied;
 
     // Variables for empty state
     private final Drawable mEmptyIcon;
@@ -1404,6 +1405,7 @@
         resetTaskVisuals();
         onTaskStackUpdated();
         updateEnabledOverlays();
+        mLoadPlanEverApplied = true;
     }
 
     private boolean isModal() {
@@ -2721,6 +2723,9 @@
         boolean isSplitPlaceholderFirstInGrid = isSplitPlaceholderFirstInGrid();
         boolean isSplitPlaceholderLastInGrid = isSplitPlaceholderLastInGrid();
         TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
+        int currentPageScroll = getScrollForPage(mCurrentPage);
+        int lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView));
+        boolean currentPageSnapsToEndOfGrid = currentPageScroll == lastGridTaskScroll;
         if (lastGridTaskView != null && lastGridTaskView.isVisibleToUser()) {
             // After dismissal, animate translation of the remaining tasks to fill any gap left
             // between the end of the grid and the clear all button. Only animate if the clear
@@ -2764,8 +2769,7 @@
                     // Shift all the tasks to make space for split placeholder.
                     longGridRowWidthDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
                 }
-            } else if (isLandscapeSplit && getScrollForPage(mCurrentPage)
-                    == getScrollForPage(indexOfChild(lastGridTaskView))) {
+            } else if (isLandscapeSplit && currentPageSnapsToEndOfGrid) {
                 // Use last task as reference point for scroll diff and snapping calculation as it's
                 // the only invariant point in landscape split screen.
                 snapToLastTask = true;
@@ -3136,14 +3140,39 @@
                                 }
                             }
 
+                            TaskView newLastGridTaskView = getLastGridTaskView();
                             if (finalSnapToLastTask) {
                                 // If snapping to last task, find the last task after dismissal.
-                                pageToSnapTo = indexOfChild(getLastGridTaskView());
+                                pageToSnapTo = indexOfChild(newLastGridTaskView);
                             } else if (taskViewIdToSnapTo != -1) {
                                 // If snapping to another page due to indices rearranging, find
                                 // the new index after dismissal & rearrange using the task view id.
                                 pageToSnapTo = indexOfChild(
                                         getTaskViewFromTaskViewId(taskViewIdToSnapTo));
+                                int taskViewToSnapToScroll = getScrollForPage(pageToSnapTo);
+                                int lastGridTaskScroll = getScrollForPage(
+                                        indexOfChild(newLastGridTaskView));
+                                if (!currentPageSnapsToEndOfGrid
+                                        && taskViewToSnapToScroll == lastGridTaskScroll) {
+                                    // If it wasn't snapped to one of the last pages, but is now
+                                    // snapped to last pages, we'll need to compensate for the
+                                    // difference as last pages' scroll is the position where
+                                    // ClearAllButton is barely invisible, instead of aligned to
+                                    // mLastComputedTaskSize.
+                                    int normalTaskEnd = mIsRtl
+                                            ? mLastComputedTaskSize.right
+                                            : mLastComputedTaskSize.left;
+                                    int lastTaskStart = mIsRtl
+                                            ? mLastComputedGridSize.left
+                                            : mLastComputedGridSize.right;
+                                    // As snapped task is not the last task, it can only be the
+                                    // second last task.
+                                    int distanceToSnappedTaskEnd =
+                                            (mPageSpacing + mLastComputedGridTaskSize.width()) * 2;
+                                    int snappedTaskEnd = lastTaskStart + (mIsRtl
+                                            ? distanceToSnappedTaskEnd : -distanceToSnappedTaskEnd);
+                                    mCurrentPageScrollDiff += snappedTaskEnd - normalTaskEnd;
+                                }
                             }
                         }
                         setCurrentPage(pageToSnapTo);
@@ -3770,7 +3799,8 @@
      * if RecentsView is in portrait or RecentsView isn't shown as grid.
      */
     private boolean isSplitPlaceholderFirstInGrid() {
-        if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()) {
+        if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()
+                || !isSplitSelectionActive()) {
             return false;
         }
         @StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
@@ -3784,7 +3814,8 @@
      * RecentsView is in portrait or RecentsView isn't shown as grid.
      */
     private boolean isSplitPlaceholderLastInGrid() {
-        if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()) {
+        if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()
+                || !isSplitSelectionActive()) {
             return false;
         }
         @StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 35c257f..1f1d57a 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -141,6 +141,7 @@
     private final CheckLongPressHelper mLongPressHelper;
 
     private final boolean mLayoutHorizontal;
+    private final boolean mIsRtl;
     private final int mIconSize;
 
     @ViewDebug.ExportedProperty(category = "launcher")
@@ -185,6 +186,8 @@
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.BubbleTextView, defStyle, 0);
         mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
+        mIsRtl = (getResources().getConfiguration().getLayoutDirection()
+                == View.LAYOUT_DIRECTION_RTL);
         DeviceProfile grid = mActivity.getDeviceProfile();
 
         mDisplay = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
@@ -581,19 +584,29 @@
         return mDotInfo != null;
     }
 
+    /**
+     * Get the icon bounds on the view depending on the layout type.
+     */
     public void getIconBounds(Rect outBounds) {
-        getIconBounds(this, outBounds, mIconSize);
+        getIconBounds(mIconSize, outBounds);
     }
 
-    public static void getIconBounds(View iconView, Rect outBounds, int iconSize) {
-        int top = iconView.getPaddingTop();
-        int left = (iconView.getWidth() - iconSize) / 2;
-        int right = left + iconSize;
-        int bottom = top + iconSize;
-        outBounds.set(left, top, right, bottom);
+    /**
+     * Get the icon bounds on the view depending on the layout type.
+     */
+    public void getIconBounds(int iconSize, Rect outBounds) {
+        Utilities.setRectToViewCenter(this, iconSize, outBounds);
+        if (mLayoutHorizontal) {
+            if (mIsRtl) {
+                outBounds.offsetTo(getWidth() - iconSize - getPaddingRight(), outBounds.top);
+            } else {
+                outBounds.offsetTo(getPaddingLeft(), outBounds.top);
+            }
+        } else {
+            outBounds.offsetTo(outBounds.left, getPaddingTop());
+        }
     }
 
-
     /**
      * Sets whether to vertically center the content.
      */
@@ -980,8 +993,7 @@
 
     @Override
     public void getWorkspaceVisualDragBounds(Rect bounds) {
-        DeviceProfile grid = mActivity.getDeviceProfile();
-        BubbleTextView.getIconBounds(this, bounds, grid.iconSizePx);
+        getIconBounds(mIconSize, bounds);
     }
 
     private int getIconSizeForDisplay(int display) {
@@ -998,7 +1010,7 @@
     }
 
     public void getSourceVisualDragBounds(Rect bounds) {
-        BubbleTextView.getIconBounds(this, bounds, getIconSizeForDisplay(mDisplay));
+        getIconBounds(mIconSize, bounds);
     }
 
     @Override
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index df09f29..9f3d445 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -483,7 +483,7 @@
                             LauncherSettings.Favorites.CONTAINER + " FROM "
                                 + Favorites.TABLE_NAME + ")";
 
-            IntArray folderIds = LauncherDbUtils.queryIntArray(db, Favorites.TABLE_NAME,
+            IntArray folderIds = LauncherDbUtils.queryIntArray(false, db, Favorites.TABLE_NAME,
                     Favorites._ID, selection, null, null);
             if (!folderIds.isEmpty()) {
                 db.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
@@ -835,8 +835,8 @@
                 case 27: {
                     // Update the favorites table so that the screen ids are ordered based on
                     // workspace page rank.
-                    IntArray finalScreens = LauncherDbUtils.queryIntArray(db, "workspaceScreens",
-                            BaseColumns._ID, null, null, "screenRank");
+                    IntArray finalScreens = LauncherDbUtils.queryIntArray(false, db,
+                            "workspaceScreens", BaseColumns._ID, null, null, "screenRank");
                     int[] original = finalScreens.toArray();
                     Arrays.sort(original);
                     String updatemap = "";
@@ -919,7 +919,7 @@
                 Log.e(TAG, "getAppWidgetIds not supported", e);
                 return;
             }
-            final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(db,
+            final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db,
                     Favorites.TABLE_NAME, Favorites.APPWIDGET_ID,
                     "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null));
             for (int widgetId : allWidgets) {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 7a38fe7..d2fe483 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -527,6 +527,18 @@
     }
 
     /**
+     * Using the view's bounds and icon size, calculate where the icon bounds will
+     * be if it was positioned at the center of the view.
+     */
+    public static void setRectToViewCenter(View iconView, int iconSize, Rect outBounds) {
+        int top = (iconView.getHeight() - iconSize) / 2;
+        int left = (iconView.getWidth() - iconSize) / 2;
+        int right = left + iconSize;
+        int bottom = top + iconSize;
+        outBounds.set(left, top, right, bottom);
+    }
+
+    /**
      * Ensures that a value is within given bounds. Specifically:
      * If value is less than lowerBound, return lowerBound; else if value is greater than upperBound,
      * return upperBound; else return value unchanged.
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 439df80..98be72a 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -628,7 +628,10 @@
     public void drawDot(Canvas canvas) {
         if (!mForceHideDot && ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0)) {
             Rect iconBounds = mDotParams.iconBounds;
-            BubbleTextView.getIconBounds(this, iconBounds, mActivity.getDeviceProfile().iconSizePx);
+
+            Utilities.setRectToViewCenter(this, mActivity.getDeviceProfile().iconSizePx,
+                    iconBounds);
+            iconBounds.offsetTo(iconBounds.left, getPaddingTop());
             float iconScale = (float) mBackground.previewSize / iconBounds.width();
             Utilities.scaleRectAboutCenter(iconBounds, iconScale);
 
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 6855bb1..b510378 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -31,11 +31,11 @@
  */
 public class LauncherDbUtils {
 
-    public static IntArray queryIntArray(SQLiteDatabase db, String tableName, String columnName,
-            String selection, String groupBy, String orderBy) {
+    public static IntArray queryIntArray(boolean distinct, SQLiteDatabase db, String tableName,
+            String columnName, String selection, String groupBy, String orderBy) {
         IntArray out = new IntArray();
-        try (Cursor c = db.query(tableName, new String[] { columnName }, selection, null,
-                groupBy, null, orderBy)) {
+        try (Cursor c = db.query(distinct, tableName, new String[] { columnName }, selection, null,
+                groupBy, null, orderBy, null)) {
             while (c.moveToNext()) {
                 out.add(c.getInt(0));
             }
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 257d732..8f607a1 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.provider;
 
+import static com.android.launcher3.model.DeviceGridState.TYPE_MULTI_DISPLAY;
 import static com.android.launcher3.model.DeviceGridState.TYPE_PHONE;
 import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
 
@@ -96,7 +97,7 @@
         try (SQLiteTransaction t = new SQLiteTransaction(db)) {
             RestoreDbTask task = new RestoreDbTask();
             task.backupWorkspace(context, db);
-            task.sanitizeDB(helper, db, new BackupManager(context));
+            task.sanitizeDB(context, helper, db, new BackupManager(context));
             task.restoreAppWidgetIdsIfExists(context);
             t.commit();
             return true;
@@ -139,7 +140,7 @@
         GridBackupTable backupTable = new GridBackupTable(context, db, idp.numDatabaseHotseatIcons,
                 idp.numColumns, idp.numRows);
         if (backupTable.restoreFromRawBackupIfAvailable(getDefaultProfileId(db))) {
-            int itemsDeleted = sanitizeDB(helper, db, backupManager);
+            int itemsDeleted = sanitizeDB(context, helper, db, backupManager);
             LauncherAppState.getInstance(context).getModel().forceReload();
             restoreAppWidgetIdsIfExists(context);
             if (itemsDeleted == 0) {
@@ -156,11 +157,12 @@
      *      the restored apps get installed.
      *   3. If the user serial for any restored profile is different than that of the previous
      *      device, update the entries to the new profile id.
+     *   4. If restored from a single display backup, remove gaps between screenIds
      *
      * @return number of items deleted.
      */
-    private int sanitizeDB(DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager)
-            throws Exception {
+    private int sanitizeDB(Context context, DatabaseHelper helper, SQLiteDatabase db,
+            BackupManager backupManager) throws Exception {
         // Primary user ids
         long myProfileId = helper.getDefaultUserSerial();
         long oldProfileId = getDefaultProfileId(db);
@@ -236,10 +238,43 @@
         if (myProfileId != oldProfileId) {
             changeDefaultColumn(db, myProfileId);
         }
+
+        // If restored from a single display backup, remove gaps between screenIds
+        if (Utilities.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE)
+                != TYPE_MULTI_DISPLAY) {
+            removeScreenIdGaps(db);
+        }
+
         return itemsDeleted;
     }
 
     /**
+     * Remove gaps between screenIds to make sure no empty pages are left in between.
+     *
+     * e.g. [0, 3, 4, 6, 7] -> [0, 1, 2, 3, 4]
+     */
+    protected void removeScreenIdGaps(SQLiteDatabase db) {
+        FileLog.d(TAG, "Removing gaps between screenIds");
+        IntArray distinctScreens = LauncherDbUtils.queryIntArray(true, db, Favorites.TABLE_NAME,
+                Favorites.SCREEN, Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP, null,
+                Favorites.SCREEN);
+        if (distinctScreens.isEmpty()) {
+            return;
+        }
+
+        StringBuilder sql = new StringBuilder("UPDATE ").append(Favorites.TABLE_NAME)
+                .append(" SET ").append(Favorites.SCREEN).append(" =\nCASE\n");
+        int screenId = distinctScreens.contains(0) ? 0 : 1;
+        for (int i = 0; i < distinctScreens.size(); i++) {
+            sql.append("WHEN ").append(Favorites.SCREEN).append(" == ")
+                    .append(distinctScreens.get(i)).append(" THEN ").append(screenId++).append("\n");
+        }
+        sql.append("ELSE screen\nEND WHERE ").append(Favorites.CONTAINER).append(" = ")
+                .append(Favorites.CONTAINER_DESKTOP).append(";");
+        db.execSQL(sql.toString());
+    }
+
+    /**
      * Updates profile id of all entries from {@param oldProfileId} to {@param newProfileId}.
      */
     protected void migrateProfileId(SQLiteDatabase db, long oldProfileId, long newProfileId) {
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 48305ee..9c8de1c 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.provider;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 
 import android.content.ContentValues;
@@ -87,6 +88,56 @@
         assertEquals(1, getCount(db, "select * from favorites where profileId = 33"));
     }
 
+    @Test
+    public void testRemoveScreenIdGaps_firstScreenEmpty() {
+        runRemoveScreenIdGapsTest(
+                new int[]{1, 2, 5, 6, 6, 7, 9, 9},
+                new int[]{1, 2, 3, 4, 4, 5, 6, 6});
+    }
+
+    @Test
+    public void testRemoveScreenIdGaps_firstScreenOccupied() {
+        runRemoveScreenIdGapsTest(
+                new int[]{0, 2, 5, 6, 6, 7, 9, 9},
+                new int[]{0, 1, 2, 3, 3, 4, 5, 5});
+    }
+
+    @Test
+    public void testRemoveScreenIdGaps_noGap() {
+        runRemoveScreenIdGapsTest(
+                new int[]{0, 1, 1, 2, 3, 3, 4, 5},
+                new int[]{0, 1, 1, 2, 3, 3, 4, 5});
+    }
+
+    private void runRemoveScreenIdGapsTest(int[] screenIds, int[] expectedScreenIds) {
+        SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase();
+        // Add some mock data
+        for (int i = 0; i < screenIds.length; i++) {
+            ContentValues values = new ContentValues();
+            values.put(Favorites._ID, i);
+            values.put(Favorites.SCREEN, screenIds[i]);
+            values.put(Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP);
+            db.insert(Favorites.TABLE_NAME, null, values);
+        }
+        // Verify items are added
+        assertEquals(screenIds.length,
+                getCount(db, "select * from favorites where container = -100"));
+
+        new RestoreDbTask().removeScreenIdGaps(db);
+
+        // verify screenId gaps removed
+        int[] resultScreenIds = new int[screenIds.length];
+        try (Cursor c = db.rawQuery(
+                "select screen from favorites where container = -100 order by screen", null)) {
+            int i = 0;
+            while (c.moveToNext()) {
+                resultScreenIds[i++] = c.getInt(0);
+            }
+        }
+
+        assertArrayEquals(expectedScreenIds, resultScreenIds);
+    }
+
     private int getCount(SQLiteDatabase db, String sql) {
         try (Cursor c = db.rawQuery(sql, null)) {
             return c.getCount();
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index aca5951..45d20e2 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -59,6 +59,15 @@
         String[] tokens = output.split("\\s+");
         mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
         mDevice.executeShellCommand("am start-user " + mProfileUserId);
+
+        mDevice.pressHome();
+        waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
+        waitForStateTransitionToEnd("Launcher internal state didn't switch to Normal",
+                () -> NORMAL);
+        waitForResumed("Launcher internal state is still Background");
+        executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
+        waitForStateTransitionToEnd("Launcher internal state didn't switch to All Apps",
+                () -> ALL_APPS);
     }
 
     @After
@@ -89,13 +98,6 @@
     @Test
     @ScreenRecord // b/202735477
     public void workTabExists() {
-        mDevice.pressHome();
-        waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
-        waitForStateTransitionToEnd("Launcher internal state didn't switch to Normal",
-                () -> NORMAL);
-        executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
-        waitForStateTransitionToEnd("Launcher internal state didn't switch to All Apps",
-                () -> ALL_APPS);
         waitForLauncherCondition("Personal tab is missing",
                 launcher -> launcher.getAppsView().isPersonalTabVisible(),
                 LauncherInstrumentation.WAIT_TIME_MS);
@@ -106,12 +108,6 @@
 
     @Test
     public void toggleWorks() {
-        mDevice.pressHome();
-        waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
-        waitForState("Launcher internal state didn't switch to Normal", () -> NORMAL);
-        executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
-        waitForState("Launcher internal state didn't switch to All Apps", () -> ALL_APPS);
-
         waitForWorkTabSetup();
 
         executeOnLauncher(launcher -> {
@@ -153,11 +149,6 @@
 
     @Test
     public void testEdu() {
-        mDevice.pressHome();
-        waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
-        waitForState("Launcher internal state didn't switch to Normal", () -> NORMAL);
-        executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
-        waitForState("Launcher internal state didn't switch to All Apps", () -> ALL_APPS);
         waitForWorkTabSetup();
         executeOnLauncher(l -> {
             l.getSharedPrefs().edit().putInt(WorkAdapterProvider.KEY_WORK_EDU_STEP, 0).commit();