Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44579d60 authored by Pierre Barbier de Reuille's avatar Pierre Barbier de Reuille
Browse files

Allow overriding dev option with adb

Use a system property per flag to override whether or not they are in
the developer option. The system property is read when the flag is first
read, the value of the flag is then cached.

Fix: 408432634
Test: atest DesktopExperienceFlagsTest
Flag: com.android.window.flags.show_desktop_experience_dev_option
Change-Id: Idbac67e22e0845c5b2d6d5021f7b2a93890f91fd
parent 6227a2b8
Loading
Loading
Loading
Loading
+35 −10
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.window;

import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT;
import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -144,31 +145,45 @@ public enum DesktopExperienceFlags {
    public static class DesktopExperienceFlag {
        // Function called to obtain aconfig flag value.
        private final BooleanSupplier mFlagFunction;
        // Name of the flag, used for adb commands.
        private final String mFlagName;
        // Whether the flag state should be affected by developer option.
        private final boolean mShouldOverrideByDevOption;
        // Cached value for that flag: null if not read yet.
        private Boolean mCachedValue;

        public DesktopExperienceFlag(BooleanSupplier flagFunction,
                boolean shouldOverrideByDevOption,
                @Nullable String flagName) {
            this.mFlagFunction = flagFunction;
            this.mShouldOverrideByDevOption = checkIfFlagShouldBeOverridden(flagName,
                    shouldOverrideByDevOption);
            this.mFlagName = flagName;
            this.mShouldOverrideByDevOption = shouldOverrideByDevOption;
        }

        /**
         * Determines state of flag based on the actual flag and desktop experience developer option
         * overrides.
         *
         * The assumption is that the flag's value doesn't change at runtime, or if it changes the
         * user will reboot very soon so being inconsistent across threads is ok.
         */
        public boolean isTrue() {
            return isFlagTrue(mFlagFunction, mShouldOverrideByDevOption);
            if (mCachedValue == null) {
                mCachedValue = isFlagTrue(mFlagFunction, mShouldOverrideByDevOption, mFlagName);
            }
            return mCachedValue;
        }
    }

    private static final String TAG = "DesktopExperienceFlags";
    // Function called to obtain aconfig flag value.
    private final BooleanSupplier mFlagFunction;
    // Name of the flag, used for adb commands.
    private final String mFlagName;
    // Whether the flag state should be affected by developer option.
    private final boolean mShouldOverrideByDevOption;
    // Cached value for that flag: null if not read yet.
    private Boolean mCachedValue;

    // Local cache for toggle override, which is initialized once on its first access. It needs to
    // be refreshed only on reboots as overridden state is expected to take effect on reboots.
@@ -182,22 +197,28 @@ public enum DesktopExperienceFlags {
    DesktopExperienceFlags(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption,
            @NonNull String flagName) {
        this.mFlagFunction = flagFunction;
        this.mShouldOverrideByDevOption = checkIfFlagShouldBeOverridden(flagName,
                shouldOverrideByDevOption);
        this.mFlagName = flagName;
        this.mShouldOverrideByDevOption = shouldOverrideByDevOption;
    }

    /**
     * Determines state of flag based on the actual flag and desktop experience developer option
     * overrides.
     *
     * The assumption is that the flag's value doesn't change at runtime, or if it changes the
     * user will reboot very soon so being inconsistent across threads is ok.
     */
    public boolean isTrue() {
        return isFlagTrue(mFlagFunction, mShouldOverrideByDevOption);
        if (mCachedValue == null) {
            mCachedValue = isFlagTrue(mFlagFunction, mShouldOverrideByDevOption, mFlagName);
        }
        return mCachedValue;
    }

    private static boolean isFlagTrue(
            BooleanSupplier flagFunction, boolean shouldOverrideByDevOption) {
        if (shouldOverrideByDevOption
                && Flags.showDesktopExperienceDevOption()
            BooleanSupplier flagFunction, boolean shouldOverrideByDevOption, String flagName) {
        if (Flags.showDesktopExperienceDevOption()
                && checkIfFlagShouldBeOverridden(flagName, shouldOverrideByDevOption)
                && getToggleOverride()) {
            return true;
        }
@@ -206,7 +227,11 @@ public enum DesktopExperienceFlags {

    private static boolean checkIfFlagShouldBeOverridden(@Nullable String flagName,
            boolean defaultValue) {
        return defaultValue;
        if (flagName == null || flagName.isEmpty()) return defaultValue;
        int lastDot = flagName.lastIndexOf('.');
        String baseName = lastDot >= 0 ? flagName.substring(lastDot + 1) : flagName;
        return SystemProperties.getBoolean(SYSTEM_PROPERTY_OVERRIDE_PREFIX + baseName,
                defaultValue);
    }

    private static boolean getToggleOverride() {
+84 −0
Original line number Diff line number Diff line
@@ -142,6 +142,90 @@ public class DesktopExperienceFlagsTest {
        assertThat(mNotOverriddenLocalFlag.isTrue()).isFalse();
    }

    @Test
    public void isTrue_flagHasDotAndNotOverridden_withSysPropOverride_returnAsDevOptionEnabled()
            throws Exception {
        DesktopExperienceFlag flag = new DesktopExperienceFlag(() -> false, false,
                "test.flag.baseName");
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_NAME, OVERRIDE_ON_SETTING);
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_OVERRIDE_PREFIX + "baseName", "true");

        if (Flags.showDesktopExperienceDevOption()) {
            assertThat(flag.isTrue()).isTrue();
        } else {
            assertThat(flag.isTrue()).isFalse();
        }
    }

    @Test
    public void isTrue_flagHasNoDotAndNotOverridden_withSysPropOverride_returnAsDevOptionEnabled()
            throws Exception {
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_NAME, OVERRIDE_ON_SETTING);
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_OVERRIDE_PREFIX + "fullName", "true");
        DesktopExperienceFlag flag = new DesktopExperienceFlag(() -> false, false, "fullName");

        if (Flags.showDesktopExperienceDevOption()) {
            assertThat(flag.isTrue()).isTrue();
        } else {
            assertThat(flag.isTrue()).isFalse();
        }
    }

    @Test
    public void isTrue_flagHasNoNameAndNotOverridden_withSysPropOverride_returnAsDevOptionEnabled()
            throws Exception {
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_NAME, OVERRIDE_ON_SETTING);
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_OVERRIDE_PREFIX, "true");
        DesktopExperienceFlag flag = new DesktopExperienceFlag(() -> false, false, "");

        assertThat(flag.isTrue()).isFalse();
    }

    @Test
    public void isTrue_flagHasDot_devOptionEnabled_flagOverridden_withSysPropOverride_returnFalse()
            throws Exception {
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_NAME, OVERRIDE_ON_SETTING);
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_OVERRIDE_PREFIX + "baseName", "false");
        DesktopExperienceFlag flag = new DesktopExperienceFlag(() -> false, true,
                "test.flag.baseName");

        assertThat(flag.isTrue()).isFalse();
    }

    @Test
    public void isTrue_flagHasNoDot_devOptionEnabled_flagOverridden_withOverride_returnFalse()
            throws Exception {
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_NAME, OVERRIDE_ON_SETTING);
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_OVERRIDE_PREFIX + "fullName", "false");
        DesktopExperienceFlag flag = new DesktopExperienceFlag(() -> false, true, "fullName");

        assertThat(flag.isTrue()).isFalse();
    }

    @Test
    public void isTrue_flagHasNoName_devOptionEnabled_flagOverridden_withOverride()
            throws Exception {
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_NAME, OVERRIDE_ON_SETTING);
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_OVERRIDE_PREFIX, "false");
        DesktopExperienceFlag flag = new DesktopExperienceFlag(() -> false, true, "");

        if (Flags.showDesktopExperienceDevOption()) {
            assertThat(flag.isTrue()).isTrue();
        } else {
            assertThat(flag.isTrue()).isFalse();
        }
    }

    @Test
    public void isTrue_sysPropSetAfterFirstRead_doesntChangeValue() throws Exception {
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_NAME, OVERRIDE_ON_SETTING);
        DesktopExperienceFlag flag = new DesktopExperienceFlag(() -> false, false, "fullName");
        flag.isTrue();
        setSysProp(DesktopExperienceFlags.SYSTEM_PROPERTY_OVERRIDE_PREFIX + "fullName", "true");

        assertThat(flag.isTrue()).isFalse();
    }

    private void setSysProp(String name, String value) throws Exception {
        if (!mInitialSyspropValues.containsKey(name)) {
            String initialValue = mUiDevice.executeShellCommand("getprop " + name).trim();