Merge "Make can create new desks a global state" into main
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
index 37e8d4d..6ee43ff 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
@@ -62,8 +62,6 @@
      * (Used only when multiple desks are enabled).
      *
      * @property displayId The ID of the display this object represents.
-     * @property canCreateDesks true if it's possible to create new desks on the display represented
-     *   by this object.
      * @property activeDeskId The ID of the active desk on the associated display (if any). It has a
      *   value of `INACTIVE_DESK_ID` (-1) if there are no active desks. Note that there can only be
      *   at most one active desk on each display.
@@ -71,11 +69,18 @@
      */
     private data class DisplayDeskConfig(
         val displayId: Int,
-        var canCreateDesks: Boolean,
         var activeDeskId: Int = INACTIVE_DESK_ID,
         val deskIds: MutableSet<Int>,
     )
 
+    /** True if it is possible to create new desks on current setup. */
+    var canCreateDesks: Boolean = false
+        private set(value) {
+            if (field == value) return
+            field = value
+            desktopVisibilityListeners.forEach { it.onCanCreateDesksChanged(field) }
+        }
+
     /** Maps each display by its ID to its desks configuration. */
     private val displaysDesksConfigsMap = SparseArray<DisplayDeskConfig>()
 
@@ -393,7 +398,10 @@
         }
     }
 
-    private fun onListenerConnected(displayDeskStates: Array<DisplayDeskState>) {
+    private fun onListenerConnected(
+        displayDeskStates: Array<DisplayDeskState>,
+        canCreateDesks: Boolean,
+    ) {
         if (!DesktopModeStatus.enableMultipleDesktops(context)) {
             return
         }
@@ -404,23 +412,24 @@
             displaysDesksConfigsMap[displayDeskState.displayId] =
                 DisplayDeskConfig(
                     displayId = displayDeskState.displayId,
-                    canCreateDesks = displayDeskState.canCreateDesk,
                     activeDeskId = displayDeskState.activeDeskId,
                     deskIds = displayDeskState.deskIds.toMutableSet(),
                 )
         }
+
+        this.canCreateDesks = canCreateDesks
     }
 
     private fun getDisplayDeskConfig(displayId: Int) =
         displaysDesksConfigsMap[displayId]
             ?: null.also { Slog.e(TAG, "Expected non-null desk config for display: $displayId") }
 
-    private fun onCanCreateDesksChanged(displayId: Int, canCreateDesks: Boolean) {
+    private fun onCanCreateDesksChanged(canCreateDesks: Boolean) {
         if (!DesktopModeStatus.enableMultipleDesktops(context)) {
             return
         }
 
-        getDisplayDeskConfig(displayId)?.canCreateDesks = canCreateDesks
+        this.canCreateDesks = canCreateDesks
     }
 
     private fun onDeskAdded(displayId: Int, deskId: Int) {
@@ -525,9 +534,12 @@
     ) : Stub() {
         private val controller = WeakReference(controller)
 
-        override fun onListenerConnected(displayDeskStates: Array<DisplayDeskState>) {
+        override fun onListenerConnected(
+            displayDeskStates: Array<DisplayDeskState>,
+            canCreateDesks: Boolean,
+        ) {
             Executors.MAIN_EXECUTOR.execute {
-                controller.get()?.onListenerConnected(displayDeskStates)
+                controller.get()?.onListenerConnected(displayDeskStates, canCreateDesks)
             }
         }
 
@@ -565,9 +577,9 @@
 
         override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) {}
 
-        override fun onCanCreateDesksChanged(displayId: Int, canCreateDesks: Boolean) {
+        override fun onCanCreateDesksChanged(canCreateDesks: Boolean) {
             Executors.MAIN_EXECUTOR.execute {
-                controller.get()?.onCanCreateDesksChanged(displayId, canCreateDesks)
+                controller.get()?.onCanCreateDesksChanged(canCreateDesks)
             }
         }
 
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index a29d302..c5a76cb 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -157,6 +157,7 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.statemanager.BaseState;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StatefulContainer;
@@ -179,6 +180,7 @@
 import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.util.ViewPool;
 import com.android.launcher3.util.coroutines.DispatcherProvider;
+import com.android.launcher3.util.window.WindowManagerProxy.DesktopVisibilityListener;
 import com.android.quickstep.BaseContainerInterface;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.HighResLoadingState;
@@ -265,7 +267,7 @@
         CONTAINER_TYPE extends Context & RecentsViewContainer & StatefulContainer<STATE_TYPE>,
         STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
         HighResLoadingState.HighResLoadingStateChangedCallback,
-        TaskVisualsChangeListener {
+        TaskVisualsChangeListener, DesktopVisibilityListener {
 
     private static final String TAG = "RecentsView";
     private static final boolean DEBUG = false;
@@ -556,6 +558,10 @@
     private final Rect mTaskViewDeadZoneRect = new Rect();
     private final Rect mTopRowDeadZoneRect = new Rect();
     private final Rect mBottomRowDeadZoneRect = new Rect();
+
+    @Nullable
+    private DesktopVisibilityController mDesktopVisibilityController = null;
+
     /**
      * Reflects if Recents is currently in the middle of a gesture, and if so, which tasks are
      * running. If a gesture is not in progress, this will be null.
@@ -913,6 +919,8 @@
             mAddDesktopButton = (AddDesktopButton) LayoutInflater.from(context).inflate(
                     R.layout.overview_add_desktop_button, this, false);
             mAddDesktopButton.setOnClickListener(this::createDesk);
+
+            mDesktopVisibilityController = DesktopVisibilityController.INSTANCE.get(mContext);
         }
 
         mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
@@ -1227,13 +1235,16 @@
         mSyncTransactionApplier = new SurfaceTransactionApplier(this);
         runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
                 .setSyncTransactionApplier(mSyncTransactionApplier));
-        RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
+        RecentsModel.INSTANCE.get(mContext).addThumbnailChangeListener(this);
         mIPipAnimationListener.setActivityAndRecentsView(mContainer, this);
-        SystemUiProxy.INSTANCE.get(getContext()).setPipAnimationListener(
+        SystemUiProxy.INSTANCE.get(mContext).setPipAnimationListener(
                 mIPipAnimationListener);
         mOrientationState.initListeners();
         mTaskOverlayFactory.initListeners();
         mSplitSelectStateController.registerSplitListener(mSplitSelectionListener);
+        if (mDesktopVisibilityController != null) {
+            mDesktopVisibilityController.registerDesktopVisibilityListener(this);
+        }
     }
 
     @Override
@@ -1248,12 +1259,15 @@
         runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
                 .setSyncTransactionApplier(null));
         executeSideTaskLaunchCallback();
-        RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this);
-        SystemUiProxy.INSTANCE.get(getContext()).setPipAnimationListener(null);
+        RecentsModel.INSTANCE.get(mContext).removeThumbnailChangeListener(this);
+        SystemUiProxy.INSTANCE.get(mContext).setPipAnimationListener(null);
         mIPipAnimationListener.setActivityAndRecentsView(null, null);
         mOrientationState.destroyListeners();
         mTaskOverlayFactory.removeListeners();
         mSplitSelectStateController.unregisterSplitListener(mSplitSelectionListener);
+        if (mDesktopVisibilityController != null) {
+            mDesktopVisibilityController.unregisterDesktopVisibilityListener(this);
+        }
         reset();
     }
 
@@ -6859,6 +6873,11 @@
         }
     }
 
+    @Override
+    public void onCanCreateDesksChanged(boolean canCreateDesks) {
+        // TODO: b/389209338 - update the AddDesktopButton's visibility on this.
+    }
+
     /** Get the color used for foreground scrimming the RecentsView for sharing. */
     public static int getForegroundScrimDimColor(Context context) {
         return context.getColor(R.color.overview_foreground_scrim_color);
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 647d170..11f0bc2 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -509,7 +509,17 @@
          * @param isInDesktopModeAndNotInOverview True if a desktop is currently active on the given
          *                                        display, and Overview is currently inactive.
          */
-        void onIsInDesktopModeChanged(int displayId, boolean isInDesktopModeAndNotInOverview);
+        default void onIsInDesktopModeChanged(int displayId,
+                boolean isInDesktopModeAndNotInOverview) {
+        }
+
+        /**
+         * Called whenever the conditions that allow the creation of desks change.
+         *
+         * @param canCreateDesks whether it is possible to create new desks.
+         */
+        default void onCanCreateDesksChanged(boolean canCreateDesks) {
+        }
     }
 
 }