Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt +24 −46 Original line number Diff line number Diff line Loading @@ -17,20 +17,16 @@ package com.android.wm.shell.shared.desktopmode import android.content.Context import android.os.SystemProperties import android.provider.Settings import android.util.Log import com.android.window.flags.Flags /** * Util to check desktop mode flags state. * * This utility is used to allow developer option toggles to override flags related to Desktop * Windowing. /* * A shared class to check desktop mode flags state. * * Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag * The class computes whether a Desktop Windowing flag should be enabled by using the aconfig flag * value and the developer option override state (if applicable). */ **/ enum class DesktopModeFlags( // Function called to obtain aconfig flag value. private val flagFunction: () -> Boolean, Loading Loading @@ -71,52 +67,35 @@ enum class DesktopModeFlags( // Cache toggle override the first time we encounter context. Override does not change // with context, as context is just used to fetch System Property and Settings.Global cachedToggleOverride = override Log.d(TAG, "Local toggle override initialized to: $override") Log.d(TAG, "Toggle override initialized to: $override") override } return override } /** * Returns [ToggleOverride] from a non-persistent system property if present. Otherwise * initializes the system property by reading Settings.Global. */ private fun getToggleOverrideFromSystem(context: Context): ToggleOverride { // A non-persistent System Property is used to store override to ensure it remains // constant till reboot. val overrideFromSystemProperties: ToggleOverride? = SystemProperties.getInt(SYSTEM_PROPERTY_OVERRIDE_KEY, INVALID_TOGGLE_OVERRIDE_SETTING) .convertToToggleOverride() System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null).convertToToggleOverride() return overrideFromSystemProperties ?: run { // TODO(b/348193756): Remove the initialization after adding it in core. If // SystemProperty is still not present then return OVERRIDE_UNSET // Initialize System Property if not present (just after reboot) initializeOverrideInSystemProperty(context) } } /** Initializes Override System property based on Settings.Global set by toggle. */ private fun initializeOverrideInSystemProperty(context: Context): ToggleOverride { val settingValue = // Read Setting Global if System Property is not present (just after reboot) // or not valid (user manually changed the value) val overrideFromSettingsGlobal = convertToToggleOverrideWithFallback( Settings.Global.getInt( context.contentResolver, Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, ToggleOverride.OVERRIDE_UNSET.setting) try { SystemProperties.set(SYSTEM_PROPERTY_OVERRIDE_KEY, settingValue.toString()) Log.d(TAG, "Initialized system property with override setting: $settingValue") } catch (e: RuntimeException) { // Thrown in device tests that don't mock SystemProperties Log.w( TAG, "Failed to set a system property: key=$SYSTEM_PROPERTY_OVERRIDE_KEY, " + "value=$settingValue, message=${e.message}") } ToggleOverride.OVERRIDE_UNSET.setting), ToggleOverride.OVERRIDE_UNSET) // Initialize System Property System.setProperty( SYSTEM_PROPERTY_OVERRIDE_KEY, overrideFromSettingsGlobal.setting.toString()) return convertToToggleOverrideWithFallback(settingValue, ToggleOverride.OVERRIDE_UNSET) overrideFromSettingsGlobal } } /** Loading @@ -134,10 +113,11 @@ enum class DesktopModeFlags( OVERRIDE_ON(1) } private fun Int.convertToToggleOverride(): ToggleOverride? { return settingToToggleOverrideMap[this] private fun String?.convertToToggleOverride(): ToggleOverride? { val intValue = this?.toIntOrNull() ?: return null return settingToToggleOverrideMap[intValue] ?: run { Log.w(TAG, "Unknown toggleOverride int $this") Log.w(TAG, "Unknown toggleOverride int $intValue") null } } Loading @@ -151,8 +131,6 @@ enum class DesktopModeFlags( */ private const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override" private const val INVALID_TOGGLE_OVERRIDE_SETTING = -2 /** * Local cache for toggle override, which is initialized once on its first access. It needs to * be refreshed only on reboots as overridden state takes effect on reboots. Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt +41 −51 Original line number Diff line number Diff line Loading @@ -16,15 +16,12 @@ package com.android.wm.shell.shared.desktopmode import android.os.SystemProperties import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import android.provider.Settings import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.modules.utils.testing.ExtendedMockitoRule import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY import com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION Loading @@ -40,9 +37,6 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito import org.mockito.kotlin.any import org.mockito.kotlin.eq /** * Test class for [DesktopModeFlags] Loading @@ -53,14 +47,7 @@ import org.mockito.kotlin.eq @RunWith(AndroidTestingRunner::class) class DesktopModeFlagsTest : ShellTestCase() { @Rule(order = 1) @JvmField val setFlagsRule = SetFlagsRule() @Rule(order = 2) @JvmField val extendedMockitoRule: ExtendedMockitoRule = ExtendedMockitoRule.Builder(this).mockStatic(SystemProperties::class.java).build() @JvmField @Rule val setFlagsRule = SetFlagsRule() @Before fun setUp() { Loading Loading @@ -132,7 +119,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_unrecognizableOverride_featureFlagOn_returnsTrue() { setOverride(INVALID_TOGGLE_OVERRIDE_SETTING) setOverride(-2) // For overridableFlag, for recognizable overrides, follow flag assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() Loading @@ -142,7 +129,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_unrecognizableOverride_featureFlagOff_returnsFalse() { setOverride(INVALID_TOGGLE_OVERRIDE_SETTING) setOverride(-2) // For overridableFlag, for recognizable overrides, follow flag assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() Loading Loading @@ -200,82 +187,102 @@ class DesktopModeFlagsTest : ShellTestCase() { @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_noSystemProperty_overrideOn_featureFlagOff_returnsTrueAndStoresPropertyOn() { setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING) System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_ON.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() // Store System Property if not present verifySystemPropertySet(OVERRIDE_ON.setting) assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_ON.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_noSystemProperty_overrideUnset_featureFlagOn_returnsTrueAndStoresPropertyUnset() { setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING) System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_UNSET.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() // Store System Property if not present verifySystemPropertySet(OVERRIDE_UNSET.setting) assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_UNSET.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_noSystemProperty_overrideUnset_featureFlagOff_returnsFalseAndStoresPropertyUnset() { setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING) System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_UNSET.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() // Store System Property if not present verifySystemPropertySet(OVERRIDE_UNSET.setting) assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_UNSET.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) @Suppress("ktlint:standard:max-line-length") fun isEnabled_systemPropertyNotInteger_overrideOff_featureFlagOn_returnsFalseAndStoresPropertyOff() { System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "abc") setOverride(OVERRIDE_OFF.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() // Store System Property if currently invalid assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_OFF.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) @Suppress("ktlint:standard:max-line-length") fun isEnabled_systemPropertyInvalidInteger_overrideOff_featureFlagOn_returnsFalseAndStoresPropertyOff() { setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING) System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "-2") setOverride(OVERRIDE_OFF.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() // Store System Property if currently invalid verifySystemPropertySet(OVERRIDE_OFF.setting) assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_OFF.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_systemPropertyOff_overrideOn_featureFlagOn_returnsFalseAndDoesNotUpdateProperty() { setSystemProperty(OVERRIDE_OFF.setting) System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_OFF.setting.toString()) setOverride(OVERRIDE_ON.setting) // Have a consistent override until reboot assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() verifySystemPropertyNotUpdated() assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_OFF.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_systemPropertyOn_overrideOff_featureFlagOff_returnsTrueAndDoesNotUpdateProperty() { setSystemProperty(OVERRIDE_ON.setting) System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_ON.setting.toString()) setOverride(OVERRIDE_OFF.setting) // Have a consistent override until reboot assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() verifySystemPropertyNotUpdated() assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_ON.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) @Suppress("ktlint:standard:max-line-length") fun isEnabled_systemPropertyUnset_overrideOff_featureFlagOn_returnsTrueAndDoesNotUpdateProperty() { setSystemProperty(OVERRIDE_UNSET.setting) System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_UNSET.setting.toString()) setOverride(OVERRIDE_OFF.setting) // Have a consistent override until reboot assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() verifySystemPropertyNotUpdated() assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_UNSET.setting.toString()) } @Test Loading Loading @@ -434,33 +441,16 @@ class DesktopModeFlagsTest : ShellTestCase() { } private fun resetCache() { val cachedToggleOverride = DesktopModeFlags::class.java.getDeclaredField("cachedToggleOverride") val cachedToggleOverride = DesktopModeFlags::class.java.getDeclaredField("cachedToggleOverride") cachedToggleOverride.isAccessible = true cachedToggleOverride.set(null, null) setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING) } private fun setSystemProperty(systemProperty: Int) { ExtendedMockito.doReturn(systemProperty).`when` { SystemProperties.getInt(eq(SYSTEM_PROPERTY_OVERRIDE_KEY), any()) } } private fun verifySystemPropertySet(systemProperty: Int) { ExtendedMockito.verify { SystemProperties.set(eq(SYSTEM_PROPERTY_OVERRIDE_KEY), eq(systemProperty.toString())) } } private fun verifySystemPropertyNotUpdated() { ExtendedMockito.verify( { SystemProperties.set(eq(SYSTEM_PROPERTY_OVERRIDE_KEY), any()) }, Mockito.never()) // Clear override cache stored in System property System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) } private companion object { const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override" const val INVALID_TOGGLE_OVERRIDE_SETTING = -2 } } services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java +37 −32 Original line number Diff line number Diff line Loading @@ -18,8 +18,8 @@ package com.android.server.wm.utils; import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET; import android.annotation.Nullable; import android.content.Context; import android.os.SystemProperties; import android.provider.Settings; import android.util.Log; Loading @@ -29,12 +29,14 @@ import java.util.function.Supplier; /** * Util to check desktop mode flags state. * <p> This utility is used to allow developer option toggles to override flags related to desktop * * This utility is used to allow developer option toggles to override flags related to desktop * windowing. * <p> Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag * * Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag * value and the developer option override state (if applicable). * <p> This is a partial copy of {@link com.android.wm.shell.shared.desktopmode.DesktopModeFlags} * which * * This is a partial copy of {@link com.android.wm.shell.shared.desktopmode.DesktopModeFlags} which * is to be used in WM core. */ public enum DesktopModeFlagsUtil { Loading Loading @@ -95,7 +97,7 @@ public enum DesktopModeFlagsUtil { // Otherwise, fetch and cache it ToggleOverride override = getToggleOverrideFromSystem(context); sCachedToggleOverride = override; Log.d(TAG, "Local Toggle override initialized to: " + override); Log.d(TAG, "Toggle override initialized to: " + override); return override; } Loading @@ -106,40 +108,43 @@ public enum DesktopModeFlagsUtil { private ToggleOverride getToggleOverrideFromSystem(Context context) { // A non-persistent System Property is used to store override to ensure it remains // constant till reboot. int overrideProperty = SystemProperties.getInt(SYSTEM_PROPERTY_OVERRIDE_KEY, -2); ToggleOverride overrideFromSystemProperties = ToggleOverride.fromSetting(overrideProperty, null); // Initialize System Property if not present (just after reboot) if (overrideFromSystemProperties == null) { return initializeOverrideInSystemProperty(context); } String overrideProperty = System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null); ToggleOverride overrideFromSystemProperties = convertToToggleOverride(overrideProperty); // If valid system property, return it if (overrideFromSystemProperties != null) { return overrideFromSystemProperties; } /** * Initializes Override System property based on Settings.Global set by toggle. */ // TODO(b/348193756): Make this method public, and call it in WindowManagerService constructor // to ensure initialization. private static ToggleOverride initializeOverrideInSystemProperty(Context context) { // Fallback when System Property is not present (just after reboot) or not valid (user // manually changed the value): Read from Settings.Global int settingValue = Settings.Global.getInt( context.getContentResolver(), Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, OVERRIDE_UNSET.getSetting() ); ToggleOverride overrideFromSettingsGlobal = ToggleOverride.fromSetting(settingValue, OVERRIDE_UNSET); // Initialize System Property System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, String.valueOf(settingValue)); return overrideFromSettingsGlobal; } /** * Converts {@code intString} into {@link ToggleOverride}. Return {@code null} if * {@code intString} does not correspond to a {@link ToggleOverride}. */ private static @Nullable ToggleOverride convertToToggleOverride( @Nullable String intString ) { if (intString == null) return null; try { SystemProperties.set(SYSTEM_PROPERTY_OVERRIDE_KEY, String.valueOf(settingValue)); Log.d(TAG, "Initialize system property with override setting: " + settingValue); } catch (RuntimeException e) { // Thrown in device tests that don't mock SystemProperties Log.w(TAG, "Failed to set a system property: key=" + SYSTEM_PROPERTY_OVERRIDE_KEY + " value=" + settingValue + " " + e.getMessage()); int intValue = Integer.parseInt(intString); return ToggleOverride.fromSetting(intValue, null); } catch (NumberFormatException e) { Log.w(TAG, "Unknown toggleOverride int " + intString); return null; } return ToggleOverride.fromSetting(settingValue, OVERRIDE_UNSET); } /** Override state of desktop mode developer option toggle. */ Loading @@ -156,7 +161,7 @@ public enum DesktopModeFlagsUtil { }; } static ToggleOverride fromSetting(int setting, ToggleOverride fallback) { static ToggleOverride fromSetting(int setting, @Nullable ToggleOverride fallback) { return switch (setting) { case 1 -> OVERRIDE_ON; case 0 -> OVERRIDE_OFF; Loading services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +0 −2 Original line number Diff line number Diff line Loading @@ -68,7 +68,6 @@ import android.os.PowerManager; import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.StrictMode; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.DeviceConfig; Loading Loading @@ -205,7 +204,6 @@ public class SystemServicesTestRule implements TestRule { .mockStatic(Watchdog.class, mockStubOnly) .spyStatic(DesktopModeHelper.class) .spyStatic(DesktopModeBoundsCalculator.class) .spyStatic(SystemProperties.class) .strictness(Strictness.LENIENT) .startMocking(); Loading services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java +51 −51 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt +24 −46 Original line number Diff line number Diff line Loading @@ -17,20 +17,16 @@ package com.android.wm.shell.shared.desktopmode import android.content.Context import android.os.SystemProperties import android.provider.Settings import android.util.Log import com.android.window.flags.Flags /** * Util to check desktop mode flags state. * * This utility is used to allow developer option toggles to override flags related to Desktop * Windowing. /* * A shared class to check desktop mode flags state. * * Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag * The class computes whether a Desktop Windowing flag should be enabled by using the aconfig flag * value and the developer option override state (if applicable). */ **/ enum class DesktopModeFlags( // Function called to obtain aconfig flag value. private val flagFunction: () -> Boolean, Loading Loading @@ -71,52 +67,35 @@ enum class DesktopModeFlags( // Cache toggle override the first time we encounter context. Override does not change // with context, as context is just used to fetch System Property and Settings.Global cachedToggleOverride = override Log.d(TAG, "Local toggle override initialized to: $override") Log.d(TAG, "Toggle override initialized to: $override") override } return override } /** * Returns [ToggleOverride] from a non-persistent system property if present. Otherwise * initializes the system property by reading Settings.Global. */ private fun getToggleOverrideFromSystem(context: Context): ToggleOverride { // A non-persistent System Property is used to store override to ensure it remains // constant till reboot. val overrideFromSystemProperties: ToggleOverride? = SystemProperties.getInt(SYSTEM_PROPERTY_OVERRIDE_KEY, INVALID_TOGGLE_OVERRIDE_SETTING) .convertToToggleOverride() System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null).convertToToggleOverride() return overrideFromSystemProperties ?: run { // TODO(b/348193756): Remove the initialization after adding it in core. If // SystemProperty is still not present then return OVERRIDE_UNSET // Initialize System Property if not present (just after reboot) initializeOverrideInSystemProperty(context) } } /** Initializes Override System property based on Settings.Global set by toggle. */ private fun initializeOverrideInSystemProperty(context: Context): ToggleOverride { val settingValue = // Read Setting Global if System Property is not present (just after reboot) // or not valid (user manually changed the value) val overrideFromSettingsGlobal = convertToToggleOverrideWithFallback( Settings.Global.getInt( context.contentResolver, Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, ToggleOverride.OVERRIDE_UNSET.setting) try { SystemProperties.set(SYSTEM_PROPERTY_OVERRIDE_KEY, settingValue.toString()) Log.d(TAG, "Initialized system property with override setting: $settingValue") } catch (e: RuntimeException) { // Thrown in device tests that don't mock SystemProperties Log.w( TAG, "Failed to set a system property: key=$SYSTEM_PROPERTY_OVERRIDE_KEY, " + "value=$settingValue, message=${e.message}") } ToggleOverride.OVERRIDE_UNSET.setting), ToggleOverride.OVERRIDE_UNSET) // Initialize System Property System.setProperty( SYSTEM_PROPERTY_OVERRIDE_KEY, overrideFromSettingsGlobal.setting.toString()) return convertToToggleOverrideWithFallback(settingValue, ToggleOverride.OVERRIDE_UNSET) overrideFromSettingsGlobal } } /** Loading @@ -134,10 +113,11 @@ enum class DesktopModeFlags( OVERRIDE_ON(1) } private fun Int.convertToToggleOverride(): ToggleOverride? { return settingToToggleOverrideMap[this] private fun String?.convertToToggleOverride(): ToggleOverride? { val intValue = this?.toIntOrNull() ?: return null return settingToToggleOverrideMap[intValue] ?: run { Log.w(TAG, "Unknown toggleOverride int $this") Log.w(TAG, "Unknown toggleOverride int $intValue") null } } Loading @@ -151,8 +131,6 @@ enum class DesktopModeFlags( */ private const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override" private const val INVALID_TOGGLE_OVERRIDE_SETTING = -2 /** * Local cache for toggle override, which is initialized once on its first access. It needs to * be refreshed only on reboots as overridden state takes effect on reboots. Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt +41 −51 Original line number Diff line number Diff line Loading @@ -16,15 +16,12 @@ package com.android.wm.shell.shared.desktopmode import android.os.SystemProperties import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import android.provider.Settings import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.modules.utils.testing.ExtendedMockitoRule import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY import com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION Loading @@ -40,9 +37,6 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito import org.mockito.kotlin.any import org.mockito.kotlin.eq /** * Test class for [DesktopModeFlags] Loading @@ -53,14 +47,7 @@ import org.mockito.kotlin.eq @RunWith(AndroidTestingRunner::class) class DesktopModeFlagsTest : ShellTestCase() { @Rule(order = 1) @JvmField val setFlagsRule = SetFlagsRule() @Rule(order = 2) @JvmField val extendedMockitoRule: ExtendedMockitoRule = ExtendedMockitoRule.Builder(this).mockStatic(SystemProperties::class.java).build() @JvmField @Rule val setFlagsRule = SetFlagsRule() @Before fun setUp() { Loading Loading @@ -132,7 +119,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_unrecognizableOverride_featureFlagOn_returnsTrue() { setOverride(INVALID_TOGGLE_OVERRIDE_SETTING) setOverride(-2) // For overridableFlag, for recognizable overrides, follow flag assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() Loading @@ -142,7 +129,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_unrecognizableOverride_featureFlagOff_returnsFalse() { setOverride(INVALID_TOGGLE_OVERRIDE_SETTING) setOverride(-2) // For overridableFlag, for recognizable overrides, follow flag assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() Loading Loading @@ -200,82 +187,102 @@ class DesktopModeFlagsTest : ShellTestCase() { @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_noSystemProperty_overrideOn_featureFlagOff_returnsTrueAndStoresPropertyOn() { setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING) System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_ON.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() // Store System Property if not present verifySystemPropertySet(OVERRIDE_ON.setting) assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_ON.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_noSystemProperty_overrideUnset_featureFlagOn_returnsTrueAndStoresPropertyUnset() { setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING) System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_UNSET.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() // Store System Property if not present verifySystemPropertySet(OVERRIDE_UNSET.setting) assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_UNSET.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_noSystemProperty_overrideUnset_featureFlagOff_returnsFalseAndStoresPropertyUnset() { setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING) System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_UNSET.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() // Store System Property if not present verifySystemPropertySet(OVERRIDE_UNSET.setting) assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_UNSET.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) @Suppress("ktlint:standard:max-line-length") fun isEnabled_systemPropertyNotInteger_overrideOff_featureFlagOn_returnsFalseAndStoresPropertyOff() { System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "abc") setOverride(OVERRIDE_OFF.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() // Store System Property if currently invalid assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_OFF.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) @Suppress("ktlint:standard:max-line-length") fun isEnabled_systemPropertyInvalidInteger_overrideOff_featureFlagOn_returnsFalseAndStoresPropertyOff() { setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING) System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "-2") setOverride(OVERRIDE_OFF.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() // Store System Property if currently invalid verifySystemPropertySet(OVERRIDE_OFF.setting) assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_OFF.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_systemPropertyOff_overrideOn_featureFlagOn_returnsFalseAndDoesNotUpdateProperty() { setSystemProperty(OVERRIDE_OFF.setting) System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_OFF.setting.toString()) setOverride(OVERRIDE_ON.setting) // Have a consistent override until reboot assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() verifySystemPropertyNotUpdated() assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_OFF.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_systemPropertyOn_overrideOff_featureFlagOff_returnsTrueAndDoesNotUpdateProperty() { setSystemProperty(OVERRIDE_ON.setting) System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_ON.setting.toString()) setOverride(OVERRIDE_OFF.setting) // Have a consistent override until reboot assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() verifySystemPropertyNotUpdated() assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_ON.setting.toString()) } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) @Suppress("ktlint:standard:max-line-length") fun isEnabled_systemPropertyUnset_overrideOff_featureFlagOn_returnsTrueAndDoesNotUpdateProperty() { setSystemProperty(OVERRIDE_UNSET.setting) System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_UNSET.setting.toString()) setOverride(OVERRIDE_OFF.setting) // Have a consistent override until reboot assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() verifySystemPropertyNotUpdated() assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_UNSET.setting.toString()) } @Test Loading Loading @@ -434,33 +441,16 @@ class DesktopModeFlagsTest : ShellTestCase() { } private fun resetCache() { val cachedToggleOverride = DesktopModeFlags::class.java.getDeclaredField("cachedToggleOverride") val cachedToggleOverride = DesktopModeFlags::class.java.getDeclaredField("cachedToggleOverride") cachedToggleOverride.isAccessible = true cachedToggleOverride.set(null, null) setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING) } private fun setSystemProperty(systemProperty: Int) { ExtendedMockito.doReturn(systemProperty).`when` { SystemProperties.getInt(eq(SYSTEM_PROPERTY_OVERRIDE_KEY), any()) } } private fun verifySystemPropertySet(systemProperty: Int) { ExtendedMockito.verify { SystemProperties.set(eq(SYSTEM_PROPERTY_OVERRIDE_KEY), eq(systemProperty.toString())) } } private fun verifySystemPropertyNotUpdated() { ExtendedMockito.verify( { SystemProperties.set(eq(SYSTEM_PROPERTY_OVERRIDE_KEY), any()) }, Mockito.never()) // Clear override cache stored in System property System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) } private companion object { const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override" const val INVALID_TOGGLE_OVERRIDE_SETTING = -2 } }
services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java +37 −32 Original line number Diff line number Diff line Loading @@ -18,8 +18,8 @@ package com.android.server.wm.utils; import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET; import android.annotation.Nullable; import android.content.Context; import android.os.SystemProperties; import android.provider.Settings; import android.util.Log; Loading @@ -29,12 +29,14 @@ import java.util.function.Supplier; /** * Util to check desktop mode flags state. * <p> This utility is used to allow developer option toggles to override flags related to desktop * * This utility is used to allow developer option toggles to override flags related to desktop * windowing. * <p> Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag * * Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag * value and the developer option override state (if applicable). * <p> This is a partial copy of {@link com.android.wm.shell.shared.desktopmode.DesktopModeFlags} * which * * This is a partial copy of {@link com.android.wm.shell.shared.desktopmode.DesktopModeFlags} which * is to be used in WM core. */ public enum DesktopModeFlagsUtil { Loading Loading @@ -95,7 +97,7 @@ public enum DesktopModeFlagsUtil { // Otherwise, fetch and cache it ToggleOverride override = getToggleOverrideFromSystem(context); sCachedToggleOverride = override; Log.d(TAG, "Local Toggle override initialized to: " + override); Log.d(TAG, "Toggle override initialized to: " + override); return override; } Loading @@ -106,40 +108,43 @@ public enum DesktopModeFlagsUtil { private ToggleOverride getToggleOverrideFromSystem(Context context) { // A non-persistent System Property is used to store override to ensure it remains // constant till reboot. int overrideProperty = SystemProperties.getInt(SYSTEM_PROPERTY_OVERRIDE_KEY, -2); ToggleOverride overrideFromSystemProperties = ToggleOverride.fromSetting(overrideProperty, null); // Initialize System Property if not present (just after reboot) if (overrideFromSystemProperties == null) { return initializeOverrideInSystemProperty(context); } String overrideProperty = System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null); ToggleOverride overrideFromSystemProperties = convertToToggleOverride(overrideProperty); // If valid system property, return it if (overrideFromSystemProperties != null) { return overrideFromSystemProperties; } /** * Initializes Override System property based on Settings.Global set by toggle. */ // TODO(b/348193756): Make this method public, and call it in WindowManagerService constructor // to ensure initialization. private static ToggleOverride initializeOverrideInSystemProperty(Context context) { // Fallback when System Property is not present (just after reboot) or not valid (user // manually changed the value): Read from Settings.Global int settingValue = Settings.Global.getInt( context.getContentResolver(), Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, OVERRIDE_UNSET.getSetting() ); ToggleOverride overrideFromSettingsGlobal = ToggleOverride.fromSetting(settingValue, OVERRIDE_UNSET); // Initialize System Property System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, String.valueOf(settingValue)); return overrideFromSettingsGlobal; } /** * Converts {@code intString} into {@link ToggleOverride}. Return {@code null} if * {@code intString} does not correspond to a {@link ToggleOverride}. */ private static @Nullable ToggleOverride convertToToggleOverride( @Nullable String intString ) { if (intString == null) return null; try { SystemProperties.set(SYSTEM_PROPERTY_OVERRIDE_KEY, String.valueOf(settingValue)); Log.d(TAG, "Initialize system property with override setting: " + settingValue); } catch (RuntimeException e) { // Thrown in device tests that don't mock SystemProperties Log.w(TAG, "Failed to set a system property: key=" + SYSTEM_PROPERTY_OVERRIDE_KEY + " value=" + settingValue + " " + e.getMessage()); int intValue = Integer.parseInt(intString); return ToggleOverride.fromSetting(intValue, null); } catch (NumberFormatException e) { Log.w(TAG, "Unknown toggleOverride int " + intString); return null; } return ToggleOverride.fromSetting(settingValue, OVERRIDE_UNSET); } /** Override state of desktop mode developer option toggle. */ Loading @@ -156,7 +161,7 @@ public enum DesktopModeFlagsUtil { }; } static ToggleOverride fromSetting(int setting, ToggleOverride fallback) { static ToggleOverride fromSetting(int setting, @Nullable ToggleOverride fallback) { return switch (setting) { case 1 -> OVERRIDE_ON; case 0 -> OVERRIDE_OFF; Loading
services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +0 −2 Original line number Diff line number Diff line Loading @@ -68,7 +68,6 @@ import android.os.PowerManager; import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.StrictMode; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.DeviceConfig; Loading Loading @@ -205,7 +204,6 @@ public class SystemServicesTestRule implements TestRule { .mockStatic(Watchdog.class, mockStubOnly) .spyStatic(DesktopModeHelper.class) .spyStatic(DesktopModeBoundsCalculator.class) .spyStatic(SystemProperties.class) .strictness(Strictness.LENIENT) .startMocking(); Loading
services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java +51 −51 File changed.Preview size limit exceeded, changes collapsed. Show changes