Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b8b6f23 authored by Eghosa Ewansiha-Vlachavas's avatar Eghosa Ewansiha-Vlachavas
Browse files

Replace desktop mode screen size check with config property flag

The screen layout of a device can be modified by the user through
setting a higher or lower density, meaning the screen layout size can
change from the default value making it an unreliable gate. Calculating
the screen size in inches using the window metrics was also explored but
did not result in accureate values given current APIs and thus is also
an unreliable gate.

Instead introduce a new config property flag, to gate the feature,
which represents whether a device supports desktop mode. By default
this will be false but set to true in the config of supported devices.

Bug: 326957646
Fixes: 328684732
Test: atest WMShellUnitTests:DesktopModeWindowDecorViewModelTests
Test: atest WMShellUnitTests:DesktopTasksControllerTest
Change-Id: I54329693746c6cb44ea4a54a6de00b33f9bc0a9c
parent 6ce00f97
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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>
+23 −14
Original line number Diff line number Diff line
@@ -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);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -305,7 +305,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")
+1 −1
Original line number Diff line number Diff line
@@ -1058,7 +1058,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(
+17 −14
Original line number Diff line number Diff line
@@ -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
@@ -88,6 +87,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)
@@ -125,7 +125,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))
@@ -334,25 +335,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)

@@ -362,7 +363,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    }

    @Test
    fun moveToDesktop_screenSizeXLarge_taskIsMovedToDesktop() {
    fun moveToDesktop_deviceSupported_taskIsMovedToDesktop() {
        val task = setUpFullscreenTask()

        controller.moveToDesktop(task)
@@ -857,7 +858,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
@@ -865,7 +867,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)
Loading