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

Commit 96eba3ae authored by Hyunyoung Song's avatar Hyunyoung Song Committed by Android (Google) Code Review
Browse files

Merge "Make TogglableFlag backed by DeviceConfig for e2e testing" into ub-launcher3-qt-qpr1-dev

parents 68f5d6bf d4204437
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")
@@ -120,7 +114,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);
                }
            }
@@ -136,27 +130,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);
            }
        }

@@ -166,14 +160,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();
@@ -217,7 +213,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()));
@@ -237,48 +233,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;
    }
}