Loading core/java/android/provider/Settings.java +13 −1 Original line number Diff line number Diff line Loading @@ -13396,7 +13396,19 @@ public final class Settings { = "enable_freeform_support"; /** * Whether to enable experimental desktop mode on secondary displays. * Whether to override the availability of the desktop mode on the main display of the * device. If on, users can make move an app to the desktop, allowing a freeform windowing * experience. * @hide */ @Readable public static final String DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES = "override_desktop_mode_features"; /** * Whether to enable the legacy freeform support on secondary displays. If enabled, the * SECONDARY_HOME of the launcher is started on any secondary display, allowing for a * desktop experience. * @hide */ @Readable Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java +45 −5 Original line number Diff line number Diff line Loading @@ -16,9 +16,13 @@ package com.android.wm.shell.shared; import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; import android.annotation.NonNull; import android.content.Context; import android.os.SystemProperties; import android.provider.Settings; import android.util.Log; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; Loading @@ -29,6 +33,8 @@ import com.android.window.flags.Flags; */ public class DesktopModeStatus { private static final String TAG = "DesktopModeStatus"; /** * Flag to indicate whether task resizing is veiled. */ Loading Loading @@ -98,11 +104,12 @@ public class DesktopModeStatus { "persist.wm.debug.desktop_max_task_limit", DEFAULT_MAX_TASK_LIMIT); /** * Return {@code true} if desktop windowing is enabled. Only to be used for testing. Callers * should use {@link #canEnterDesktopMode(Context)} to query the state of desktop windowing. * Return {@code true} if desktop windowing flag is enabled. Only to be used for testing. * Callers should use {@link #canEnterDesktopMode(Context)} to query the state of desktop * windowing. */ @VisibleForTesting public static boolean isEnabled() { public static boolean isDesktopModeFlagEnabled() { return Flags.enableDesktopWindowingMode(); } Loading Loading @@ -153,11 +160,37 @@ public class DesktopModeStatus { return context.getResources().getBoolean(R.bool.config_isDesktopModeSupported); } /** * Return {@code true} if desktop mode dev option should be shown on current device */ public static boolean canShowDesktopModeDevOption(@NonNull Context context) { return isDeviceEligibleForDesktopMode(context) && Flags.showDesktopWindowingDevOption(); } /** Returns if desktop mode dev option should be enabled if there is no user override. */ public static boolean shouldDevOptionBeEnabledByDefault() { return isDesktopModeFlagEnabled(); } /** * Return {@code true} if desktop mode is enabled and can be entered on the current device. */ public static boolean canEnterDesktopMode(@NonNull Context context) { return (!enforceDeviceRestrictions() || isDesktopModeSupported(context)) && isEnabled(); if (!isDeviceEligibleForDesktopMode(context)) return false; // If dev option has ever been manually toggled by the user, return its value // TODO(b/348193756) : Move the logic for DW override based on toggle overides to a common // infrastructure and add caching for the computation int defaultOverrideState = -1; int toggleState = Settings.Global.getInt(context.getContentResolver(), DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, defaultOverrideState); if (toggleState != defaultOverrideState) { Log.d(TAG, "Using Desktop mode dev option overridden state"); return toggleState != 0; } // Return Desktop windowing flag value return isDesktopModeFlagEnabled(); } /** Loading @@ -181,4 +214,11 @@ public class DesktopModeStatus { return DESKTOP_DENSITY_OVERRIDE >= DESKTOP_DENSITY_MIN && DESKTOP_DENSITY_OVERRIDE <= DESKTOP_DENSITY_MAX; } /** * Return {@code true} if desktop mode is unrestricted and is supported in the device. */ private static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) { return !enforceDeviceRestrictions() || isDesktopModeSupported(context); } } libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -193,7 +193,7 @@ class DesktopTasksControllerTest : ShellTestCase() { .strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java) .startMocking() whenever(DesktopModeStatus.isEnabled()).thenReturn(true) whenever(DesktopModeStatus.isDesktopModeFlagEnabled()).thenReturn(true) doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } shellInit = spy(ShellInit(testExecutor)) Loading Loading @@ -264,7 +264,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun instantiate_flagOff_doNotAddInitCallback() { whenever(DesktopModeStatus.isEnabled()).thenReturn(false) whenever(DesktopModeStatus.isDesktopModeFlagEnabled()).thenReturn(false) clearInvocations(shellInit) createController() Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt +17 −3 Original line number Diff line number Diff line Loading @@ -27,6 +27,9 @@ import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display import android.window.WindowContainerToken import com.android.dx.mockito.inline.extended.ExtendedMockito 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.R import com.android.wm.shell.common.DisplayController Loading @@ -37,6 +40,7 @@ import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertTrue import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test Loading @@ -45,6 +49,7 @@ import org.mockito.Mock import org.mockito.Mockito.any import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations import org.mockito.quality.Strictness /** * Tests for [DragPositioningCallbackUtility]. Loading Loading @@ -82,9 +87,13 @@ class DragPositioningCallbackUtilityTest { @Rule val setFlagsRule = SetFlagsRule() private lateinit var mockitoSession: StaticMockitoSession @Before fun setup() { MockitoAnnotations.initMocks(this) mockitoSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java).startMocking() whenever(taskToken.asBinder()).thenReturn(taskBinder) whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout) Loading @@ -105,6 +114,11 @@ class DragPositioningCallbackUtilityTest { whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID } } @After fun tearDown() { mockitoSession.finishMocking() } @Test fun testChangeBoundsDoesNotChangeHeightWhenLessThanMin() { val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat()) Loading Loading @@ -252,7 +266,7 @@ class DragPositioningCallbackUtilityTest { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS) fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeLessThanMin_shouldNotChangeBounds() { whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true) doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) } initializeTaskInfo(taskMinWidth = -1, taskMinHeight = -1) val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat()) Loading @@ -275,7 +289,7 @@ class DragPositioningCallbackUtilityTest { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS) fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeAllowedSize_shouldChangeBounds() { whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true) doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) } initializeTaskInfo(taskMinWidth = -1, taskMinHeight = -1) val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat()) Loading Loading @@ -361,7 +375,7 @@ class DragPositioningCallbackUtilityTest { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS) fun testChangeBoundsInDesktopMode_windowSizeExceedsStableBounds_shouldBeLimitedToDisplaySize() { whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true) doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) } val startingPoint = PointF(OFF_CENTER_STARTING_BOUNDS.right.toFloat(), OFF_CENTER_STARTING_BOUNDS.bottom.toFloat()) Loading packages/SettingsLib/res/values/strings.xml +4 −4 Original line number Diff line number Diff line Loading @@ -1010,10 +1010,10 @@ <!-- UI debug setting: force allow on external summary [CHAR LIMIT=150] --> <string name="force_resizable_activities_summary">Make all activities resizable for multi-window, regardless of manifest values.</string> <!-- UI debug setting: enable freeform window support [CHAR LIMIT=50] --> <string name="enable_freeform_support">Enable freeform windows</string> <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] --> <string name="enable_freeform_support_summary">Enable support for experimental freeform windows.</string> <!-- UI debug setting: enable legacy freeform window support [CHAR LIMIT=50] --> <string name="enable_freeform_support">Enable freeform windows (legacy)</string> <!-- UI debug setting: enable legacy freeform window support summary [CHAR LIMIT=150] --> <string name="enable_freeform_support_summary">Enable support for experimental legacy freeform windows.</string> <!-- Local (desktop) backup password menu title [CHAR LIMIT=25] --> <string name="local_backup_password_title">Desktop backup password</string> Loading Loading
core/java/android/provider/Settings.java +13 −1 Original line number Diff line number Diff line Loading @@ -13396,7 +13396,19 @@ public final class Settings { = "enable_freeform_support"; /** * Whether to enable experimental desktop mode on secondary displays. * Whether to override the availability of the desktop mode on the main display of the * device. If on, users can make move an app to the desktop, allowing a freeform windowing * experience. * @hide */ @Readable public static final String DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES = "override_desktop_mode_features"; /** * Whether to enable the legacy freeform support on secondary displays. If enabled, the * SECONDARY_HOME of the launcher is started on any secondary display, allowing for a * desktop experience. * @hide */ @Readable Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java +45 −5 Original line number Diff line number Diff line Loading @@ -16,9 +16,13 @@ package com.android.wm.shell.shared; import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; import android.annotation.NonNull; import android.content.Context; import android.os.SystemProperties; import android.provider.Settings; import android.util.Log; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; Loading @@ -29,6 +33,8 @@ import com.android.window.flags.Flags; */ public class DesktopModeStatus { private static final String TAG = "DesktopModeStatus"; /** * Flag to indicate whether task resizing is veiled. */ Loading Loading @@ -98,11 +104,12 @@ public class DesktopModeStatus { "persist.wm.debug.desktop_max_task_limit", DEFAULT_MAX_TASK_LIMIT); /** * Return {@code true} if desktop windowing is enabled. Only to be used for testing. Callers * should use {@link #canEnterDesktopMode(Context)} to query the state of desktop windowing. * Return {@code true} if desktop windowing flag is enabled. Only to be used for testing. * Callers should use {@link #canEnterDesktopMode(Context)} to query the state of desktop * windowing. */ @VisibleForTesting public static boolean isEnabled() { public static boolean isDesktopModeFlagEnabled() { return Flags.enableDesktopWindowingMode(); } Loading Loading @@ -153,11 +160,37 @@ public class DesktopModeStatus { return context.getResources().getBoolean(R.bool.config_isDesktopModeSupported); } /** * Return {@code true} if desktop mode dev option should be shown on current device */ public static boolean canShowDesktopModeDevOption(@NonNull Context context) { return isDeviceEligibleForDesktopMode(context) && Flags.showDesktopWindowingDevOption(); } /** Returns if desktop mode dev option should be enabled if there is no user override. */ public static boolean shouldDevOptionBeEnabledByDefault() { return isDesktopModeFlagEnabled(); } /** * Return {@code true} if desktop mode is enabled and can be entered on the current device. */ public static boolean canEnterDesktopMode(@NonNull Context context) { return (!enforceDeviceRestrictions() || isDesktopModeSupported(context)) && isEnabled(); if (!isDeviceEligibleForDesktopMode(context)) return false; // If dev option has ever been manually toggled by the user, return its value // TODO(b/348193756) : Move the logic for DW override based on toggle overides to a common // infrastructure and add caching for the computation int defaultOverrideState = -1; int toggleState = Settings.Global.getInt(context.getContentResolver(), DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, defaultOverrideState); if (toggleState != defaultOverrideState) { Log.d(TAG, "Using Desktop mode dev option overridden state"); return toggleState != 0; } // Return Desktop windowing flag value return isDesktopModeFlagEnabled(); } /** Loading @@ -181,4 +214,11 @@ public class DesktopModeStatus { return DESKTOP_DENSITY_OVERRIDE >= DESKTOP_DENSITY_MIN && DESKTOP_DENSITY_OVERRIDE <= DESKTOP_DENSITY_MAX; } /** * Return {@code true} if desktop mode is unrestricted and is supported in the device. */ private static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) { return !enforceDeviceRestrictions() || isDesktopModeSupported(context); } }
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -193,7 +193,7 @@ class DesktopTasksControllerTest : ShellTestCase() { .strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java) .startMocking() whenever(DesktopModeStatus.isEnabled()).thenReturn(true) whenever(DesktopModeStatus.isDesktopModeFlagEnabled()).thenReturn(true) doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } shellInit = spy(ShellInit(testExecutor)) Loading Loading @@ -264,7 +264,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun instantiate_flagOff_doNotAddInitCallback() { whenever(DesktopModeStatus.isEnabled()).thenReturn(false) whenever(DesktopModeStatus.isDesktopModeFlagEnabled()).thenReturn(false) clearInvocations(shellInit) createController() Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt +17 −3 Original line number Diff line number Diff line Loading @@ -27,6 +27,9 @@ import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display import android.window.WindowContainerToken import com.android.dx.mockito.inline.extended.ExtendedMockito 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.R import com.android.wm.shell.common.DisplayController Loading @@ -37,6 +40,7 @@ import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertTrue import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test Loading @@ -45,6 +49,7 @@ import org.mockito.Mock import org.mockito.Mockito.any import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations import org.mockito.quality.Strictness /** * Tests for [DragPositioningCallbackUtility]. Loading Loading @@ -82,9 +87,13 @@ class DragPositioningCallbackUtilityTest { @Rule val setFlagsRule = SetFlagsRule() private lateinit var mockitoSession: StaticMockitoSession @Before fun setup() { MockitoAnnotations.initMocks(this) mockitoSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java).startMocking() whenever(taskToken.asBinder()).thenReturn(taskBinder) whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout) Loading @@ -105,6 +114,11 @@ class DragPositioningCallbackUtilityTest { whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID } } @After fun tearDown() { mockitoSession.finishMocking() } @Test fun testChangeBoundsDoesNotChangeHeightWhenLessThanMin() { val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat()) Loading Loading @@ -252,7 +266,7 @@ class DragPositioningCallbackUtilityTest { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS) fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeLessThanMin_shouldNotChangeBounds() { whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true) doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) } initializeTaskInfo(taskMinWidth = -1, taskMinHeight = -1) val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat()) Loading @@ -275,7 +289,7 @@ class DragPositioningCallbackUtilityTest { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS) fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeAllowedSize_shouldChangeBounds() { whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true) doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) } initializeTaskInfo(taskMinWidth = -1, taskMinHeight = -1) val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat()) Loading Loading @@ -361,7 +375,7 @@ class DragPositioningCallbackUtilityTest { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS) fun testChangeBoundsInDesktopMode_windowSizeExceedsStableBounds_shouldBeLimitedToDisplaySize() { whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true) doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) } val startingPoint = PointF(OFF_CENTER_STARTING_BOUNDS.right.toFloat(), OFF_CENTER_STARTING_BOUNDS.bottom.toFloat()) Loading
packages/SettingsLib/res/values/strings.xml +4 −4 Original line number Diff line number Diff line Loading @@ -1010,10 +1010,10 @@ <!-- UI debug setting: force allow on external summary [CHAR LIMIT=150] --> <string name="force_resizable_activities_summary">Make all activities resizable for multi-window, regardless of manifest values.</string> <!-- UI debug setting: enable freeform window support [CHAR LIMIT=50] --> <string name="enable_freeform_support">Enable freeform windows</string> <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] --> <string name="enable_freeform_support_summary">Enable support for experimental freeform windows.</string> <!-- UI debug setting: enable legacy freeform window support [CHAR LIMIT=50] --> <string name="enable_freeform_support">Enable freeform windows (legacy)</string> <!-- UI debug setting: enable legacy freeform window support summary [CHAR LIMIT=150] --> <string name="enable_freeform_support_summary">Enable support for experimental legacy freeform windows.</string> <!-- Local (desktop) backup password menu title [CHAR LIMIT=25] --> <string name="local_backup_password_title">Desktop backup password</string> Loading