Merge "Import translations. DO NOT MERGE ANYWHERE" into tm-qpr-dev
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 0c8543f..2a9674f 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -33,7 +33,8 @@
     <com.android.quickstep.views.TaskThumbnailView
         android:id="@+id/snapshot"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
+        android:layout_height="wrap_content"
+        android:visibility="gone" />
 
     <com.android.quickstep.views.IconView
         android:id="@+id/icon"
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 63e1b4a..178482e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -281,7 +281,7 @@
             boolean committed = !hasAnyFlag(FLAG_TRANSITION_STATE_RUNNING);
             playStateTransitionAnim(animatorSet, duration, committed);
 
-            if (committed && mLauncherState == LauncherState.QUICK_SWITCH) {
+            if (committed && mLauncherState == LauncherState.QUICK_SWITCH_FROM_HOME) {
                 // We're about to be paused, set immediately to ensure seamless handoff.
                 updateStateForFlag(FLAG_RESUMED, false);
                 applyState(0 /* duration */);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 87fa6f3..bfdf156 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -204,12 +204,11 @@
                         if (foundTaskView != null) {
                             // There is already a running app of this type, use that as second app.
                             // Get index of task (0 or 1), in case it's a GroupedTaskView
-                            int indexOfTask = foundTaskView.getIndexOfTask(foundTask.key.id);
                             TaskIdAttributeContainer taskAttributes =
-                                    foundTaskView.getTaskIdAttributeContainers()[indexOfTask];
+                                    foundTaskView.getTaskAttributesById(foundTask.key.id);
                             recents.confirmSplitSelect(
                                     foundTaskView,
-                                    taskAttributes.getTask(),
+                                    foundTask,
                                     taskAttributes.getIconView().getDrawable(),
                                     taskAttributes.getThumbnailView(),
                                     taskAttributes.getThumbnailView().getThumbnail(),
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 8fb7030..955440b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.uioverrides;
 
+import static com.android.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME;
 import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
 import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
@@ -167,12 +168,12 @@
         LauncherState fromState = mLauncher.getStateManager().getState();
         setter.setFloat(mRecentsView, TASK_THUMBNAIL_SPLASH_ALPHA,
                 toState.showTaskThumbnailSplash() ? 1f : 0f,
-                !toState.showTaskThumbnailSplash() && fromState == LauncherState.QUICK_SWITCH
+                !toState.showTaskThumbnailSplash() && fromState == QUICK_SWITCH_FROM_HOME
                         ? LINEAR : INSTANT);
 
         boolean showAsGrid = toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile());
         Interpolator gridProgressInterpolator = showAsGrid
-                ? fromState == LauncherState.QUICK_SWITCH ? LINEAR : INSTANT
+                ? fromState == QUICK_SWITCH_FROM_HOME ? LINEAR : INSTANT
                 : FINAL_FRAME;
         setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
                 gridProgressInterpolator);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index e0cb0b4..f78d9cf 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -19,7 +19,7 @@
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
-import static com.android.launcher3.LauncherState.QUICK_SWITCH;
+import static com.android.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME;
 import static com.android.launcher3.anim.AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD;
 import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
@@ -195,7 +195,7 @@
         nonOverviewBuilder.setInterpolator(ANIM_WORKSPACE_SCALE, FADE_OUT_INTERPOLATOR);
         nonOverviewBuilder.setInterpolator(ANIM_DEPTH, FADE_OUT_INTERPOLATOR);
         nonOverviewBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, TRANSLATE_OUT_INTERPOLATOR);
-        updateNonOverviewAnim(QUICK_SWITCH, nonOverviewBuilder);
+        updateNonOverviewAnim(QUICK_SWITCH_FROM_HOME, nonOverviewBuilder);
         mNonOverviewAnim.dispatchOnStart();
 
         if (mRecentsView.getTaskViewCount() == 0) {
@@ -220,7 +220,7 @@
     }
 
     private void setupOverviewAnimators() {
-        final LauncherState fromState = QUICK_SWITCH;
+        final LauncherState fromState = QUICK_SWITCH_FROM_HOME;
         final LauncherState toState = OVERVIEW;
 
         // Set RecentView's initial properties.
@@ -243,7 +243,7 @@
         // Use QuickSwitchState instead of OverviewState to determine scrim color,
         // since we need to take potential taskbar into account.
         xAnim.setViewBackgroundColor(mLauncher.getScrimView(),
-                QUICK_SWITCH.getWorkspaceScrimColor(mLauncher), LINEAR);
+                QUICK_SWITCH_FROM_HOME.getWorkspaceScrimColor(mLauncher), LINEAR);
         if (mRecentsView.getTaskViewCount() == 0) {
             xAnim.addFloat(mRecentsView, CONTENT_ALPHA, 0f, 1f, LINEAR);
         }
@@ -335,24 +335,24 @@
             } else {
                 if (velocity.y > 0) {
                     // Flinging right and down goes to quick switch.
-                    targetState = QUICK_SWITCH;
+                    targetState = QUICK_SWITCH_FROM_HOME;
                 } else {
                     // Flinging up and right could go either home or to quick switch.
                     // Determine the target based on the higher velocity.
                     targetState = Math.abs(velocity.x) > Math.abs(velocity.y)
-                        ? QUICK_SWITCH : NORMAL;
+                        ? QUICK_SWITCH_FROM_HOME : NORMAL;
                 }
             }
         } else if (horizontalFling) {
-            targetState = velocity.x > 0 ? QUICK_SWITCH : NORMAL;
+            targetState = velocity.x > 0 ? QUICK_SWITCH_FROM_HOME : NORMAL;
         } else if (verticalFling) {
-            targetState = velocity.y > 0 ? QUICK_SWITCH : NORMAL;
+            targetState = velocity.y > 0 ? QUICK_SWITCH_FROM_HOME : NORMAL;
         } else {
             // If user isn't flinging, just snap to the closest state.
             boolean passedHorizontalThreshold = mXOverviewAnim.getInterpolatedProgress() > 0.5f;
             boolean passedVerticalThreshold = mYOverviewAnim.value > 1f;
             targetState = passedHorizontalThreshold && !passedVerticalThreshold
-                    ? QUICK_SWITCH : NORMAL;
+                    ? QUICK_SWITCH_FROM_HOME : NORMAL;
         }
 
         // Animate the various components to the target state.
@@ -414,7 +414,7 @@
             nonOverviewAnim.setFloatValues(startProgress, endProgress);
             mNonOverviewAnim.dispatchOnStart();
         }
-        if (targetState == QUICK_SWITCH) {
+        if (targetState == QUICK_SWITCH_FROM_HOME) {
             // Navigating to quick switch, add scroll feedback since the first time is not
             // considered a scroll by the RecentsView.
             VibratorWrapper.INSTANCE.get(mLauncher).vibrate(
@@ -437,7 +437,7 @@
                 .withSrcState(LAUNCHER_STATE_HOME)
                 .withDstState(targetState.statsLogOrdinal)
                 .log(getLauncherAtomEvent(mStartState.statsLogOrdinal, targetState.statsLogOrdinal,
-                        targetState == QUICK_SWITCH
+                        targetState == QUICK_SWITCH_FROM_HOME
                                 ? LAUNCHER_QUICKSWITCH_RIGHT
                                 : targetState.ordinal > mStartState.ordinal
                                         ? LAUNCHER_UNKNOWN_SWIPEUP
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 56ac4c5..c5383c3 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -16,7 +16,7 @@
 package com.android.launcher3.uioverrides.touchcontrollers;
 
 import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.QUICK_SWITCH;
+import static com.android.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME;
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
@@ -87,7 +87,7 @@
         if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
             return NORMAL;
         }
-        return isDragTowardPositive ? QUICK_SWITCH : NORMAL;
+        return isDragTowardPositive ? QUICK_SWITCH_FROM_HOME : NORMAL;
     }
 
     @Override
@@ -110,7 +110,7 @@
 
         // Set RecentView's initial properties for coming in from the side.
         RECENTS_SCALE_PROPERTY.set(mOverviewPanel,
-                QUICK_SWITCH.getOverviewScaleAndOffset(mLauncher)[0] * 0.85f);
+                QUICK_SWITCH_FROM_HOME.getOverviewScaleAndOffset(mLauncher)[0] * 0.85f);
         ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mOverviewPanel, 1f);
         mOverviewPanel.setContentAlpha(1);
 
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 710de8c..89e8f51 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -18,7 +18,7 @@
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.LauncherState.QUICK_SWITCH;
+import static com.android.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME;
 import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -346,7 +346,7 @@
             case RECENTS:
                 return OVERVIEW;
             case NEW_TASK:
-                return QUICK_SWITCH;
+                return QUICK_SWITCH_FROM_HOME;
             case LAST_TASK:
                 return BACKGROUND_APP;
             case HOME:
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index b33ceca..38ac5bb 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -17,7 +17,7 @@
 package com.android.quickstep;
 
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED;
+import static com.android.quickstep.views.DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED;
 import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
 
 import android.annotation.TargetApi;
@@ -270,7 +270,7 @@
         TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size());
 
         for (GroupedRecentTaskInfo rawTask : rawTasks) {
-            if (DESKTOP_MODE_SUPPORTED && rawTask.getType() == TYPE_FREEFORM) {
+            if (DESKTOP_IS_PROTO2_ENABLED && rawTask.getType() == TYPE_FREEFORM) {
                 GroupTask desktopTask = createDesktopTask(rawTask);
                 allTasks.add(desktopTask);
                 continue;
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 44aa41a..dc265e4 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -61,20 +61,24 @@
 // TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
 public class DesktopTaskView extends TaskView {
 
+    /** Flag to indicate whether desktop windowing proto 1 is enabled */
+    private static final boolean DESKTOP_IS_PROTO1_ENABLED = SystemProperties.getBoolean(
+            "persist.wm.debug.desktop_mode", false);
+
     /** Flag to indicate whether desktop windowing proto 2 is enabled */
     public static final boolean DESKTOP_IS_PROTO2_ENABLED = SystemProperties.getBoolean(
             "persist.wm.debug.desktop_mode_2", false);
 
     /** Flags to indicate whether desktop mode is available on the device */
     public static final boolean DESKTOP_MODE_SUPPORTED =
-            SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false)
-                    || DESKTOP_IS_PROTO2_ENABLED;
+            DESKTOP_IS_PROTO1_ENABLED || DESKTOP_IS_PROTO2_ENABLED;
 
     private static final String TAG = DesktopTaskView.class.getSimpleName();
 
     private static final boolean DEBUG = true;
 
-    private List<Task> mTasks;
+    @NonNull
+    private List<Task> mTasks = new ArrayList<>();
 
     private final ArrayList<TaskThumbnailView> mSnapshotViews = new ArrayList<>();
 
@@ -108,8 +112,6 @@
                 getContext().getTheme()));
         // TODO(b/244348395): this should be wallpaper
         setBackground(mBackground);
-
-        mSnapshotViews.add(mSnapshotView);
     }
 
     @Override
@@ -129,12 +131,9 @@
             }
             Log.d(TAG, sb.toString());
         }
-        if (tasks.isEmpty()) {
-            return;
-        }
         cancelPendingLoadTasks();
 
-        mTasks = tasks;
+        mTasks = new ArrayList<>(tasks);
         mSnapshotViewMap.clear();
 
         // Ensure there are equal number of snapshot views and tasks.
@@ -207,7 +206,8 @@
         if (task != null) {
             return mSnapshotViewMap.get(task.key.id);
         }
-        return null;
+        // Return the place holder snapshot views. Callers expect this to be non-null
+        return mSnapshotView;
     }
 
     @Override
@@ -314,6 +314,11 @@
     }
 
     @Override
+    public boolean isDesktopTask() {
+        return true;
+    }
+
+    @Override
     void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
         // Sets new thumbnails based on the incoming data and refreshes the rest.
         // Create a copy of the thumbnail map, so we can track thumbnails that need refreshing.
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 61d6179..2505d91 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1550,8 +1550,14 @@
         removeView(focusedTaskView);
         mMovingTaskView = null;
         focusedTaskView.resetPersistentViewTransforms();
-        addView(focusedTaskView, 0);
-        setCurrentPage(0);
+        int frontTaskIndex = 0;
+        if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED && !focusedTaskView.isDesktopTask()) {
+            // If desktop mode is enabled, desktop task view is pinned at first position.
+            // Move focused task to position 1
+            frontTaskIndex = 1;
+        }
+        addView(focusedTaskView, frontTaskIndex);
+        setCurrentPage(frontTaskIndex);
 
         updateGridProperties();
     }
@@ -1588,7 +1594,7 @@
 
         int currentTaskId = -1;
         TaskView currentTaskView = getTaskViewAt(mCurrentPage);
-        if (currentTaskView != null) {
+        if (currentTaskView != null && currentTaskView.getTask() != null) {
             currentTaskId = currentTaskView.getTask().key.id;
         }
 
@@ -1617,6 +1623,8 @@
         // update the map of instance counts
         mFilterState.updateInstanceCountMap(taskGroups);
 
+        DesktopTask desktopTask = null;
+
         // Add views as children based on whether it's grouped or single task. Looping through
         // taskGroups backwards populates the thumbnail grid from least recent to most recent.
         for (int i = taskGroups.size() - 1; i >= 0; i--) {
@@ -1624,6 +1632,12 @@
             boolean isRemovalNeeded = stagedTaskIdToBeRemovedFromGrid != INVALID_TASK_ID
                     && groupTask.containsTask(stagedTaskIdToBeRemovedFromGrid);
 
+            if (groupTask instanceof DesktopTask) {
+                desktopTask = (DesktopTask) groupTask;
+                // Desktop task will be added separately in the end
+                continue;
+            }
+
             TaskView taskView;
             if (isRemovalNeeded && groupTask.hasMultipleTasks()) {
                 // If we need to remove half of a pair of tasks, force a TaskView with Type.SINGLE
@@ -1654,9 +1668,6 @@
 
                 ((GroupedTaskView) taskView).bind(leftTopTask, rightBottomTask, mOrientationState,
                         groupTask.mSplitBounds);
-            } else if (taskView instanceof DesktopTaskView) {
-                ((DesktopTaskView) taskView).bind(((DesktopTask) groupTask).tasks,
-                        mOrientationState);
             } else {
                 taskView.bind(groupTask.task1, mOrientationState);
             }
@@ -1669,6 +1680,14 @@
 
         if (!taskGroups.isEmpty()) {
             addView(mClearAllButton);
+
+            if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
+                TaskView taskView = getTaskViewFromPool(TaskView.Type.DESKTOP);
+                // Always add a desktop task to the first position. Even if it is empty
+                addView(taskView, 0);
+                ArrayList<Task> tasks = desktopTask != null ? desktopTask.tasks : new ArrayList<>();
+                ((DesktopTaskView) taskView).bind(tasks, mOrientationState);
+            }
         }
 
         // Keep same previous focused task
@@ -1676,6 +1695,12 @@
         // If the list changed, maybe the focused task doesn't exist anymore
         if (newFocusedTaskView == null && getTaskViewCount() > 0) {
             newFocusedTaskView = getTaskViewAt(0);
+            // Check if the first task is the desktop.
+            // If first task is desktop, try to find another task to set as the focused task
+            if (newFocusedTaskView != null && newFocusedTaskView.isDesktopTask()
+                    && getTaskViewCount() > 1) {
+                newFocusedTaskView = getTaskViewAt(1);
+            }
         }
         mFocusedTaskViewId = newFocusedTaskView != null ?
                 newFocusedTaskView.getTaskViewId() : -1;
@@ -1709,7 +1734,12 @@
             if (runningTaskId != -1) {
                 targetPage = indexOfChild(newRunningTaskView);
             } else if (getTaskViewCount() > 0) {
-                targetPage = indexOfChild(requireTaskViewAt(0));
+                TaskView taskView = requireTaskViewAt(0);
+                // If first task id desktop, try to find another task to set the target page
+                if (taskView.isDesktopTask() && getTaskViewCount() > 1) {
+                    taskView = requireTaskViewAt(1);
+                }
+                targetPage = indexOfChild(taskView);
             }
         }
         if (targetPage != -1 && mCurrentPage != targetPage) {
@@ -2141,6 +2171,9 @@
         for (int i = 0; i < getTaskViewCount(); i++) {
             TaskView taskView = requireTaskViewAt(i);
             Task task = taskView.getTask();
+            if (task == null) {
+                continue;
+            }
             int index = indexOfChild(taskView);
             boolean visible;
             if (showAsGrid()) {
@@ -2715,6 +2748,8 @@
         TaskView homeTaskView = getHomeTaskView();
         TaskView nextFocusedTaskView = null;
 
+        int desktopTaskIndex = Integer.MAX_VALUE;
+
         if (!isTaskDismissal) {
             mTopRowIdSet.clear();
         }
@@ -2741,6 +2776,14 @@
                     // If focused task is snapped, the row width is just task width and spacing.
                     snappedTaskRowWidth = taskWidthAndSpacing;
                 }
+            } else if (taskView.isDesktopTask()) {
+                // Desktop task was not focused. Pin it to the right of focused
+                desktopTaskIndex = i;
+                gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
+
+                // Center view vertically in case it's from different orientation.
+                taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin
+                        - taskView.getLayoutParams().height) / 2f);
             } else {
                 if (i > focusedTaskIndex) {
                     // For tasks after the focused task, shift by focused task's width and spacing.
@@ -2781,7 +2824,7 @@
                     // Move horizontally into empty space.
                     float widthOffset = 0;
                     for (int j = i - 1; !topSet.contains(j) && j >= 0; j--) {
-                        if (j == focusedTaskIndex) {
+                        if (j == focusedTaskIndex || j == desktopTaskIndex) {
                             continue;
                         }
                         widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
@@ -2800,7 +2843,7 @@
                     // Move horizontally into empty space.
                     float widthOffset = 0;
                     for (int j = i - 1; !bottomSet.contains(j) && j >= 0; j--) {
-                        if (j == focusedTaskIndex) {
+                        if (j == focusedTaskIndex || j == desktopTaskIndex) {
                             continue;
                         }
                         widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
@@ -5101,6 +5144,10 @@
     }
 
     private int getFirstViewIndex() {
+        if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
+            // Desktop task is at position 0, that is the first view
+            return 0;
+        }
         TaskView focusedTaskView = mShowAsGridLastOnLayout ? getFocusedTaskView() : null;
         return focusedTaskView != null ? indexOfChild(focusedTaskView) : 0;
     }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 8c8c2ba..19ffa27 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -602,16 +602,18 @@
     }
 
     /**
-     * Finds the index of a given taskId within this TaskView, or -1 if the TaskView does not
-     * contain it. For grouped tasks (of two), this is 0 or 1; for solo tasks, it is 0.
+     * Returns the TaskIdAttributeContainer corresponding to a given taskId, or null if the TaskView
+     * does not contain a Task with that ID.
      */
-    public int getIndexOfTask(int taskId) {
-        for (int i = 0; i < mTaskIdContainer.length; i++) {
-            if (mTaskIdContainer[i] == taskId) {
-                return i;
+    @Nullable
+    public TaskIdAttributeContainer getTaskAttributesById(int taskId) {
+        for (TaskIdAttributeContainer attributes : mTaskIdAttributeContainer) {
+            if (attributes.getTask().key.id == taskId) {
+                return attributes;
             }
         }
-        return -1;
+
+        return null;
     }
 
     public TaskThumbnailView getThumbnail() {
@@ -1031,6 +1033,11 @@
         return deviceProfile.isTablet && !isFocusedTask();
     }
 
+    /** Whether this task view represents the desktop */
+    public boolean isDesktopTask() {
+        return false;
+    }
+
     /**
      * Called to animate a smooth transition when going directly from an app into Overview (and
      * vice versa). Icons fade in, and DWB banners slide in with a "shift up" animation.
@@ -1541,7 +1548,7 @@
             int boxWidth;
             int boxHeight;
             boolean isFocusedTask = isFocusedTask();
-            if (isFocusedTask) {
+            if (isFocusedTask || isDesktopTask()) {
                 // Task will be focused and should use focused task size. Use focusTaskRatio
                 // that is associated with the original orientation of the focused task.
                 boxWidth = taskWidth;
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index b9e4c17..81fbe79 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -131,7 +131,11 @@
     public static final LauncherState OVERVIEW = new OverviewState(OVERVIEW_STATE_ORDINAL);
     public static final LauncherState OVERVIEW_MODAL_TASK = OverviewState.newModalTaskState(
             OVERVIEW_MODAL_TASK_STATE_ORDINAL);
-    public static final LauncherState QUICK_SWITCH =
+    /**
+     * State when user performs a quickswitch gesture from home/workspace to the most recent
+     * app
+     */
+    public static final LauncherState QUICK_SWITCH_FROM_HOME =
             OverviewState.newSwitchState(QUICK_SWITCH_STATE_ORDINAL);
     public static final LauncherState BACKGROUND_APP =
             OverviewState.newBackgroundState(BACKGROUND_APP_STATE_ORDINAL);
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index ae9ba67..2d1c963 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -242,7 +242,8 @@
         // Launcher should run in test harness so that custom accessibility protocol between
         // Launcher and TAPL is enabled. In-process tests enable this protocol with a direct call
         // into Launcher.
-        assertTrue("Device must run in a test harness",
+        assertTrue("Device must run in a test harness. "
+                        + "Run `adb shell setprop ro.test_harness 1` to enable it.",
                 TestHelpers.isInLauncherProcess() || ActivityManager.isRunningInTestHarness());
 
         final String testPackage = getContext().getPackageName();