Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt +65 −29 Original line number Diff line number Diff line Loading @@ -37,15 +37,12 @@ enum class DesktopModeFlags( // All desktop mode related flags will be added here DESKTOP_WINDOWING_MODE(DesktopModeStatus::isDesktopModeFlagEnabled, true); private val TAG = "DesktopModeFlags" // 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. // 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. private var cachedToggleOverride: ToggleOverride? = null /** * Determines state of flag based on the actual flag and desktop mode developer option * overrides. * Determines state of flag based on the actual flag and desktop mode developer option overrides. * * Note, this method makes sure that a constant developer toggle overrides is read until reboot. */ Loading @@ -63,34 +60,44 @@ enum class DesktopModeFlags( } private fun getToggleOverride(context: Context): ToggleOverride { val override = cachedToggleOverride ?: run { val override = cachedToggleOverride ?: run { val override = getToggleOverrideFromSystem(context) // Cache toggle override the first time we encounter context. Override does not change // with context, as context is just used to fetch a system property. // with context, as context is just used to fetch System Property and Settings.Global cachedToggleOverride = override Log.d(TAG, "Toggle override initialized to: $override") override } return override } // TODO(b/348193756): Cache a persistent value for Settings.Global until reboot. Current // cache will change with process restart. val toggleOverride = 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? = System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null).convertToToggleOverride() return overrideFromSystemProperties ?: run { // Read Setting Global if System Property is not present (just after reboot) // or not valid (user manually changed the value) val overrideFromSettingsGlobal = Settings.Global.getInt( context.contentResolver, Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, ToggleOverride.OVERRIDE_UNSET.setting) .convertToToggleOverrideWithFallback(ToggleOverride.OVERRIDE_UNSET) // Initialize System Property System.setProperty( SYSTEM_PROPERTY_OVERRIDE_KEY, overrideFromSettingsGlobal.setting.toString()) val newOverride = settingToToggleOverrideMap[toggleOverride] ?: run { Log.w(TAG, "Unknown toggleOverride $toggleOverride") ToggleOverride.OVERRIDE_UNSET } cachedToggleOverride = newOverride Log.d(TAG, "Toggle override initialized to: $newOverride") newOverride overrideFromSettingsGlobal } return override } // TODO(b/348193756): Share ToggleOverride enum with Settings // 'DesktopModePreferenceController' // TODO(b/348193756): Share ToggleOverride enum with Settings 'DesktopModePreferenceController' /** * Override state of desktop mode developer option toggle. * Loading @@ -107,4 +114,33 @@ enum class DesktopModeFlags( } private val settingToToggleOverrideMap = ToggleOverride.entries.associateBy { it.setting } private fun String?.convertToToggleOverride(): ToggleOverride? { val intValue = this?.toIntOrNull() ?: return null return settingToToggleOverrideMap[intValue] ?: run { Log.w(TAG, "Unknown toggleOverride int $intValue") null } } private fun Int.convertToToggleOverrideWithFallback( fallbackOverride: ToggleOverride ): ToggleOverride { return settingToToggleOverrideMap[this] ?: run { Log.w(TAG, "Unknown toggleOverride int $this") fallbackOverride } } private companion object { const val TAG = "DesktopModeFlags" /** * Key for non-persistent System Property which is used to store desktop windowing developer * option overrides. */ const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override" } } libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt +123 −14 Original line number Diff line number Diff line Loading @@ -82,7 +82,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_unsetOverride_featureFlagOn_returnsTrue() { fun isEnabled_overrideUnset_featureFlagOn_returnsTrue() { setOverride(OVERRIDE_UNSET.setting) // For overridableFlag, for unset overrides, follow flag Loading @@ -92,7 +92,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_unsetOverride_featureFlagOff_returnsFalse() { fun isEnabled_overrideUnset_featureFlagOff_returnsFalse() { setOverride(OVERRIDE_UNSET.setting) // For overridableFlag, for unset overrides, follow flag Loading @@ -101,7 +101,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_noOverride_featureFlagOn_returnsTrue() { fun isEnabled_noOverride_featureFlagOn_returnsTrue() { setOverride(null) // For overridableFlag, in absence of overrides, follow flag Loading @@ -111,7 +111,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_noOverride_featureFlagOff_returnsFalse() { fun isEnabled_noOverride_featureFlagOff_returnsFalse() { setOverride(null) // For overridableFlag, in absence of overrides, follow flag Loading @@ -120,7 +120,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_unrecognizableOverride_featureFlagOn_returnsTrue() { fun isEnabled_unrecognizableOverride_featureFlagOn_returnsTrue() { setOverride(-2) // For overridableFlag, for recognizable overrides, follow flag Loading @@ -130,7 +130,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_unrecognizableOverride_featureFlagOff_returnsFalse() { fun isEnabled_unrecognizableOverride_featureFlagOff_returnsFalse() { setOverride(-2) // For overridableFlag, for recognizable overrides, follow flag Loading @@ -139,7 +139,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_overrideOff_featureFlagOn_returnsFalse() { fun isEnabled_overrideOff_featureFlagOn_returnsFalse() { setOverride(OVERRIDE_OFF.setting) // For overridableFlag, follow override if they exist Loading @@ -149,7 +149,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_overrideOn_featureFlagOff_returnsTrue() { fun isEnabled_overrideOn_featureFlagOff_returnsTrue() { setOverride(OVERRIDE_ON.setting) // For overridableFlag, follow override if they exist Loading @@ -158,7 +158,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() { fun isEnabled_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() { setOverride(OVERRIDE_OFF.setting) // For overridableFlag, follow override if they exist Loading @@ -173,7 +173,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() { fun isEnabled_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() { setOverride(OVERRIDE_ON.setting) // For overridableFlag, follow override if they exist Loading @@ -187,7 +187,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_noOverride_featureFlagOnThenOff_returnsTrueAndFalse() { fun isEnabled_noOverride_featureFlagOnThenOff_returnsTrueAndFalse() { setOverride(null) // For overridableFlag, in absence of overrides, follow flag assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() Loading @@ -206,6 +206,108 @@ class DesktopModeFlagsTest : ShellTestCase() { } } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_noSystemProperty_overrideOn_featureFlagOff_returnsTrueAndStoresPropertyOn() { System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_ON.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() // Store System Property if not present 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() { System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_UNSET.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() // Store System Property if not present 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() { System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_UNSET.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() // Store System Property if not present 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() { System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "-2") 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) fun isEnabled_systemPropertyOff_overrideOn_featureFlagOn_returnsFalseAndDoesNotUpdateProperty() { 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() 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() { 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() 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() { 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() assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_UNSET.setting.toString()) } private fun setOverride(setting: Int?) { val contentResolver = mContext.contentResolver val key = Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES Loading @@ -217,9 +319,16 @@ class DesktopModeFlagsTest : ShellTestCase() { } private fun resetCache() { val cacheToggleOverride = val cachedToggleOverride = DESKTOP_WINDOWING_MODE::class.java.getDeclaredField("cachedToggleOverride") cacheToggleOverride.isAccessible = true cacheToggleOverride.set(DESKTOP_WINDOWING_MODE, null) cachedToggleOverride.isAccessible = true cachedToggleOverride.set(DESKTOP_WINDOWING_MODE, null) // 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" } } Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt +65 −29 Original line number Diff line number Diff line Loading @@ -37,15 +37,12 @@ enum class DesktopModeFlags( // All desktop mode related flags will be added here DESKTOP_WINDOWING_MODE(DesktopModeStatus::isDesktopModeFlagEnabled, true); private val TAG = "DesktopModeFlags" // 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. // 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. private var cachedToggleOverride: ToggleOverride? = null /** * Determines state of flag based on the actual flag and desktop mode developer option * overrides. * Determines state of flag based on the actual flag and desktop mode developer option overrides. * * Note, this method makes sure that a constant developer toggle overrides is read until reboot. */ Loading @@ -63,34 +60,44 @@ enum class DesktopModeFlags( } private fun getToggleOverride(context: Context): ToggleOverride { val override = cachedToggleOverride ?: run { val override = cachedToggleOverride ?: run { val override = getToggleOverrideFromSystem(context) // Cache toggle override the first time we encounter context. Override does not change // with context, as context is just used to fetch a system property. // with context, as context is just used to fetch System Property and Settings.Global cachedToggleOverride = override Log.d(TAG, "Toggle override initialized to: $override") override } return override } // TODO(b/348193756): Cache a persistent value for Settings.Global until reboot. Current // cache will change with process restart. val toggleOverride = 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? = System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null).convertToToggleOverride() return overrideFromSystemProperties ?: run { // Read Setting Global if System Property is not present (just after reboot) // or not valid (user manually changed the value) val overrideFromSettingsGlobal = Settings.Global.getInt( context.contentResolver, Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, ToggleOverride.OVERRIDE_UNSET.setting) .convertToToggleOverrideWithFallback(ToggleOverride.OVERRIDE_UNSET) // Initialize System Property System.setProperty( SYSTEM_PROPERTY_OVERRIDE_KEY, overrideFromSettingsGlobal.setting.toString()) val newOverride = settingToToggleOverrideMap[toggleOverride] ?: run { Log.w(TAG, "Unknown toggleOverride $toggleOverride") ToggleOverride.OVERRIDE_UNSET } cachedToggleOverride = newOverride Log.d(TAG, "Toggle override initialized to: $newOverride") newOverride overrideFromSettingsGlobal } return override } // TODO(b/348193756): Share ToggleOverride enum with Settings // 'DesktopModePreferenceController' // TODO(b/348193756): Share ToggleOverride enum with Settings 'DesktopModePreferenceController' /** * Override state of desktop mode developer option toggle. * Loading @@ -107,4 +114,33 @@ enum class DesktopModeFlags( } private val settingToToggleOverrideMap = ToggleOverride.entries.associateBy { it.setting } private fun String?.convertToToggleOverride(): ToggleOverride? { val intValue = this?.toIntOrNull() ?: return null return settingToToggleOverrideMap[intValue] ?: run { Log.w(TAG, "Unknown toggleOverride int $intValue") null } } private fun Int.convertToToggleOverrideWithFallback( fallbackOverride: ToggleOverride ): ToggleOverride { return settingToToggleOverrideMap[this] ?: run { Log.w(TAG, "Unknown toggleOverride int $this") fallbackOverride } } private companion object { const val TAG = "DesktopModeFlags" /** * Key for non-persistent System Property which is used to store desktop windowing developer * option overrides. */ const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override" } }
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt +123 −14 Original line number Diff line number Diff line Loading @@ -82,7 +82,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_unsetOverride_featureFlagOn_returnsTrue() { fun isEnabled_overrideUnset_featureFlagOn_returnsTrue() { setOverride(OVERRIDE_UNSET.setting) // For overridableFlag, for unset overrides, follow flag Loading @@ -92,7 +92,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_unsetOverride_featureFlagOff_returnsFalse() { fun isEnabled_overrideUnset_featureFlagOff_returnsFalse() { setOverride(OVERRIDE_UNSET.setting) // For overridableFlag, for unset overrides, follow flag Loading @@ -101,7 +101,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_noOverride_featureFlagOn_returnsTrue() { fun isEnabled_noOverride_featureFlagOn_returnsTrue() { setOverride(null) // For overridableFlag, in absence of overrides, follow flag Loading @@ -111,7 +111,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_noOverride_featureFlagOff_returnsFalse() { fun isEnabled_noOverride_featureFlagOff_returnsFalse() { setOverride(null) // For overridableFlag, in absence of overrides, follow flag Loading @@ -120,7 +120,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_unrecognizableOverride_featureFlagOn_returnsTrue() { fun isEnabled_unrecognizableOverride_featureFlagOn_returnsTrue() { setOverride(-2) // For overridableFlag, for recognizable overrides, follow flag Loading @@ -130,7 +130,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_unrecognizableOverride_featureFlagOff_returnsFalse() { fun isEnabled_unrecognizableOverride_featureFlagOff_returnsFalse() { setOverride(-2) // For overridableFlag, for recognizable overrides, follow flag Loading @@ -139,7 +139,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_overrideOff_featureFlagOn_returnsFalse() { fun isEnabled_overrideOff_featureFlagOn_returnsFalse() { setOverride(OVERRIDE_OFF.setting) // For overridableFlag, follow override if they exist Loading @@ -149,7 +149,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_overrideOn_featureFlagOff_returnsTrue() { fun isEnabled_overrideOn_featureFlagOff_returnsTrue() { setOverride(OVERRIDE_ON.setting) // For overridableFlag, follow override if they exist Loading @@ -158,7 +158,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() { fun isEnabled_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() { setOverride(OVERRIDE_OFF.setting) // For overridableFlag, follow override if they exist Loading @@ -173,7 +173,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() { fun isEnabled_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() { setOverride(OVERRIDE_ON.setting) // For overridableFlag, follow override if they exist Loading @@ -187,7 +187,7 @@ class DesktopModeFlagsTest : ShellTestCase() { @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_flagOverridable_noOverride_featureFlagOnThenOff_returnsTrueAndFalse() { fun isEnabled_noOverride_featureFlagOnThenOff_returnsTrueAndFalse() { setOverride(null) // For overridableFlag, in absence of overrides, follow flag assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() Loading @@ -206,6 +206,108 @@ class DesktopModeFlagsTest : ShellTestCase() { } } @Test @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) fun isEnabled_noSystemProperty_overrideOn_featureFlagOff_returnsTrueAndStoresPropertyOn() { System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_ON.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() // Store System Property if not present 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() { System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_UNSET.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue() // Store System Property if not present 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() { System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY) setOverride(OVERRIDE_UNSET.setting) assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse() // Store System Property if not present 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() { System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "-2") 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) fun isEnabled_systemPropertyOff_overrideOn_featureFlagOn_returnsFalseAndDoesNotUpdateProperty() { 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() 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() { 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() 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() { 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() assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) .isEqualTo(OVERRIDE_UNSET.setting.toString()) } private fun setOverride(setting: Int?) { val contentResolver = mContext.contentResolver val key = Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES Loading @@ -217,9 +319,16 @@ class DesktopModeFlagsTest : ShellTestCase() { } private fun resetCache() { val cacheToggleOverride = val cachedToggleOverride = DESKTOP_WINDOWING_MODE::class.java.getDeclaredField("cachedToggleOverride") cacheToggleOverride.isAccessible = true cacheToggleOverride.set(DESKTOP_WINDOWING_MODE, null) cachedToggleOverride.isAccessible = true cachedToggleOverride.set(DESKTOP_WINDOWING_MODE, null) // 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" } }