Add dev option to force desktop mode
When turned on, this will:
- Enable system decorations on external screens
- Enable freeform windowing mode on external displays
- TODO: Show mouse pointer on external display
Bug: 112451761
Test: DisplaySettingsTests
Test: DesktopModePreferenceControllerTest
Test: FreeformWindowsPreferenceControllerTest
Change-Id: If46399b9d6b8faa2a11fbdf8a4bbfef1284147c8
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a30e38a..fb1edfb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9162,6 +9162,13 @@
public static final String DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT
= "enable_freeform_support";
+ /**
+ * Whether to enable experimental desktop mode on secondary displays.
+ * @hide
+ */
+ public static final String DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS =
+ "force_desktop_mode_on_external_displays";
+
/**
* Whether user has enabled development settings.
*/
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 69ebb59..e0e7b6f 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -270,6 +270,7 @@
optional SettingProto enable_freeform_windows_support = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto force_rtl = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto emulate_display_cutout = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto force_desktop_mode_on_external_displays = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Development development = 39;
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index d5dc903..9db7cf5 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -197,6 +197,7 @@
Settings.Global.DESK_DOCK_SOUND,
Settings.Global.DESK_UNDOCK_SOUND,
Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
+ Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
Settings.Global.DEVELOPMENT_FORCE_RTL,
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index b46c288..d4ae8e5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -481,6 +481,9 @@
dumpSetting(s, p,
Settings.Global.EMULATE_DISPLAY_CUTOUT,
GlobalSettingsProto.Development.EMULATE_DISPLAY_CUTOUT);
+ dumpSetting(s, p,
+ Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
+ GlobalSettingsProto.Development.FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS);
p.end(developmentToken);
final long deviceToken = p.start(GlobalSettingsProto.DEVICE);
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 5fb1def..d650871 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -1061,13 +1061,12 @@
}
/**
+ * Checks if system decorations should be shown on this display.
+ *
* @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
*/
boolean supportsSystemDecorations() {
- return mDisplay.supportsSystemDecorations()
- // TODO (b/111363427): Remove this and set the new FLAG_SHOULD_SHOW_LAUNCHER flag
- // (b/114338689) whenever vr 2d display id is set.
- || mDisplayId == mSupervisor.mService.mVr2dDisplayId;
+ return mWindowContainerController.supportsSystemDecorations();
}
private boolean shouldDestroyContentOnRemove() {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3359eac8..dc07a7c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -56,7 +56,6 @@
import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
-import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
@@ -652,8 +651,6 @@
ActivityTaskManager.supportsSplitScreenMultiWindow(mContext);
final boolean supportsMultiDisplay = mContext.getPackageManager()
.hasSystemFeature(FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
- final boolean alwaysFinishActivities =
- Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
final boolean forceResizable = Settings.Global.getInt(
resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 348b2af..570bd23 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4651,4 +4651,16 @@
pendingLayoutChanges |= changes;
}
+
+ /**
+ * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
+ */
+ boolean supportsSystemDecorations() {
+ // TODO(b/114338689): Read the setting from DisplaySettings.
+ return mDisplay.supportsSystemDecorations()
+ // TODO (b/111363427): Remove this and set the new FLAG_SHOULD_SHOW_LAUNCHER flag
+ // (b/114338689) whenever vr 2d display id is set.
+ || mDisplayId == mService.mVr2dDisplayId
+ || mService.mForceDesktopModeOnExternalDisplays;
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplaySettings.java b/services/core/java/com/android/server/wm/DisplaySettings.java
index 44956ab..624fbc7 100644
--- a/services/core/java/com/android/server/wm/DisplaySettings.java
+++ b/services/core/java/com/android/server/wm/DisplaySettings.java
@@ -185,15 +185,12 @@
}
// No record is present so use default windowing mode policy.
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- if (displayId == Display.DEFAULT_DISPLAY) {
- windowingMode = (mService.mIsPc && mService.mSupportsFreeformWindowManagement)
- ? WindowConfiguration.WINDOWING_MODE_FREEFORM
- : WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
- } else {
- windowingMode = mService.mSupportsFreeformWindowManagement
- ? WindowConfiguration.WINDOWING_MODE_FREEFORM
- : WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
- }
+ final boolean forceDesktopMode = mService.mForceDesktopModeOnExternalDisplays
+ && displayId != Display.DEFAULT_DISPLAY;
+ windowingMode = mService.mSupportsFreeformWindowManagement
+ && (mService.mIsPc || forceDesktopMode)
+ ? WindowConfiguration.WINDOWING_MODE_FREEFORM
+ : WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
}
return windowingMode;
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
index f772216..f4f4dd3 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -314,6 +314,17 @@
|| transit == TRANSIT_TASK_TO_FRONT;
}
+ /**
+ * Checks if system decorations should be shown on this display.
+ *
+ * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
+ */
+ public boolean supportsSystemDecorations() {
+ synchronized (mGlobalLock) {
+ return mContainer.supportsSystemDecorations();
+ }
+ }
+
@Override
public String toString() {
return "{DisplayWindowController displayId=" + mDisplayId + "}";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a641f75..73cdbd3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -29,6 +29,7 @@
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myPid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.DOCKED_INVALID;
@@ -538,12 +539,21 @@
int mDockedStackCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
Rect mDockedStackCreateBounds;
- boolean mForceResizableTasks = false;
- boolean mSupportsPictureInPicture = false;
- boolean mSupportsFreeformWindowManagement = false;
- boolean mIsPc = false;
+ boolean mForceResizableTasks;
+ boolean mSupportsPictureInPicture;
+ boolean mSupportsFreeformWindowManagement;
+ boolean mIsPc;
+ /**
+ * Flag that indicates that desktop mode is forced for public secondary screens.
+ *
+ * This includes several settings:
+ * - Set freeform windowing mode on external screen if it's supported and enabled.
+ * - Enable system decorations and IME on external screen.
+ * - TODO: Show mouse pointer on external screen.
+ */
+ boolean mForceDesktopModeOnExternalDisplays;
- boolean mDisableTransitionAnimation = false;
+ boolean mDisableTransitionAnimation;
int getDragLayerLocked() {
return mPolicy.getWindowLayerFromTypeLw(TYPE_DRAG) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
@@ -976,17 +986,21 @@
}
}, UserHandle.ALL, suspendPackagesFilter, null, null);
+ final ContentResolver resolver = context.getContentResolver();
// Get persisted window scale setting
- mWindowAnimationScaleSetting = Settings.Global.getFloat(context.getContentResolver(),
+ mWindowAnimationScaleSetting = Settings.Global.getFloat(resolver,
Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);
- mTransitionAnimationScaleSetting = Settings.Global.getFloat(context.getContentResolver(),
+ mTransitionAnimationScaleSetting = Settings.Global.getFloat(resolver,
Settings.Global.TRANSITION_ANIMATION_SCALE,
context.getResources().getFloat(
R.dimen.config_appTransitionAnimationDurationScaleDefault));
- setAnimatorDurationScale(Settings.Global.getFloat(context.getContentResolver(),
+ setAnimatorDurationScale(Settings.Global.getFloat(resolver,
Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting));
+ mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver,
+ DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;
+
IntentFilter filter = new IntentFilter();
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
filter.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
@@ -6406,6 +6420,12 @@
}
}
+ void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
+ synchronized (mWindowMap) {
+ mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
+ }
+ }
+
public void setIsPc(boolean isPc) {
synchronized (mGlobalLock) {
mIsPc = isPc;
@@ -6584,10 +6604,10 @@
final long token = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final DisplayContent dc = getDisplayContentOrCreate(displayId, null);
+ final DisplayContent dc = getDisplayContentOrCreate(displayId, null /* token */);
if (dc == null) {
throw new IllegalArgumentException(
- "Trying to register a non existent display.");
+ "Trying to configure a non existent display.");
}
// We usually set the override info in DisplayManager so that we get consistent
// values when displays are changing. However, we don't do this for displays that
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
index f0c49c8..5808bc9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
@@ -64,6 +64,7 @@
mWm.setSupportsFreeformWindowManagement(false);
mWm.setIsPc(false);
+ mWm.setForceDesktopModeOnExternalDisplays(false);
mTarget = new DisplaySettings(mWm, TEST_FOLDER);
@@ -78,7 +79,7 @@
}
@Test
- public void testPrimaryDisplayDefaultToFullscreenWithoutFreeformSupport() {
+ public void testPrimaryDisplayDefaultToFullscreen_NoFreeformSupport() {
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
@@ -86,7 +87,7 @@
}
@Test
- public void testPrimaryDisplayDefaultToFullscreenWithFreeformSupportNonPc() {
+ public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_NoDesktopMode() {
mWm.setSupportsFreeformWindowManagement(true);
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -96,7 +97,18 @@
}
@Test
- public void testPrimaryDisplayDefaultToFreeformWithFreeformIsPc() {
+ public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_HasDesktopMode() {
+ mWm.setSupportsFreeformWindowManagement(true);
+ mWm.setForceDesktopModeOnExternalDisplays(true);
+
+ mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+
+ assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
+ mPrimaryDisplay.getWindowingMode());
+ }
+
+ @Test
+ public void testPrimaryDisplayDefaultToFreeform_HasFreeformSupport_IsPc() {
mWm.setSupportsFreeformWindowManagement(true);
mWm.setIsPc(true);
@@ -107,7 +119,7 @@
}
@Test
- public void testSecondaryDisplayDefaultToFullscreenWithoutFreeformSupport() {
+ public void testSecondaryDisplayDefaultToFullscreen_NoFreeformSupport() {
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
@@ -115,17 +127,28 @@
}
@Test
- public void testSecondaryDisplayDefaultToFreeformWithFreeformSupportNonPc() {
+ public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_NoDesktopMode() {
mWm.setSupportsFreeformWindowManagement(true);
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
+ mSecondaryDisplay.getWindowingMode());
+ }
+
+ @Test
+ public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_HasDesktopMode() {
+ mWm.setSupportsFreeformWindowManagement(true);
+ mWm.setForceDesktopModeOnExternalDisplays(true);
+
+ mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+
assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
mSecondaryDisplay.getWindowingMode());
}
@Test
- public void testSecondaryDisplayDefaultToFreeformWithFreeformSupportIsPc() {
+ public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_IsPc() {
mWm.setSupportsFreeformWindowManagement(true);
mWm.setIsPc(true);