diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d49d24545666e..fa1ace630856e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -28,6 +28,7 @@ import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LE import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.StatusBarManager.DISABLE_MASK; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; +import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; import static android.content.pm.PackageManager.FEATURE_PC; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; @@ -36,7 +37,9 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE; import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP; import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS; +import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; +import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.DOCKED_INVALID; @@ -666,7 +669,8 @@ public class WindowManagerService extends IWindowManager.Stub WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; SettingsObserver mSettingsObserver; - private final class SettingsObserver extends ContentObserver { + @VisibleForTesting + final class SettingsObserver extends ContentObserver { private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); private final Uri mWindowAnimationScaleUri = @@ -681,6 +685,12 @@ public class WindowManagerService extends IWindowManager.Stub Settings.Global.getUriFor(Settings.Global.POLICY_CONTROL); private final Uri mPointerLocationUri = Settings.System.getUriFor(Settings.System.POINTER_LOCATION); + private final Uri mForceDesktopModeOnExternalDisplaysUri = Settings.Global.getUriFor( + Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS); + private final Uri mFreeformWindowUri = Settings.Global.getUriFor( + Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT); + private final Uri mForceResizableUri = Settings.Global.getUriFor( + DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES); public SettingsObserver() { super(new Handler()); @@ -697,6 +707,10 @@ public class WindowManagerService extends IWindowManager.Stub UserHandle.USER_ALL); resolver.registerContentObserver(mPolicyControlUri, false, this, UserHandle.USER_ALL); resolver.registerContentObserver(mPointerLocationUri, false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(mForceDesktopModeOnExternalDisplaysUri, false, this, + UserHandle.USER_ALL); + resolver.registerContentObserver(mFreeformWindowUri, false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(mForceResizableUri, false, this, UserHandle.USER_ALL); } @Override @@ -720,6 +734,21 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mForceDesktopModeOnExternalDisplaysUri.equals(uri)) { + updateForceDesktopModeOnExternalDisplays(); + return; + } + + if (mFreeformWindowUri.equals(uri)) { + updateFreeformWindowManagement(); + return; + } + + if (mForceResizableUri.equals(uri)) { + updateForceResizableTasks(); + return; + } + @UpdateAnimationScaleMode final int mode; if (mWindowAnimationScaleUri.equals(uri)) { @@ -762,6 +791,33 @@ public class WindowManagerService extends IWindowManager.Stub mPointerLocationEnabled)); } } + + void updateForceDesktopModeOnExternalDisplays() { + ContentResolver resolver = mContext.getContentResolver(); + final boolean enableForceDesktopMode = Settings.Global.getInt(resolver, + DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0; + if (mForceDesktopModeOnExternalDisplays == enableForceDesktopMode) { + return; + } + setForceDesktopModeOnExternalDisplays(enableForceDesktopMode); + } + + void updateFreeformWindowManagement() { + ContentResolver resolver = mContext.getContentResolver(); + final boolean freeformWindowManagement = mContext.getPackageManager().hasSystemFeature( + FEATURE_FREEFORM_WINDOW_MANAGEMENT) || Settings.Global.getInt( + resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0; + + mAtmService.mSupportsFreeformWindowManagement = freeformWindowManagement; + } + + void updateForceResizableTasks() { + ContentResolver resolver = mContext.getContentResolver(); + final boolean forceResizable = Settings.Global.getInt(resolver, + DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0; + + mAtmService.mForceResizableActivities = forceResizable; + } } PowerManager mPowerManager; diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java new file mode 100644 index 0000000000000..86f0f8bc1bb9b --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2019 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.server.wm; + +import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; +import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; +import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertEquals; + +import android.content.ContentResolver; +import android.net.Uri; +import android.provider.Settings; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Test for {@link WindowManagerService.SettingsObserver}. + * + * Build/Install/Run: + * atest WmTests:WindowManagerSettingsTests + */ +@SmallTest +public class WindowManagerSettingsTests extends WindowTestsBase { + + @Test + public void testForceDesktopModeOnExternalDisplays() { + try (SettingsSession forceDesktopModeSession = new + SettingsSession(DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS)) { + final boolean forceDesktopMode = !forceDesktopModeSession.getSetting(); + final Uri forceDesktopModeUri = forceDesktopModeSession.setSetting(forceDesktopMode); + mWm.mSettingsObserver.onChange(false, forceDesktopModeUri); + + assertEquals(mWm.mForceDesktopModeOnExternalDisplays, forceDesktopMode); + } + } + + @Test + public void testFreeformWindow() { + try (SettingsSession freeformWindowSession = new + SettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) { + final boolean freeformWindow = !freeformWindowSession.getSetting(); + final Uri freeformWindowUri = freeformWindowSession.setSetting(freeformWindow); + mWm.mSettingsObserver.onChange(false, freeformWindowUri); + + assertEquals(mWm.mAtmService.mSupportsFreeformWindowManagement, freeformWindow); + } + } + + @Test + public void testForceResizableMode() { + try (SettingsSession forceResizableSession = new + SettingsSession(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES)) { + final boolean forceResizableMode = !forceResizableSession.getSetting(); + final Uri forceResizableUri = forceResizableSession.setSetting(forceResizableMode); + mWm.mSettingsObserver.onChange(false, forceResizableUri); + + assertEquals(mWm.mAtmService.mForceResizableActivities, forceResizableMode); + } + } + + private class SettingsSession implements AutoCloseable { + + private static final int SETTING_VALUE_OFF = 0; + private static final int SETTING_VALUE_ON = 1; + private final String mSettingName; + private final int mInitialValue; + + SettingsSession(String name) { + mSettingName = name; + mInitialValue = getSetting() ? SETTING_VALUE_ON : SETTING_VALUE_OFF; + } + + boolean getSetting() { + return Settings.Global.getInt(getContentResolver(), mSettingName, 0) != 0; + } + + Uri setSetting(boolean enable) { + Settings.Global.putInt(getContentResolver(), mSettingName, + enable ? SETTING_VALUE_ON : SETTING_VALUE_OFF); + return Settings.Global.getUriFor(mSettingName); + } + + private ContentResolver getContentResolver() { + return getInstrumentation().getTargetContext().getContentResolver(); + } + + @Override + public void close() { + setSetting(mInitialValue == SETTING_VALUE_ON); + } + } +}