Add observer for WindowManager developer options

Some WM-related developer options write a setting entry, which is
initialized only at system boot. We need to reboot after the setting
chanaged. The CL register an observer to "Enable freeform windows",
"Force desktop mode" and "Force resizable activities". It will take
effect after setting changed without reboot.

Bug: 129279411
Test: A. atest WmTests:WindowManagerSettingsTests
      B. Manual test.
         1. Enable "Force desktop mode",Freefome window","Force resizable activities" from
	    developer option.
         2. connect mouse (USB or Bluetooth).
         3. Create simulated display from developer options.
         4. Launch activities from launcher on simulated display and interact with mouse.

Change-Id: I7b5e15f548de5c2f163a1816020fe46756968f5e
This commit is contained in:
Jeff Chang
2019-07-10 11:38:05 +08:00
parent e303b21732
commit 0c53e5e568
2 changed files with 168 additions and 1 deletions

View File

@@ -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;

View File

@@ -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);
}
}
}