summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/window/DesktopExperienceFlags.java1
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java38
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/AppHandleAndHeaderVisibilityHelper.kt100
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt13
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt7
-rw-r--r--services/core/java/com/android/server/wm/DesktopModeHelper.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java1
10 files changed, 186 insertions, 43 deletions
diff --git a/core/java/android/window/DesktopExperienceFlags.java b/core/java/android/window/DesktopExperienceFlags.java
index cf582176a9f7..b4ff8e70ec36 100644
--- a/core/java/android/window/DesktopExperienceFlags.java
+++ b/core/java/android/window/DesktopExperienceFlags.java
@@ -66,6 +66,7 @@ public enum DesktopExperienceFlags {
false),
ENABLE_PER_DISPLAY_PACKAGE_CONTEXT_CACHE_IN_STATUSBAR_NOTIF(
Flags::enablePerDisplayPackageContextCacheInStatusbarNotif, false),
+ ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE(Flags::enableProjectedDisplayDesktopMode, false),
ENABLE_TASKBAR_CONNECTED_DISPLAYS(Flags::enableTaskbarConnectedDisplays, false),
ENTER_DESKTOP_BY_DEFAULT_ON_FREEFORM_DISPLAYS(Flags::enterDesktopByDefaultOnFreeformDisplays,
false),
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 2e33253b5e09..ed5e0c608675 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -17,7 +17,9 @@
package com.android.wm.shell.shared.desktopmode;
import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
+import static android.window.DesktopExperienceFlags.ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE;
+import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
import static com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper.enableBubbleToFullscreen;
import android.annotation.NonNull;
@@ -224,7 +226,7 @@ public class DesktopModeStatus {
/**
* Return {@code true} if the current device can host desktop sessions on its internal display.
*/
- public static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
+ private static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
return context.getResources().getBoolean(R.bool.config_canInternalDisplayHostDesktops);
}
@@ -269,6 +271,29 @@ public class DesktopModeStatus {
}
/**
+ * Check to see if a display should have desktop mode enabled or not. Internal
+ * and external displays have separate logic.
+ */
+ public static boolean isDesktopModeSupportedOnDisplay(Context context, Display display) {
+ if (!canEnterDesktopMode(context)) {
+ return false;
+ }
+ if (display.getType() == Display.TYPE_INTERNAL) {
+ return canInternalDisplayHostDesktops(context);
+ }
+
+ // TODO (b/395014779): Change this to use WM API
+ if ((display.getType() == Display.TYPE_EXTERNAL
+ || display.getType() == Display.TYPE_OVERLAY)
+ && enableDisplayContentModeManagement()) {
+ final WindowManager wm = context.getSystemService(WindowManager.class);
+ return wm != null && wm.shouldShowSystemDecors(display.getDisplayId());
+ }
+
+ return false;
+ }
+
+ /**
* Returns whether the multiple desktops feature is enabled for this device (both backend and
* frontend implementations).
*/
@@ -341,8 +366,11 @@ public class DesktopModeStatus {
if (!enforceDeviceRestrictions()) {
return true;
}
- final boolean desktopModeSupported = isDesktopModeSupported(context)
- && canInternalDisplayHostDesktops(context);
+ // If projected display is enabled, #canInternalDisplayHostDesktops is no longer a
+ // requirement.
+ final boolean desktopModeSupported = ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE.isTrue()
+ ? isDesktopModeSupported(context) : (isDesktopModeSupported(context)
+ && canInternalDisplayHostDesktops(context));
final boolean desktopModeSupportedByDevOptions =
Flags.enableDesktopModeThroughDevOption()
&& isDesktopModeDevOptionSupported(context);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 6b7f311daa7c..32bdf3221bbe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -167,6 +167,7 @@ import com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel;
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer;
+import com.android.wm.shell.windowdecor.common.AppHandleAndHeaderVisibilityHelper;
import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader;
import com.android.wm.shell.windowdecor.common.viewhost.DefaultWindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.common.viewhost.PooledWindowDecorViewHostSupplier;
@@ -1002,6 +1003,7 @@ public abstract class WMShellModule {
Optional<DesktopTasksLimiter> desktopTasksLimiter,
AppHandleEducationController appHandleEducationController,
AppToWebEducationController appToWebEducationController,
+ AppHandleAndHeaderVisibilityHelper appHandleAndHeaderVisibilityHelper,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
FocusTransitionObserver focusTransitionObserver,
@@ -1025,10 +1027,10 @@ public abstract class WMShellModule {
rootTaskDisplayAreaOrganizer, interactionJankMonitor, genericLinksParser,
assistContentRequester, windowDecorViewHostSupplier, multiInstanceHelper,
desktopTasksLimiter, appHandleEducationController, appToWebEducationController,
- windowDecorCaptionHandleRepository, activityOrientationChangeHandler,
- focusTransitionObserver, desktopModeEventLogger, desktopModeUiEventLogger,
- taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy,
- desktopTilingDecorViewModel,
+ appHandleAndHeaderVisibilityHelper, windowDecorCaptionHandleRepository,
+ activityOrientationChangeHandler, focusTransitionObserver, desktopModeEventLogger,
+ desktopModeUiEventLogger, taskResourceLoader, recentsTransitionHandler,
+ desktopModeCompatPolicy, desktopTilingDecorViewModel,
multiDisplayDragMoveIndicatorController));
}
@@ -1056,6 +1058,16 @@ public abstract class WMShellModule {
@WMSingleton
@Provides
+ static AppHandleAndHeaderVisibilityHelper provideAppHandleAndHeaderVisibilityHelper(
+ @NonNull Context context,
+ @NonNull DisplayController displayController,
+ @NonNull DesktopModeCompatPolicy desktopModeCompatPolicy) {
+ return new AppHandleAndHeaderVisibilityHelper(context, displayController,
+ desktopModeCompatPolicy);
+ }
+
+ @WMSingleton
+ @Provides
static WindowDecorTaskResourceLoader provideWindowDecorTaskResourceLoader(
@NonNull Context context, @NonNull ShellInit shellInit,
@NonNull ShellController shellController,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 7ef1a93cbe45..ffb81f8c33e5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -17,11 +17,9 @@
package com.android.wm.shell.windowdecor;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_HOVER_ENTER;
@@ -79,7 +77,6 @@ import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewRootImpl;
-import android.view.WindowManager;
import android.window.DesktopModeFlags;
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
@@ -121,7 +118,6 @@ import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
import com.android.wm.shell.desktopmode.DesktopUserRepositories;
-import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction;
import com.android.wm.shell.desktopmode.common.ToggleTaskSizeUtilsKt;
@@ -146,6 +142,7 @@ import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.FocusTransitionObserver;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener;
+import com.android.wm.shell.windowdecor.common.AppHandleAndHeaderVisibilityHelper;
import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader;
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
@@ -207,6 +204,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
private final Optional<DesktopTasksLimiter> mDesktopTasksLimiter;
private final AppHandleEducationController mAppHandleEducationController;
private final AppToWebEducationController mAppToWebEducationController;
+ private final AppHandleAndHeaderVisibilityHelper mAppHandleAndHeaderVisibilityHelper;
private final AppHeaderViewHolder.Factory mAppHeaderViewHolderFactory;
private boolean mTransitionDragActive;
@@ -294,6 +292,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
AppHandleEducationController appHandleEducationController,
AppToWebEducationController appToWebEducationController,
+ AppHandleAndHeaderVisibilityHelper appHandleAndHeaderVisibilityHelper,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
FocusTransitionObserver focusTransitionObserver,
@@ -338,6 +337,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
desktopTasksLimiter,
appHandleEducationController,
appToWebEducationController,
+ appHandleAndHeaderVisibilityHelper,
windowDecorCaptionHandleRepository,
activityOrientationChangeHandler,
new TaskPositionerFactory(),
@@ -386,6 +386,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
AppHandleEducationController appHandleEducationController,
AppToWebEducationController appToWebEducationController,
+ AppHandleAndHeaderVisibilityHelper appHandleAndHeaderVisibilityHelper,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
TaskPositionerFactory taskPositionerFactory,
@@ -431,6 +432,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
mDesktopTasksLimiter = desktopTasksLimiter;
mAppHandleEducationController = appHandleEducationController;
mAppToWebEducationController = appToWebEducationController;
+ mAppHandleAndHeaderVisibilityHelper = appHandleAndHeaderVisibilityHelper;
mWindowDecorCaptionHandleRepository = windowDecorCaptionHandleRepository;
mActivityOrientationChangeHandler = activityOrientationChangeHandler;
mAssistContentRequester = assistContentRequester;
@@ -528,6 +530,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
@Override
public void setSplitScreenController(SplitScreenController splitScreenController) {
mSplitScreenController = splitScreenController;
+ mAppHandleAndHeaderVisibilityHelper.setSplitScreenController(splitScreenController);
}
@Override
@@ -1717,32 +1720,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
}
private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
- if (mDisplayController.getDisplay(taskInfo.displayId) == null) {
- // If DisplayController doesn't have it tracked, it could be a private/managed display.
- return false;
- }
- if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
- if (mSplitScreenController != null
- && mSplitScreenController.isTaskRootOrStageRoot(taskInfo.taskId)) {
- return false;
- }
- if (mDesktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing(taskInfo)) {
- return false;
- }
- final boolean isOnLargeScreen =
- mDisplayController.getDisplay(taskInfo.displayId).getMinSizeDimensionDp()
- >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
- if (!DesktopModeStatus.canEnterDesktopMode(mContext)
- && DesktopModeStatus.overridesShowAppHandle(mContext) && !isOnLargeScreen) {
- // Devices with multiple screens may enable the app handle but it should not show on
- // small screens
- return false;
- }
- return DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(mContext)
- && !DesktopWallpaperActivity.isWallpaperTask(taskInfo)
- && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
- && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
- && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop();
+ return mAppHandleAndHeaderVisibilityHelper.shouldShowAppHandleOrHeader(taskInfo);
}
private void createWindowDecoration(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/AppHandleAndHeaderVisibilityHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/AppHandleAndHeaderVisibilityHelper.kt
new file mode 100644
index 000000000000..39ccf5bd03a7
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/AppHandleAndHeaderVisibilityHelper.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.windowdecor.common
+
+import android.app.ActivityManager
+import android.app.WindowConfiguration
+import android.content.Context
+import android.view.WindowManager
+import android.window.DesktopExperienceFlags.ENABLE_BUG_FIXES_FOR_SECONDARY_DISPLAY
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.desktopmode.DesktopWallpaperActivity.Companion.isWallpaperTask
+import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.splitscreen.SplitScreenController
+
+/**
+ * Resolves whether, given a task and its associated display that it is currently on, to show the
+ * app handle/header or not.
+ */
+class AppHandleAndHeaderVisibilityHelper (
+ private val context: Context,
+ private val displayController: DisplayController,
+ private val desktopModeCompatPolicy: DesktopModeCompatPolicy
+) {
+ var splitScreenController: SplitScreenController? = null
+
+ /**
+ * Returns, given a task's attribute and its display attribute, whether the app
+ * handle/header should show or not for this task.
+ */
+ fun shouldShowAppHandleOrHeader(taskInfo: ActivityManager.RunningTaskInfo): Boolean {
+ if (!ENABLE_BUG_FIXES_FOR_SECONDARY_DISPLAY.isTrue) {
+ return allowedForTask(taskInfo)
+ }
+ return allowedForTask(taskInfo) && allowedForDisplay(taskInfo.displayId)
+ }
+
+ private fun allowedForTask(taskInfo: ActivityManager.RunningTaskInfo): Boolean {
+ // TODO (b/382023296): Remove once we no longer rely on
+ // Flags.enableBugFixesForSecondaryDisplay as it is taken care of in #allowedForDisplay
+ if (displayController.getDisplay(taskInfo.displayId) == null) {
+ // If DisplayController doesn't have it tracked, it could be a private/managed display.
+ return false
+ }
+ if (taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) return true
+ if (splitScreenController?.isTaskRootOrStageRoot(taskInfo.taskId) == true) {
+ return false
+ }
+
+ if (desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing(taskInfo)) {
+ return false
+ }
+
+ // TODO (b/382023296): Remove once we no longer rely on
+ // Flags.enableBugFixesForSecondaryDisplay as it is taken care of in #allowedForDisplay
+ val isOnLargeScreen =
+ displayController.getDisplay(taskInfo.displayId).minSizeDimensionDp >=
+ WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
+ if (!DesktopModeStatus.canEnterDesktopMode(context)
+ && DesktopModeStatus.overridesShowAppHandle(context)
+ && !isOnLargeScreen
+ ) {
+ // Devices with multiple screens may enable the app handle but it should not show on
+ // small screens
+ return false
+ }
+ return DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)
+ && !isWallpaperTask(taskInfo)
+ && taskInfo.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED
+ && taskInfo.activityType == WindowConfiguration.ACTIVITY_TYPE_STANDARD
+ && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop
+ }
+
+ private fun allowedForDisplay(displayId: Int): Boolean {
+ // If DisplayController doesn't have it tracked, it could be a private/managed display.
+ val display = displayController.getDisplay(displayId)
+ if (display == null) return false
+
+ if (DesktopModeStatus.isDesktopModeSupportedOnDisplay(context, display)) {
+ return true
+ }
+ // If on default display and on Large Screen (unfolded), show app handle
+ return DesktopModeStatus.overridesShowAppHandle(context)
+ && display.minSizeDimensionDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
index fb62ba75e056..edf91fe62e7d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
@@ -234,14 +234,25 @@ class DesktopModeStatusTest : ShellTestCase() {
assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse()
}
+ @DisableFlags(Flags.FLAG_ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE)
@Test
fun isDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktopOff_returnsFalse() {
doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported))
- doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
+ doReturn(false).whenever(mockResources)
+ .getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse()
}
+ @EnableFlags(Flags.FLAG_ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE)
+ @Test
+ fun isPDDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktopOff_returnsTrue() {
+ doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported))
+ doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
+
+ assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isTrue()
+ }
+
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION)
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index e89a122595d5..d69509faf4ec 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -115,7 +115,8 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest
.spyStatic(DragPositioningCallbackUtility::class.java)
.startMocking()
- doReturn(true).`when` { DesktopModeStatus.canInternalDisplayHostDesktops(Mockito.any()) }
+ doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupportedOnDisplay(Mockito.any(),
+ Mockito.any()) }
doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(Mockito.any()) }
doReturn(false).`when` { DesktopModeStatus.overridesShowAppHandle(Mockito.any()) }
@@ -394,7 +395,7 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest
whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true)
val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN)
- doReturn(true).`when` { DesktopModeStatus.canInternalDisplayHostDesktops(any()) }
+ doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupportedOnDisplay(any(), any()) }
setUpMockDecorationsForTasks(task)
onTaskOpening(task)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
index 81dfaed56b6f..a1f40fdefee9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
@@ -79,6 +79,7 @@ import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.util.StubTransaction
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
+import com.android.wm.shell.windowdecor.common.AppHandleAndHeaderVisibilityHelper
import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier
@@ -174,6 +175,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() {
internal lateinit var desktopModeOnKeyguardChangedListener: DesktopModeKeyguardChangeListener
protected lateinit var desktopModeWindowDecorViewModel: DesktopModeWindowDecorViewModel
protected lateinit var desktopModeCompatPolicy: DesktopModeCompatPolicy
+ protected lateinit var appHandleAndHeaderVisibilityHelper: AppHandleAndHeaderVisibilityHelper
fun setUpCommon() {
spyContext = spy(mContext)
@@ -185,9 +187,13 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() {
whenever(mockDesktopUserRepositories.current).thenReturn(mockDesktopRepository)
whenever(mockDisplayController.getDisplayContext(any())).thenReturn(spyContext)
whenever(mockDisplayController.getDisplay(any())).thenReturn(display)
+ whenever(display.type).thenReturn(Display.TYPE_INTERNAL)
whenever(mockDesktopUserRepositories.getProfile(anyInt()))
.thenReturn(mockDesktopRepository)
desktopModeCompatPolicy = DesktopModeCompatPolicy(spyContext)
+ appHandleAndHeaderVisibilityHelper =
+ AppHandleAndHeaderVisibilityHelper(spyContext, mockDisplayController,
+ desktopModeCompatPolicy)
desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel(
spyContext,
testShellExecutor,
@@ -222,6 +228,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() {
Optional.of(mockTasksLimiter),
mockAppHandleEducationController,
mockAppToWebEducationController,
+ appHandleAndHeaderVisibilityHelper,
mockCaptionHandleRepository,
Optional.of(mockActivityOrientationChangeHandler),
mockTaskPositionerFactory,
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index dc42b32967e2..d91fca9e2816 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.Flags.enableConnectedDisplaysWallpaper;
+import static android.window.DesktopExperienceFlags.ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE;
import android.annotation.NonNull;
import android.content.Context;
@@ -66,7 +67,7 @@ public final class DesktopModeHelper {
* Return {@code true} if the current device can hosts desktop sessions on its internal display.
*/
@VisibleForTesting
- static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
+ private static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
return context.getResources().getBoolean(R.bool.config_canInternalDisplayHostDesktops);
}
@@ -83,8 +84,11 @@ public final class DesktopModeHelper {
if (!shouldEnforceDeviceRestrictions()) {
return true;
}
- final boolean desktopModeSupported = isDesktopModeSupported(context)
- && canInternalDisplayHostDesktops(context);
+ // If projected display is enabled, #canInternalDisplayHostDesktops is no longer a
+ // requirement.
+ final boolean desktopModeSupported = ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE.isTrue()
+ ? isDesktopModeSupported(context) : (isDesktopModeSupported(context)
+ && canInternalDisplayHostDesktops(context));
final boolean desktopModeSupportedByDevOptions =
Flags.enableDesktopModeThroughDevOption()
&& isDesktopModeDevOptionsSupported(context);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
index 1e91bedb5c18..43755ea3165e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
@@ -181,6 +181,7 @@ public class DesktopModeHelperTest {
assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isTrue();
}
+ @DisableFlags(Flags.FLAG_ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE)
@Test
public void isDeviceEligibleForDesktopMode_configDEModeOffAndIntDispHostsDesktop_returnsFalse() {
doReturn(true).when(mMockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported));