Force Taskbar to remain stashed when in 3p launcher or recents

This patch makes it so that the transient Taskbar cannot unstash when in 3P launcher.

Previously, the user was able to unstash Taskbar when in 3P launcher, causing a janky-looking UI (3P launchers may implement their own version of Taskbar on the home screen. This also caused problems with certain Taskbar commands like split screen, which provide an entry portal to Pixel-specific implementations.

Fixed by forcing the Taskbar to stay stashed when a 3P Launcher is displayed. The Taskbar is still usable inside of other non-launcher apps. This was done by using TopTaskTracker to check for ACTIVITY_TYPE_HOME or ACTIVITY_TYPE_RECENTS, and disabling Taskbar when these activities are running.

Fixes: 277963491
Test: Manual
Change-Id: Ifc0f3c07e3b76eb610f93205978fbc596bab6253
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index ed4a212..f981610 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -21,12 +21,15 @@
 
 import android.animation.Animator;
 
-import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.TopTaskTracker;
 import com.android.quickstep.fallback.RecentsState;
 import com.android.quickstep.views.RecentsView;
 
+import java.util.stream.Stream;
+
 /**
  * A data source which integrates with the fallback RecentsActivity instance (for 3P launchers).
  */
@@ -81,18 +84,15 @@
      * Currently this animation just force stashes the taskbar in Overview.
      */
     public Animator createAnimToRecentsState(RecentsState toState, long duration) {
-        // Force stash the taskbar in overview modal state or when going home. We do not force
-        // stash on home when running in a test as 3p launchers rely on taskbar instead of hotseat.
-        boolean isGoingHome = toState == RecentsState.HOME && !isRunningInTestHarness();
-        boolean useStashedLauncherState = toState.hasOverviewActions() || isGoingHome;
-        boolean stashedLauncherState = useStashedLauncherState && (
-                (FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get() && toState == RecentsState.MODAL_TASK)
-                        || isGoingHome);
+        // Force stash taskbar (disallow unstashing) when:
+        // - in a 3P launcher or overview task.
+        // - not running in a test harness (unstash is needed for tests)
+        boolean forceStash = isIn3pHomeOrRecents() && !isRunningInTestHarness();
         TaskbarStashController stashController = mControllers.taskbarStashController;
         // Set both FLAG_IN_STASHED_LAUNCHER_STATE and FLAG_IN_APP to ensure the state is respected.
         // For all other states, just use the current stashed-in-app setting (e.g. if long clicked).
-        stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, stashedLauncherState);
-        stashController.updateStateForFlag(FLAG_IN_APP, !useStashedLauncherState);
+        stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, forceStash);
+        stashController.updateStateForFlag(FLAG_IN_APP, !forceStash);
         return stashController.createApplyStateAnimator(duration);
     }
 
@@ -108,4 +108,20 @@
     public RecentsView getRecentsView() {
         return mRecentsActivity.getOverviewPanel();
     }
+
+    @Override
+    Stream<SystemShortcut.Factory<BaseTaskbarContext>> getSplitMenuOptions() {
+        if (isIn3pHomeOrRecents()) {
+            // Split from Taskbar is not supported in fallback launcher, so return empty stream
+            return Stream.empty();
+        } else {
+            return super.getSplitMenuOptions();
+        }
+    }
+
+    private boolean isIn3pHomeOrRecents() {
+        TopTaskTracker.CachedTaskInfo topTask = TopTaskTracker.INSTANCE
+                .get(mControllers.taskbarActivityContext).getCachedTopTask(true);
+        return topTask.isHomeTask() || topTask.isRecentsTask();
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index d94d8f7..cf82900 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -1145,6 +1145,10 @@
         return mControllers.taskbarStashController.isInApp();
     }
 
+    public boolean isInStashedLauncherState() {
+        return mControllers.taskbarStashController.isInStashedLauncherState();
+    }
+
     protected void dumpLogs(String prefix, PrintWriter pw) {
         pw.println(prefix + "TaskbarActivityContext:");
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index a442849..f3e704c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -32,7 +32,6 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.dot.FolderDotInfo;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
@@ -205,9 +204,7 @@
         // append split options to APP_INFO shortcut, the order here will reflect in the popup
         return Stream.concat(
                 Stream.of(APP_INFO),
-                Utilities.getSplitPositionOptions(mContext.getDeviceProfile())
-                        .stream()
-                        .map(this::createSplitShortcutFactory)
+                mControllers.uiController.getSplitMenuOptions()
         );
     }
 
@@ -265,7 +262,7 @@
      *                 right.
      * @return A factory function to be used in populating the long-press menu.
      */
-    private SystemShortcut.Factory<BaseTaskbarContext> createSplitShortcutFactory(
+    SystemShortcut.Factory<BaseTaskbarContext> createSplitShortcutFactory(
             SplitPositionOption position) {
         return (context, itemInfo, originalView) -> new TaskbarSplitShortcut(context, itemInfo,
                 originalView, position, mAllowInitialSplitSelection);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index f3513fd..be5cbac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -30,8 +30,10 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.Utilities;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.SplitConfigurationOptions;
@@ -41,6 +43,7 @@
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
 
 import java.io.PrintWriter;
+import java.util.stream.Stream;
 
 /**
  * Base class for providing different taskbar UI
@@ -323,4 +326,14 @@
      * Refreshes the resumed state of this ui controller.
      */
     public void refreshResumedState() {}
+
+    /**
+     * Returns a stream of split screen menu options appropriate to the device.
+     */
+    Stream<SystemShortcut.Factory<BaseTaskbarContext>> getSplitMenuOptions() {
+        return Utilities
+                .getSplitPositionOptions(mControllers.taskbarActivityContext.getDeviceProfile())
+                .stream()
+                .map(mControllers.taskbarPopupController::createSplitShortcutFactory);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index 24cf72c..d34cddf 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -18,6 +18,7 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.content.Intent.ACTION_CHOOSER;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -244,6 +245,11 @@
                     .getActivityType() == ACTIVITY_TYPE_HOME;
         }
 
+        public boolean isRecentsTask() {
+            return mTopTask != null && mTopTask.configuration.windowConfiguration
+                    .getActivityType() == ACTIVITY_TYPE_RECENTS;
+        }
+
         /**
          * Returns {@code true} if this task windowing mode is set to {@link
          * android.app.WindowConfiguration#WINDOWING_MODE_FREEFORM}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 682763f..99a57a2 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -862,7 +862,8 @@
             if (tac != null) {
                 // Present always on large screen or on small screen w/ flag
                 DeviceProfile dp = tac.getDeviceProfile();
-                boolean useTaskbarConsumer = dp.isTaskbarPresent && !TaskbarManager.isPhoneMode(dp);
+                boolean useTaskbarConsumer = dp.isTaskbarPresent && !TaskbarManager.isPhoneMode(dp)
+                        && !tac.isInStashedLauncherState();
                 if (canStartSystemGesture && useTaskbarConsumer) {
                     reasonString.append(NEWLINE_PREFIX)
                             .append(reasonPrefix)
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index f17f074..d8fe32d 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2345,7 +2345,6 @@
             remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false);
         });
         resetFromSplitSelectionState();
-        mSplitSelectStateController.resetState();
 
         // These are relatively expensive and don't need to be done this frame (RecentsView isn't
         // visible anyway), so defer by a frame to get off the critical path, e.g. app to home.
@@ -4740,6 +4739,7 @@
         setTaskViewsPrimarySplitTranslation(0);
         setTaskViewsSecondarySplitTranslation(0);
 
+        mSplitSelectStateController.resetState();
         if (mSplitHiddenTaskViewIndex == -1) {
             return;
         }