diff options
4 files changed, 638 insertions, 6 deletions
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java index 1f341147deb1..e0c0c2c60123 100644 --- a/services/core/java/com/android/server/wm/DesktopModeHelper.java +++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java @@ -22,7 +22,7 @@ import android.os.SystemProperties; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; -import com.android.window.flags.Flags; +import com.android.server.wm.utils.DesktopModeFlagsUtil; /** * Constants for desktop mode feature @@ -35,8 +35,8 @@ public final class DesktopModeHelper { "persist.wm.debug.desktop_mode_enforce_device_restrictions", true); /** Whether desktop mode is enabled. */ - static boolean isDesktopModeEnabled() { - return Flags.enableDesktopWindowingMode(); + static boolean isDesktopModeEnabled(@NonNull Context context) { + return DesktopModeFlagsUtil.DESKTOP_WINDOWING_MODE.isEnabled(context); } /** @@ -60,7 +60,7 @@ public final class DesktopModeHelper { * Return {@code true} if desktop mode can be entered on the current device. */ static boolean canEnterDesktopMode(@NonNull Context context) { - return isDesktopModeEnabled() + return isDesktopModeEnabled(context) && (!shouldEnforceDeviceRestrictions() || isDesktopModeSupported(context)); } } diff --git a/services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java b/services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java new file mode 100644 index 000000000000..4211764085b1 --- /dev/null +++ b/services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2024 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.utils; + +import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET; + +import android.annotation.Nullable; +import android.content.Context; +import android.provider.Settings; +import android.util.Log; + +import com.android.window.flags.Flags; + +import java.util.function.Supplier; + +/** + * Util to check desktop mode flags state. + * + * This utility is used to allow developer option toggles to override flags related to desktop + * windowing. + * + * Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag + * value and the developer option override state (if applicable). + * + * 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 { + // All desktop mode related flags to be overridden by developer option toggle will be added here + DESKTOP_WINDOWING_MODE( + Flags::enableDesktopWindowingMode, /* shouldOverrideByDevOption= */ true), + WALLPAPER_ACTIVITY( + Flags::enableDesktopWindowingWallpaperActivity, /* shouldOverrideByDevOption= */ true); + + private static final String TAG = "DesktopModeFlagsUtil"; + private static final String SYSTEM_PROPERTY_OVERRIDE_KEY = + "sys.wmshell.desktopmode.dev_toggle_override"; + + // Function called to obtain aconfig flag value. + private final Supplier<Boolean> mFlagFunction; + // Whether the flag state should be affected by developer option. + private final boolean mShouldOverrideByDevOption; + + // 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 static ToggleOverride sCachedToggleOverride; + + DesktopModeFlagsUtil(Supplier<Boolean> flagFunction, boolean shouldOverrideByDevOption) { + this.mFlagFunction = flagFunction; + this.mShouldOverrideByDevOption = shouldOverrideByDevOption; + } + + /** + * 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. + */ + public boolean isEnabled(Context context) { + if (!Flags.showDesktopWindowingDevOption() + || !mShouldOverrideByDevOption + || context.getContentResolver() == null) { + return mFlagFunction.get(); + } else { + boolean shouldToggleBeEnabledByDefault = Flags.enableDesktopWindowingMode(); + return switch (getToggleOverride(context)) { + case OVERRIDE_UNSET -> mFlagFunction.get(); + // When toggle override matches its default state, don't override flags. This + // helps users reset their feature overrides. + case OVERRIDE_OFF -> !shouldToggleBeEnabledByDefault && mFlagFunction.get(); + case OVERRIDE_ON -> shouldToggleBeEnabledByDefault ? mFlagFunction.get() : true; + }; + } + } + + private ToggleOverride getToggleOverride(Context context) { + // If cached, return it + if (sCachedToggleOverride != null) { + return sCachedToggleOverride; + } + + // Otherwise, fetch and cache it + ToggleOverride override = getToggleOverrideFromSystem(context); + sCachedToggleOverride = override; + Log.d(TAG, "Toggle override initialized to: " + override); + return override; + } + + /** + * Returns {@link ToggleOverride} from a non-persistent system property if present. Otherwise + * initializes the system property by reading Settings.Global. + */ + private ToggleOverride getToggleOverrideFromSystem(Context context) { + // A non-persistent System Property is used to store override to ensure it remains + // constant till reboot. + String overrideProperty = System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null); + ToggleOverride overrideFromSystemProperties = convertToToggleOverride(overrideProperty); + + // If valid system property, return it + if (overrideFromSystemProperties != null) { + return overrideFromSystemProperties; + } + + // 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 { + int intValue = Integer.parseInt(intString); + return ToggleOverride.fromSetting(intValue, null); + } catch (NumberFormatException e) { + Log.w(TAG, "Unknown toggleOverride int " + intString); + return null; + } + } + + /** Override state of desktop mode developer option toggle. */ + enum ToggleOverride { + OVERRIDE_UNSET, + OVERRIDE_OFF, + OVERRIDE_ON; + + int getSetting() { + return switch (this) { + case OVERRIDE_ON -> 1; + case OVERRIDE_OFF -> 0; + case OVERRIDE_UNSET -> -1; + }; + } + + static ToggleOverride fromSetting(int setting, @Nullable ToggleOverride fallback) { + return switch (setting) { + case 1 -> OVERRIDE_ON; + case 0 -> OVERRIDE_OFF; + case -1 -> OVERRIDE_UNSET; + default -> fallback; + }; + } + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 41f1ac72c56d..ea2abf7ddcb8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -141,8 +141,8 @@ import java.util.HashMap; import java.util.List; /** Common base class for window manager unit test classes. */ -class WindowTestsBase extends SystemServiceTestsBase { - final Context mContext = getInstrumentation().getTargetContext(); +public class WindowTestsBase extends SystemServiceTestsBase { + protected final Context mContext = getInstrumentation().getTargetContext(); // Default package name static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo"; diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java new file mode 100644 index 000000000000..e5f2f89ccead --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java @@ -0,0 +1,459 @@ +/* + * Copyright (C) 2024 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.utils; + +import static com.android.server.wm.utils.DesktopModeFlagsUtil.DESKTOP_WINDOWING_MODE; +import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_OFF; +import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_ON; +import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE; +import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY; +import static com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.ContentResolver; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; +import android.provider.Settings; + +import androidx.test.filters.SmallTest; + +import com.android.server.wm.WindowTestRunner; +import com.android.server.wm.WindowTestsBase; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Field; + +/** + * Test class for [DesktopModeFlagsUtil] + * + * Build/Install/Run: + * atest WmTests:DesktopModeFlagsUtilTest + */ +@SmallTest +@Presubmit +@RunWith(WindowTestRunner.class) +public class DesktopModeFlagsUtilTest extends WindowTestsBase { + + @Rule + public SetFlagsRule setFlagsRule = new SetFlagsRule(); + + @Before + public void setUp() throws Exception { + resetCache(); + } + + private static final String SYSTEM_PROPERTY_OVERRIDE_KEY = + "sys.wmshell.desktopmode.dev_toggle_override"; + + @Test + @DisableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_devOptionFlagDisabled_overrideOff_featureFlagOn_returnsTrue() { + setOverride(OVERRIDE_OFF.getSetting()); + // In absence of dev options, follow flag + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + } + + + @Test + @DisableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_devOptionFlagDisabled_overrideOn_featureFlagOff_returnsFalse() { + setOverride(OVERRIDE_ON.getSetting()); + + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_overrideUnset_featureFlagOn_returnsTrue() { + setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting()); + + // For overridableFlag, for unset overrides, follow flag + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_overrideUnset_featureFlagOff_returnsFalse() { + setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting()); + + // For overridableFlag, for unset overrides, follow flag + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_noOverride_featureFlagOn_returnsTrue() { + setOverride(null); + + // For overridableFlag, in absence of overrides, follow flag + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_noOverride_featureFlagOff_returnsFalse() { + setOverride(null); + + // For overridableFlag, in absence of overrides, follow flag + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_unrecognizableOverride_featureFlagOn_returnsTrue() { + setOverride(-2); + + // For overridableFlag, for unrecognized overrides, follow flag + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_unrecognizableOverride_featureFlagOff_returnsFalse() { + setOverride(-2); + + // For overridableFlag, for unrecognizable overrides, follow flag + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_overrideOff_featureFlagOn_returnsFalse() { + setOverride(OVERRIDE_OFF.getSetting()); + + // For overridableFlag, follow override if they exist + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_overrideOn_featureFlagOff_returnsTrue() { + setOverride(OVERRIDE_ON.getSetting()); + + // For overridableFlag, follow override if they exist + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() { + setOverride(OVERRIDE_OFF.getSetting()); + + // For overridableFlag, follow override if they exist + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + + setOverride(OVERRIDE_ON.getSetting()); + + // Keep overrides constant through the process + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() { + setOverride(OVERRIDE_ON.getSetting()); + + // For overridableFlag, follow override if they exist + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + + setOverride(OVERRIDE_OFF.getSetting()); + + // Keep overrides constant through the process + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_noProperty_overrideOn_featureFlagOff_returnsTrueAndPropertyOn() { + System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY); + setOverride(OVERRIDE_ON.getSetting()); + + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + // Store System Property if not present + assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) + .isEqualTo(String.valueOf(OVERRIDE_ON.getSetting())); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_noProperty_overrideUnset_featureFlagOn_returnsTrueAndPropertyUnset() { + System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY); + setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting()); + + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + // Store System Property if not present + assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) + .isEqualTo(String.valueOf( + DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting())); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_noProperty_overrideUnset_featureFlagOff_returnsFalseAndPropertyUnset() { + System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY); + setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting()); + + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + // Store System Property if not present + assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) + .isEqualTo(String.valueOf( + DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting())); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_propertyNotInt_overrideOff_featureFlagOn_returnsFalseAndPropertyOff() { + System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "abc"); + setOverride(OVERRIDE_OFF.getSetting()); + + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + // Store System Property if currently invalid + assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) + .isEqualTo(String.valueOf(OVERRIDE_OFF.getSetting())); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_propertyInvalid_overrideOff_featureFlagOn_returnsFalseAndPropertyOff() { + System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "-2"); + setOverride(OVERRIDE_OFF.getSetting()); + + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + // Store System Property if currently invalid + assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) + .isEqualTo(String.valueOf(OVERRIDE_OFF.getSetting())); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_propertyOff_overrideOn_featureFlagOn_returnsFalseAndnoPropertyUpdate() { + System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, String.valueOf( + OVERRIDE_OFF.getSetting())); + setOverride(OVERRIDE_ON.getSetting()); + + // Have a consistent override until reboot + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse(); + assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) + .isEqualTo(String.valueOf(OVERRIDE_OFF.getSetting())); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_propertyOn_overrideOff_featureFlagOff_returnsTrueAndnoPropertyUpdate() { + System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, String.valueOf(OVERRIDE_ON.getSetting())); + setOverride(OVERRIDE_OFF.getSetting()); + + // Have a consistent override until reboot + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) + .isEqualTo(String.valueOf(OVERRIDE_ON.getSetting())); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isEnabled_propertyUnset_overrideOff_featureFlagOn_returnsTrueAndnoPropertyUpdate() { + System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, + String.valueOf(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting())); + setOverride(OVERRIDE_OFF.getSetting()); + + // Have a consistent override until reboot + assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue(); + assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)) + .isEqualTo(String.valueOf( + DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting())); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY}) + public void isEnabled_dwFlagOn_overrideUnset_featureFlagOn_returnsTrue() { + setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting()); + + // For unset overrides, follow flag + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) + public void isEnabled_dwFlagOn_overrideUnset_featureFlagOff_returnsFalse() { + setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting()); + // For unset overrides, follow flag + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags({ + FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, + FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY + }) + public void isEnabled_dwFlagOn_overrideOn_featureFlagOn_returnsTrue() { + setOverride(OVERRIDE_ON.getSetting()); + + // When toggle override matches its default state (dw flag), don't override flags + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) + public void isEnabled_dwFlagOn_overrideOn_featureFlagOff_returnsFalse() { + setOverride(OVERRIDE_ON.getSetting()); + + // When toggle override matches its default state (dw flag), don't override flags + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags({ + FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, + FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY + }) + public void isEnabled_dwFlagOn_overrideOff_featureFlagOn_returnsFalse() { + setOverride(OVERRIDE_OFF.getSetting()); + + // Follow override if they exist, and is not equal to default toggle state (dw flag) + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) + public void isEnabled_dwFlagOn_overrideOff_featureFlagOff_returnsFalse() { + setOverride(OVERRIDE_OFF.getSetting()); + + // Follow override if they exist, and is not equal to default toggle state (dw flag) + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags({ + FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, + FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY + }) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_dwFlagOff_overrideUnset_featureFlagOn_returnsTrue() { + setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting()); + + // For unset overrides, follow flag + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags({ + FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY + }) + public void isEnabled_dwFlagOff_overrideUnset_featureFlagOff_returnsFalse() { + setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting()); + + // For unset overrides, follow flag + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse(); + } + + @Test + @EnableFlags({ + FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, + FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY + }) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_dwFlagOff_overrideOn_featureFlagOn_returnsTrue() { + setOverride(OVERRIDE_ON.getSetting()); + + // Follow override if they exist, and is not equal to default toggle state (dw flag) + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags({ + FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY + }) + public void isEnabled_dwFlagOff_overrideOn_featureFlagOff_returnTrue() { + setOverride(OVERRIDE_ON.getSetting()); + + // Follow override if they exist, and is not equal to default toggle state (dw flag) + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags({ + FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, + FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY + }) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isEnabled_dwFlagOff_overrideOff_featureFlagOn_returnsTrue() { + setOverride(OVERRIDE_OFF.getSetting()); + + // When toggle override matches its default state (dw flag), don't override flags + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue(); + } + + @Test + @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + @DisableFlags({ + FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY + }) + public void isEnabled_dwFlagOff_overrideOff_featureFlagOff_returnsFalse() { + setOverride(OVERRIDE_OFF.getSetting()); + + // When toggle override matches its default state (dw flag), don't override flags + assertThat(DesktopModeFlagsUtil.WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse(); + } + + private void setOverride(Integer setting) { + ContentResolver contentResolver = mContext.getContentResolver(); + String key = Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; + + if (setting == null) { + Settings.Global.putString(contentResolver, key, null); + } else { + Settings.Global.putInt(contentResolver, key, setting); + } + } + + private void resetCache() throws Exception { + Field cachedToggleOverride = DesktopModeFlagsUtil.class.getDeclaredField( + "sCachedToggleOverride"); + cachedToggleOverride.setAccessible(true); + cachedToggleOverride.set(null, null); + + // Clear override cache stored in System property + System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY); + } +} |