Merge changes from topic "p-shortcut-impl" into main

* changes:
  Widget Picker: Update the launcher integration to support shortcuts
  Widget Picker: Update UI layer to support shortcuts
  Widget Picker: Update data layer to support shortcuts
diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig
index 61cdc75..c6fb8bf 100644
--- a/aconfig/launcher_overview.aconfig
+++ b/aconfig/launcher_overview.aconfig
@@ -97,3 +97,10 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "enable_simultaneous_overview_trigger_on_extended_desktop"
+    namespace: "launcher_overview"
+    description: "Enable Overview to launch and exit simultaneously on default and external displays wherever it was triggered or quit from"
+    bug:  "421128035"
+}
diff --git a/quickstep/dagger/com/android/launcher3/dagger/AppModule.kt b/quickstep/dagger/com/android/launcher3/dagger/AppModule.kt
index 5521c06..d88fc94 100644
--- a/quickstep/dagger/com/android/launcher3/dagger/AppModule.kt
+++ b/quickstep/dagger/com/android/launcher3/dagger/AppModule.kt
@@ -16,10 +16,8 @@
 
 package com.android.launcher3.dagger
 
-import com.android.launcher3.backuprestore.LauncherRestoreEventLogger
 import com.android.launcher3.model.ModelDelegate
 import com.android.launcher3.model.QuickstepModelDelegate
-import com.android.quickstep.LauncherRestoreEventLoggerImpl
 import dagger.Binds
 import dagger.Module
 
@@ -31,9 +29,4 @@
 abstract class AppModule {
 
     @Binds abstract fun bindModelDelegate(impl: QuickstepModelDelegate): ModelDelegate
-
-    @Binds
-    abstract fun bindRestoreEventLogger(
-        impl: LauncherRestoreEventLoggerImpl
-    ): LauncherRestoreEventLogger
 }
diff --git a/quickstep/src/com/android/launcher3/dagger/Modules.kt b/quickstep/src/com/android/launcher3/dagger/Modules.kt
index fccbf2b..5581d37 100644
--- a/quickstep/src/com/android/launcher3/dagger/Modules.kt
+++ b/quickstep/src/com/android/launcher3/dagger/Modules.kt
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.dagger
 
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger
 import com.android.launcher3.icons.LauncherIconProvider
 import com.android.launcher3.icons.LauncherIconProviderImpl
 import com.android.launcher3.logging.StatsLogManager.StatsLogManagerFactory
@@ -29,6 +30,7 @@
 import com.android.launcher3.util.window.WindowManagerProxy
 import com.android.launcher3.widget.LauncherWidgetHolder.WidgetHolderFactory
 import com.android.quickstep.InstantAppResolverImpl
+import com.android.quickstep.LauncherRestoreEventLoggerImpl
 import com.android.quickstep.logging.StatsLogCompatManager.StatsLogCompatManagerFactory
 import com.android.quickstep.util.ChoreographerFrameRateTracker
 import com.android.quickstep.util.GestureExclusionManager
@@ -58,6 +60,11 @@
     abstract fun bindIconProvider(iconProviderImpl: LauncherIconProviderImpl): LauncherIconProvider
 
     @Binds abstract fun bindInstantAppResolver(impl: InstantAppResolverImpl): InstantAppResolver
+
+    @Binds
+    abstract fun bindRestoreEventLogger(
+        impl: LauncherRestoreEventLoggerImpl
+    ): LauncherRestoreEventLogger
 }
 
 @Module
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 5ab21f8..f7e760d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -1844,7 +1844,7 @@
                     return;
                 }
             }
-            if (shouldLaunchInDesktop(displayId)) {
+            if (shouldLaunchInDesktop(displayId, info)) {
                 launchDesktopApp(intent, info, displayId);
             } else {
                 startActivity(intent, null);
@@ -1856,10 +1856,16 @@
         }
     }
 
-    private boolean shouldLaunchInDesktop(int displayId) {
+    private boolean shouldLaunchInDesktop(int displayId, ItemInfo info) {
         if (!DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue()) {
             return false;
         }
+        if (DesktopExperienceFlags.ENABLE_DESKTOP_FIRST_FULLSCREEN_REFOCUS_BUGFIX.isTrue()
+                && DisplayController.isInDesktopFirstMode(this)
+                && mControllers.taskbarRecentAppsController.hasSingleTask(info)) {
+            // Keep the fullscreen mode in desktop-first mode.
+            return false;
+        }
         // Always launch in freeform if in external display.
         return (DesktopExperienceFlags.ENABLE_FREEFORM_DISPLAY_LAUNCH_PARAMS.isTrue()
                 && isExternalDisplay(displayId)) || isTaskbarShowingDesktopTasks();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index 8176920..f4d0f15 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -138,6 +138,19 @@
         }
     }
 
+    /**
+     * Returns `true` if recents has the single task (i.e., fullscreen) represented by the given
+     * [itemInfo].
+     */
+    fun hasSingleTask(itemInfo: ItemInfo?): Boolean {
+        val packageName = itemInfo?.targetPackage ?: return false
+        return allRecentTasks.any { task ->
+            task is SingleTask &&
+                packageName == task.task.key.packageName &&
+                    task.task.key.userId == itemInfo.user.identifier
+        }
+    }
+
     @VisibleForTesting
     val runningTaskIds: Set<Int>
         /**
diff --git a/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModel.kt b/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModel.kt
index 049556a..8e67c10 100644
--- a/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModel.kt
+++ b/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModel.kt
@@ -94,15 +94,16 @@
         }
 
     private val overlayEnabled =
-        if (taskViewType == TaskViewType.DESKTOP) {
-            flowOf(false)
-        } else {
-            combine(recentsViewData.overlayEnabled, recentsViewData.settledFullyVisibleTaskIds) {
-                    isOverlayEnabled,
-                    settledFullyVisibleTaskIds ->
-                    isOverlayEnabled && settledFullyVisibleTaskIds.any { it in taskIds.value }
-                }
-                .distinctUntilChanged()
+        when (taskViewType) {
+            TaskViewType.SINGLE ->
+                combine(
+                        recentsViewData.overlayEnabled,
+                        recentsViewData.settledFullyVisibleTaskIds,
+                    ) { isOverlayEnabled, settledFullyVisibleTaskIds ->
+                        isOverlayEnabled && settledFullyVisibleTaskIds.any { it in taskIds.value }
+                    }
+                    .distinctUntilChanged()
+            else -> flowOf(false)
         }
 
     private val preThreadingImprovedState: Flow<TaskTileUiState> =
@@ -126,10 +127,11 @@
             val taskIds = taskModels.map { it.first }.toSet()
             val isCentralTask = taskIds == centralTaskIds
             val overlayEnabled =
-                if (taskViewType == TaskViewType.DESKTOP) {
-                    false
-                } else {
-                    isOverlayEnabled && settledFullyVisibleTaskIds.any { it in taskIds }
+                when (taskViewType) {
+                    TaskViewType.SINGLE -> {
+                        isOverlayEnabled && settledFullyVisibleTaskIds.any { it in taskIds }
+                    }
+                    else -> false
                 }
             val isLiveTile = runningTaskIds == taskIds && !runningTaskShowScreenshot
             val taskData = mapToTaskData(taskModels, isLiveTile)
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index 0f1f1cd..d5ffe4b 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -36,6 +36,7 @@
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.fallback.window.RecentsWindowFlags;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.shared.desktopmode.DesktopState;
 
 import java.util.List;
 import java.util.Set;
@@ -82,6 +83,15 @@
     }
 
     @Override
+    public boolean isDisplayDesktopFirst(Context displayInfoContext) {
+        if (!DesktopState.fromContext(displayInfoContext).canEnterDesktopMode()) {
+            return false;
+        }
+        return displayInfoContext.getResources().getConfiguration()
+                .windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
+    }
+
+    @Override
     public boolean showLockedTaskbarOnHome(Context displayInfoContext) {
         if (!DesktopModeStatus.canEnterDesktopMode(displayInfoContext)) {
             return false;
@@ -89,9 +99,8 @@
         if (!DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(displayInfoContext)) {
             return false;
         }
-        final boolean isFreeformDisplay = displayInfoContext.getResources().getConfiguration()
-                .windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
-        return isFreeformDisplay;
+
+        return isDisplayDesktopFirst(displayInfoContext);
     }
 
     @Override
@@ -108,9 +117,7 @@
             return false;
         }
 
-        final boolean isFreeformDisplay = displayInfoContext.getResources().getConfiguration()
-                .windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
-        return isFreeformDisplay;
+        return isDisplayDesktopFirst(displayInfoContext);
     }
 
     @Override
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
index c119572..f3d828a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
@@ -1118,6 +1118,61 @@
             .containsExactlyElementsIn(listOf(1, 2, 3, 4))
     }
 
+    @Test
+    fun hasSingleTask_noTargetPackage_returnsFalse() {
+        prepareHotseatAndRunningAndRecentApps(
+            hotseatPackages = emptyList(),
+            runningTasks = emptyList(),
+            recentTaskPackages = listOf(RECENT_PACKAGE_1),
+        )
+        assertThat(recentAppsController.hasSingleTask(ItemInfo())).isFalse()
+    }
+
+    @Test
+    fun hasSingleTask_noRecentTasks_returnsFalse() {
+        prepareHotseatAndRunningAndRecentApps(
+            hotseatPackages = emptyList(),
+            runningTasks = emptyList(),
+            recentTaskPackages = emptyList(),
+        )
+        val itemInfo = createItemInfo(RECENT_PACKAGE_1)
+        assertThat(recentAppsController.hasSingleTask(itemInfo)).isFalse()
+    }
+
+    @Test
+    fun hasSingleTask_noMatchingSingleTask_returnsFalse() {
+        prepareHotseatAndRunningAndRecentApps(
+            hotseatPackages = emptyList(),
+            runningTasks = emptyList(),
+            recentTaskPackages = listOf(RECENT_PACKAGE_1),
+        )
+        val itemInfo = createItemInfo(RECENT_PACKAGE_2)
+        assertThat(recentAppsController.hasSingleTask(itemInfo)).isFalse()
+    }
+
+    @Test
+    fun hasSingleTask_matchingSingleTask_returnsTrue() {
+        prepareHotseatAndRunningAndRecentApps(
+            hotseatPackages = emptyList(),
+            runningTasks = emptyList(),
+            recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
+        )
+        val itemInfo = createItemInfo(RECENT_PACKAGE_1)
+        assertThat(recentAppsController.hasSingleTask(itemInfo)).isTrue()
+    }
+
+    @Test
+    fun hasSingleTask_matchingSingleTaskDifferentUser_returnsFalse() {
+        prepareHotseatAndRunningAndRecentApps(
+            hotseatPackages = emptyList(),
+            runningTasks = emptyList(),
+            recentTaskPackages = listOf(RECENT_PACKAGE_1),
+        )
+        // RECENT_PACKAGE_1 is created with myUserHandle in createRecentTasksFromPackageNames
+        val itemInfo = createItemInfo(RECENT_PACKAGE_1, USER_HANDLE_1)
+        assertThat(recentAppsController.hasSingleTask(itemInfo)).isFalse()
+    }
+
     private fun prepareHotseatAndRunningAndRecentApps(
         hotseatPackages: List<String>,
         runningTasks: List<Task>,
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModelTest.kt
index 9eb1f11..b499a1d 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModelTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModelTest.kt
@@ -306,6 +306,17 @@
         }
 
     @Test
+    fun taskOverlayDisabled_when_OverlayIsEnabledForVisibleGroupedTask() =
+        testScope.runTest {
+            sut = createTaskViewModel(TaskViewType.GROUPED)
+            sut.bind(TASK_MODEL_1.id)
+            recentsViewData.overlayEnabled.value = true
+            recentsViewData.settledFullyVisibleTaskIds.value = setOf(1)
+
+            assertThat(sut.state.first().taskOverlayEnabled).isFalse()
+        }
+
+    @Test
     fun isCentralTask_when_CentralTaskIdsMatchTaskIds() =
         testScope.runTest {
             sut.bind(TASK_MODEL_1.id, TASK_MODEL_2.id)
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 60c65e5..ab9ede6 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -258,6 +258,13 @@
     }
 
     /**
+     * Returns whether the display is in desktop-first mode.
+     */
+    public static boolean isInDesktopFirstMode(Context context) {
+        return getInfo(context).isInDesktopFirstMode();
+    }
+
+    /**
      * Returns whether the taskbar is forced to be pinned when home is visible.
      */
     public static boolean showLockedTaskbarOnHome(Context context) {
@@ -524,6 +531,7 @@
         private final boolean mIsTaskbarPinned;
 
         private final boolean mIsInDesktopMode;
+        private final boolean mIsInDesktopFirstMode;
 
         private final boolean mShowLockedTaskbarOnHome;
         private final boolean mIsHomeVisible;
@@ -600,6 +608,7 @@
 
             mIsTaskbarPinned = LauncherPrefs.get(displayInfoContext).get(TASKBAR_PINNING);
             mIsInDesktopMode = wmProxy.isInDesktopMode(DEFAULT_DISPLAY);
+            mIsInDesktopFirstMode = wmProxy.isDisplayDesktopFirst(displayInfoContext);
             mShowLockedTaskbarOnHome = wmProxy.showLockedTaskbarOnHome(displayInfoContext);
             mShowDesktopTaskbarForFreeformDisplay = wmProxy.showDesktopTaskbarForFreeformDisplay(
                     displayInfoContext);
@@ -653,6 +662,13 @@
         }
 
         /**
+         * Returns whether the display is in desktop-first mode.
+         */
+        public boolean isInDesktopFirstMode() {
+            return mIsInDesktopFirstMode;
+        }
+
+        /**
          * Returns {@code true} if the bounds represent a tablet.
          */
         public boolean isTablet(WindowBounds bounds) {
@@ -767,6 +783,7 @@
             pw.println("  navigationMode=" + info.getNavigationMode().name());
             pw.println("  isTaskbarPinned=" + info.mIsTaskbarPinned);
             pw.println("  isInDesktopMode=" + info.mIsInDesktopMode);
+            pw.println("  isInDesktopFirstMode=" + info.isInDesktopFirstMode());
             pw.println("  showLockedTaskbarOnHome=" + info.showLockedTaskbarOnHome());
             pw.println("  currentSize=" + info.currentSize);
             info.mPerDisplayBounds.forEach((key, value) -> pw.println(
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 43059b6..493aef2 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -116,6 +116,13 @@
     }
 
     /**
+     * Returns if the display is in desktop-first mode.
+     */
+    public boolean isDisplayDesktopFirst(Context displayInfoContext) {
+        return false;
+    }
+
+    /**
      * Returns if the pinned taskbar should be shown when home is visible.
      */
     public boolean showLockedTaskbarOnHome(Context displayInfoContext) {