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

Commit d4204437 authored by Hyunyoung Song's avatar Hyunyoung Song
Browse files

Make TogglableFlag backed by DeviceConfig for e2e testing

Bug: 138964490

TL;DR;; need this to be part of QQ1 or QD1 to verify if DeviceConfig
can be supported for launcher toggleableFlags.

Not handled in this CL:
- When flag is locally modified, that will override the flag value
How that scenario is handled should be discussed separately and is not
within scope of this CL.

Change-Id: I2e6694a40bee9202ed0b0d559e3b5607634071bf
parent 1b0445df
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.uioverrides;

import android.provider.DeviceConfig;
import com.android.launcher3.config.BaseFlags.BaseTogglableFlag;

public class TogglableFlag extends BaseTogglableFlag {

    public TogglableFlag(String key, boolean defaultValue, String description) {
        super(key, defaultValue, description);
    }

    @Override
    public boolean getInitialValue(boolean value) {
        return DeviceConfig.getBoolean("launcher", getKey(), value);
    }
}
+5 −3
Original line number Diff line number Diff line
package com.android.launcher3.config;


import com.android.launcher3.config.BaseFlags.BaseTogglableFlag;
import com.android.launcher3.uioverrides.TogglableFlag;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
@@ -70,7 +72,7 @@ public final class FlagOverrideRule implements TestRule {
        };
    }

    private void override(BaseFlags.TogglableFlag flag, boolean newValue) {
    private void override(BaseTogglableFlag flag, boolean newValue) {
        if (!ruleInProgress) {
            throw new IllegalStateException(
                    "Rule isn't in progress. Did you remember to mark it with @Rule?");
@@ -93,7 +95,7 @@ public final class FlagOverrideRule implements TestRule {

    private void applyAnnotation(FlagOverride flagOverride) {
        boolean found = false;
        for (BaseFlags.TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
        for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
            if (flag.getKey().equals(flagOverride.key())) {
                override(flag, flagOverride.value());
                found = true;
@@ -109,7 +111,7 @@ public final class FlagOverrideRule implements TestRule {
     * Resets all flags to their default values.
     */
    private void clearOverrides() {
        for (BaseFlags.TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
        for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) {
            flag.setForTests(flag.getDefaultValue());
        }
    }
+13 −61
Original line number Diff line number Diff line
@@ -18,20 +18,16 @@ package com.android.launcher3.config;

import static androidx.core.util.Preconditions.checkNotNull;

import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;

import androidx.annotation.GuardedBy;
import androidx.annotation.Keep;
import androidx.annotation.VisibleForTesting;

import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;

import com.android.launcher3.uioverrides.TogglableFlag;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
@@ -41,11 +37,9 @@ import java.util.TreeMap;
 * Defines a set of flags used to control various launcher behaviors.
 *
 * <p>All the flags should be defined here with appropriate default values.
 *
 * <p>This class is kept package-private to prevent direct access.
 */
@Keep
abstract class BaseFlags {
public abstract class BaseFlags {

    private static final Object sLock = new Object();
    @GuardedBy("sLock")
@@ -116,7 +110,7 @@ abstract class BaseFlags {
        // Avoid the disk read for user builds
        if (Utilities.IS_DEBUG_DEVICE) {
            synchronized (sLock) {
                for (TogglableFlag flag : sFlags) {
                for (BaseTogglableFlag flag : sFlags) {
                    flag.initialize(context);
                }
            }
@@ -132,27 +126,27 @@ abstract class BaseFlags {
        SortedMap<String, TogglableFlag> flagsByKey = new TreeMap<>();
        synchronized (sLock) {
            for (TogglableFlag flag : sFlags) {
                flagsByKey.put(flag.key, flag);
                flagsByKey.put(((BaseTogglableFlag) flag).getKey(), flag);
            }
        }
        return new ArrayList<>(flagsByKey.values());
    }

    public static class TogglableFlag {
    public static abstract class BaseTogglableFlag {
        private final String key;
        private final boolean defaultValue;
        private final String description;
        private boolean currentValue;

        TogglableFlag(
        public BaseTogglableFlag(
                String key,
                boolean defaultValue,
                String description) {
            this.key = checkNotNull(key);
            this.currentValue = this.defaultValue = defaultValue;
            this.currentValue = this.defaultValue = getInitialValue(defaultValue);
            this.description = checkNotNull(description);
            synchronized (sLock) {
                sFlags.add(this);
                sFlags.add((TogglableFlag)this);
            }
        }

@@ -162,14 +156,16 @@ abstract class BaseFlags {
            currentValue = value;
        }

        @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
        public String getKey() {
            return key;
        }

        void initialize(Context context) {
            currentValue = getFromStorage(context, defaultValue);
        }

        protected abstract boolean getInitialValue(boolean value);

        public void updateStorage(Context context, boolean value) {
            SharedPreferences.Editor editor = context.getSharedPreferences(FLAGS_PREF_NAME,
                    Context.MODE_PRIVATE).edit();
@@ -213,7 +209,7 @@ abstract class BaseFlags {
                return true;
            }
            if (o instanceof TogglableFlag) {
                TogglableFlag that = (TogglableFlag) o;
                BaseTogglableFlag that = (BaseTogglableFlag) o;
                return (this.key.equals(that.getKey()))
                        && (this.defaultValue == that.getDefaultValue())
                        && (this.description.equals(that.getDescription()));
@@ -233,48 +229,4 @@ abstract class BaseFlags {
            return h$;
        }
    }

    /**
     * Stores the FeatureFlag's value in Settings.Global instead of our SharedPrefs.
     * This is useful if we want to be able to control this flag from another process.
     */
    public static final class ToggleableGlobalSettingsFlag extends TogglableFlag {
        private ContentResolver contentResolver;

        ToggleableGlobalSettingsFlag(String key, boolean defaultValue, String description) {
            super(key, defaultValue, description);
        }

        @Override
        public void initialize(Context context) {
            contentResolver = context.getContentResolver();
            contentResolver.registerContentObserver(Settings.Global.getUriFor(getKey()), true,
                    new ContentObserver(new Handler(Looper.getMainLooper())) {
                        @Override
                        public void onChange(boolean selfChange) {
                            superInitialize(context);
                    }});
            superInitialize(context);
        }

        private void superInitialize(Context context) {
            super.initialize(context);
        }

        @Override
        public void updateStorage(Context context, boolean value) {
            if (contentResolver == null) {
                return;
            }
            Settings.Global.putInt(contentResolver, getKey(), value ? 1 : 0);
        }

        @Override
        boolean getFromStorage(Context context, boolean defaultValue) {
            if (contentResolver == null) {
                return defaultValue;
            }
            return Settings.Global.getInt(contentResolver, getKey(), defaultValue ? 1 : 0) == 1;
        }
    }
}
+6 −5
Original line number Diff line number Diff line
@@ -26,12 +26,13 @@ import android.view.MenuItem;
import android.widget.Toast;

import com.android.launcher3.R;
import com.android.launcher3.config.BaseFlags.TogglableFlag;

import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceFragment;
import androidx.preference.PreferenceGroup;
import androidx.preference.SwitchPreference;
import com.android.launcher3.config.BaseFlags.BaseTogglableFlag;
import com.android.launcher3.uioverrides.TogglableFlag;

/**
 * Dev-build only UI allowing developers to toggle flag settings. See {@link FeatureFlags}.
@@ -62,7 +63,7 @@ public final class FlagTogglerPrefUi {

        @Override
        public boolean getBoolean(String key, boolean defaultValue) {
            for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
            for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) {
                if (flag.getKey().equals(key)) {
                    return flag.getFromStorage(mContext, defaultValue);
                }
@@ -83,7 +84,7 @@ public final class FlagTogglerPrefUi {
        // flag with a different value than the default. That way, when we flip flags in
        // future, engineers will pick up the new value immediately. To accomplish this, we use a
        // custom preference data store.
        for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
        for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) {
            SwitchPreference switchPreference = new SwitchPreference(mContext);
            switchPreference.setKey(flag.getKey());
            switchPreference.setDefaultValue(flag.getDefaultValue());
@@ -99,7 +100,7 @@ public final class FlagTogglerPrefUi {
    /**
     * Updates the summary to show the description and whether the flag overrides the default value.
     */
    private void updateSummary(SwitchPreference switchPreference, TogglableFlag flag) {
    private void updateSummary(SwitchPreference switchPreference, BaseTogglableFlag flag) {
        String onWarning = flag.getDefaultValue() ? "" : "<b>OVERRIDDEN</b><br>";
        String offWarning = flag.getDefaultValue() ? "<b>OVERRIDDEN</b><br>" : "";
        switchPreference.setSummaryOn(Html.fromHtml(onWarning + flag.getDescription()));
@@ -134,7 +135,7 @@ public final class FlagTogglerPrefUi {
        }
    }

    private boolean getFlagStateFromSharedPrefs(TogglableFlag flag) {
    private boolean getFlagStateFromSharedPrefs(BaseTogglableFlag flag) {
        return mDataStore.getBoolean(flag.getKey(), flag.getDefaultValue());
    }

+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.uioverrides;

import com.android.launcher3.config.BaseFlags.BaseTogglableFlag;

public class TogglableFlag extends BaseTogglableFlag {

    public TogglableFlag(String key, boolean defaultValue, String description) {
        super(key, defaultValue, description);
    }

    @Override
    public boolean getInitialValue(boolean value) {
        return value;
    }
}