diff options
6 files changed, 87 insertions, 51 deletions
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml index a541c590575f..c68b0be47228 100644 --- a/libs/WindowManager/Shell/res/values/config.xml +++ b/libs/WindowManager/Shell/res/values/config.xml @@ -148,4 +148,7 @@ <!-- Whether pointer pilfer is required to start back animation. --> <bool name="config_backAnimationRequiresPointerPilfer">true</bool> + + <!-- Whether desktop mode is supported on the current device --> + <bool name="config_isDesktopModeSupported">false</bool> </resources> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java index 7b8486870a40..494d89307514 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java @@ -16,13 +16,13 @@ package com.android.wm.shell.desktopmode; -import static android.content.res.Configuration.SCREENLAYOUT_SIZE_XLARGE; - import android.annotation.NonNull; -import android.app.ActivityManager.RunningTaskInfo; +import android.content.Context; import android.os.SystemProperties; +import com.android.internal.annotations.VisibleForTesting; import com.android.window.flags.Flags; +import com.android.wm.shell.R; /** * Constants for desktop mode feature @@ -70,8 +70,11 @@ public class DesktopModeStatus { private static final boolean USE_ROUNDED_CORNERS = SystemProperties.getBoolean( "persist.wm.debug.desktop_use_rounded_corners", true); - private static final boolean ENFORCE_DISPLAY_RESTRICTIONS = SystemProperties.getBoolean( - "persist.wm.debug.desktop_mode_enforce_display_restrictions", true); + /** + * Flag to indicate whether to restrict desktop mode to supported devices. + */ + private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean( + "persist.wm.debug.desktop_mode_enforce_device_restrictions", true); /** * Return {@code true} if desktop windowing is enabled @@ -113,19 +116,25 @@ public class DesktopModeStatus { } /** - * Return whether the display size restrictions should be enforced. + * Return {@code true} if desktop mode should be restricted to supported devices. + */ + @VisibleForTesting + public static boolean enforceDeviceRestrictions() { + return ENFORCE_DEVICE_RESTRICTIONS; + } + + /** + * Return {@code true} if the current device supports desktop mode. */ - public static boolean enforceDisplayRestrictions() { - return ENFORCE_DISPLAY_RESTRICTIONS; + @VisibleForTesting + public static boolean isDesktopModeSupported(@NonNull Context context) { + return context.getResources().getBoolean(R.bool.config_isDesktopModeSupported); } /** - * Return {@code true} if the display associated with the task is at least of size - * {@link android.content.res.Configuration#SCREENLAYOUT_SIZE_XLARGE} or has been overridden to - * ignore the size constraint. + * Return {@code true} if desktop mode can be entered on the current device. */ - public static boolean meetsMinimumDisplayRequirements(@NonNull RunningTaskInfo taskInfo) { - return !enforceDisplayRestrictions() - || taskInfo.configuration.isLayoutSizeAtLeast(SCREENLAYOUT_SIZE_XLARGE); + public static boolean canEnterDesktopMode(@NonNull Context context) { + return !enforceDeviceRestrictions() || isDesktopModeSupported(context); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index c2c944211552..95237c38f309 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -306,7 +306,7 @@ class DesktopTasksController( task: RunningTaskInfo, wct: WindowContainerTransaction = WindowContainerTransaction() ) { - if (!DesktopModeStatus.meetsMinimumDisplayRequirements(task)) { + if (!DesktopModeStatus.canEnterDesktopMode(context)) { KtProtoLog.w( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: Cannot enter desktop, " + "display does not meet minimum size requirements") 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 bf22193566ed..9c0144292c12 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 @@ -1052,7 +1052,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop() - && DesktopModeStatus.meetsMinimumDisplayRequirements(taskInfo); + && DesktopModeStatus.canEnterDesktopMode(mContext); } private void createWindowDecoration( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 92b187f90d65..0136751d8c9a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -23,8 +23,6 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED -import android.content.res.Configuration.SCREENLAYOUT_SIZE_NORMAL -import android.content.res.Configuration.SCREENLAYOUT_SIZE_XLARGE import android.os.Binder import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY @@ -38,6 +36,7 @@ import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER import androidx.test.filters.SmallTest +import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.ExtendedMockito.never import com.android.dx.mockito.inline.extended.StaticMockitoSession @@ -89,6 +88,7 @@ import org.mockito.Mockito.anyInt import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever +import org.mockito.quality.Strictness @SmallTest @RunWith(AndroidTestingRunner::class) @@ -126,7 +126,8 @@ class DesktopTasksControllerTest : ShellTestCase() { @Before fun setUp() { - mockitoSession = mockitoSession().spyStatic(DesktopModeStatus::class.java).startMocking() + mockitoSession = mockitoSession().strictness(Strictness.LENIENT) + .spyStatic(DesktopModeStatus::class.java).startMocking() whenever(DesktopModeStatus.isEnabled()).thenReturn(true) shellInit = Mockito.spy(ShellInit(testExecutor)) @@ -335,25 +336,25 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - fun moveToDesktop_screenSizeBelowXLarge_doesNothing() { + fun moveToDesktop_deviceNotSupported_doesNothing() { val task = setUpFullscreenTask() - // Update screen layout to be below minimum size - task.configuration.screenLayout = SCREENLAYOUT_SIZE_NORMAL + // Simulate non compatible device + doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } controller.moveToDesktop(task) verifyWCTNotExecuted() } @Test - fun moveToDesktop_screenSizeBelowXLarge_displayRestrictionsOverridden_taskIsMovedToDesktop() { + fun moveToDesktop_deviceNotSupported_deviceRestrictionsOverridden_taskIsMovedToDesktop() { val task = setUpFullscreenTask() - // Update screen layout to be below minimum size - task.configuration.screenLayout = SCREENLAYOUT_SIZE_NORMAL + // Simulate non compatible device + doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } - // Simulate enforce display restrictions system property overridden to false - whenever(DesktopModeStatus.enforceDisplayRestrictions()).thenReturn(false) + // Simulate enforce device restrictions system property overridden to false + whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(false) controller.moveToDesktop(task) @@ -363,7 +364,7 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - fun moveToDesktop_screenSizeXLarge_taskIsMovedToDesktop() { + fun moveToDesktop_deviceSupported_taskIsMovedToDesktop() { val task = setUpFullscreenTask() controller.moveToDesktop(task) @@ -874,7 +875,8 @@ class DesktopTasksControllerTest : ShellTestCase() { private fun setUpFullscreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo { val task = createFullscreenTask(displayId) - task.configuration.screenLayout = SCREENLAYOUT_SIZE_XLARGE + doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true) whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) runningTasks.add(task) return task @@ -882,7 +884,8 @@ class DesktopTasksControllerTest : ShellTestCase() { private fun setUpSplitScreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo { val task = createSplitScreenTask(displayId) - task.configuration.screenLayout = SCREENLAYOUT_SIZE_XLARGE + doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true) whenever(splitScreenController.isTaskInSplitScreen(task.taskId)).thenReturn(true) whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) runningTasks.add(task) 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 83519bbf624a..6940739d68b2 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 @@ -23,8 +23,6 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.Context -import android.content.res.Configuration.SCREENLAYOUT_SIZE_NORMAL -import android.content.res.Configuration.SCREENLAYOUT_SIZE_XLARGE import android.graphics.Rect import android.hardware.display.DisplayManager import android.hardware.display.VirtualDisplay @@ -47,6 +45,7 @@ import android.view.WindowInsets.Type.navigationBars import android.view.WindowInsets.Type.statusBars import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession +import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn import com.android.dx.mockito.inline.extended.StaticMockitoSession import com.android.window.flags.Flags import com.android.wm.shell.RootTaskDisplayAreaOrganizer @@ -367,30 +366,41 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - fun testWindowDecor_screenSizeBelowXLarge_decorNotCreated() { - val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true) - // Update screen layout to be below minimum size - task.configuration.screenLayout = SCREENLAYOUT_SIZE_NORMAL + fun testWindowDecor_desktopModeUnsupportedOnDevice_decorNotCreated() { + val mockitoSession: StaticMockitoSession = mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(DesktopModeStatus::class.java) + .startMocking() + try { + // Simulate default enforce device restrictions system property + whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true) - onTaskOpening(task) - verify(mockDesktopModeWindowDecorFactory, never()) - .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) + val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true) + // Simulate device that doesn't support desktop mode + doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + + onTaskOpening(task) + verify(mockDesktopModeWindowDecorFactory, never()) + .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) + } finally { + mockitoSession.finishMocking() + } } @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - fun testWindowDecor_screenSizeBelowXLarge_displayRestrictionsOverridden_decorCreated() { + fun testWindowDecor_desktopModeUnsupportedOnDevice_deviceRestrictionsOverridden_decorCreated() { val mockitoSession: StaticMockitoSession = mockitoSession() .strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java) .startMocking() try { - // Simulate enforce display restrictions system property overridden to false - whenever(DesktopModeStatus.enforceDisplayRestrictions()).thenReturn(false) + // Simulate enforce device restrictions system property overridden to false + whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(false) + // Simulate device that doesn't support desktop mode + doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true) - // Update screen layout to be below minimum size - task.configuration.screenLayout = SCREENLAYOUT_SIZE_NORMAL setUpMockDecorationsForTasks(task) onTaskOpening(task) @@ -403,14 +413,25 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - fun testWindowDecor_screenSizeXLarge_decorCreated() { - val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true) - task.configuration.screenLayout = SCREENLAYOUT_SIZE_XLARGE - setUpMockDecorationsForTasks(task) + fun testWindowDecor_deviceSupportsDesktopMode_decorCreated() { + val mockitoSession: StaticMockitoSession = mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(DesktopModeStatus::class.java) + .startMocking() + try { + // Simulate default enforce device restrictions system property + whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true) - onTaskOpening(task) - verify(mockDesktopModeWindowDecorFactory) - .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) + val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true) + doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + setUpMockDecorationsForTasks(task) + + onTaskOpening(task) + verify(mockDesktopModeWindowDecorFactory) + .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) + } finally { + mockitoSession.finishMocking() + } } private fun onTaskOpening(task: RunningTaskInfo, leash: SurfaceControl = SurfaceControl()) { |