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

Commit 06037712 authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Add new Flag class. New FlagReaderPlugin.

This CL is a stepping stone towards a more complete flag system.

This cl allows for the definition of flags within systemui, each of
which have a unique id and a default value. Methods for retrieving
the value of a flag are defined.

By default, reading a flag always returns its default value.

A FlagReaderPlugin is also defined that, when loaded, allows for
returning alternate values for a given flag. The details of how an
alternate value are determined are left for the plugin to decide.

The plugin interface should be considered incomplete with this cl.
Methods for reading flags are defined, but hooks for knowing when
flags change (and hooks for knowing when a flag plugin has been
loaded), are not defined. Moreover, the flag plugin is not loaded
early in the process with this cl, so anyone who reads flags
before the plugin is may misss out on the values they care about.

More changes to come.

Bug: 194781951
Test: atest SystemUITests
Change-Id: I888d5eba82359a37878a3a4d4747990b79a77804
parent 8661d451
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.systemui.flags

interface Flag<T> {
    val id: Int
    val default: T
}

data class BooleanFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: Boolean = false
) : Flag<Boolean>

data class StringFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: String = ""
) : Flag<String>

data class IntFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: Int = 0
) : Flag<Int>

data class LongFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: Long = 0
) : Flag<Long>

data class FloatFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: Float = 0f
) : Flag<Float>

data class DoubleFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: Double = 0.0
) : Flag<Double>
 No newline at end of file
+23 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.systemui.flags;

/**
 * List of {@link Flag} objects for use in SystemUI.
 */
public class Flags {
}
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.systemui.plugins;

import com.android.systemui.plugins.annotations.ProvidesInterface;


/**
 * Plugin for loading flag values from an alternate source of truth.
 */
@ProvidesInterface(action = FlagReaderPlugin.ACTION, version = FlagReaderPlugin.VERSION)
public interface FlagReaderPlugin extends Plugin {
    int VERSION = 1;
    String ACTION = "com.android.systemui.flags.FLAG_READER_PLUGIN";

    /** Returns a boolean value for the given flag. */
    default boolean isEnabled(int id, boolean def) {
        return def;
    }

    /** Returns a string value for the given flag id. */
    default String getValue(int id, String def) {
        return def;
    }

    /** Returns a int value for the given flag. */
    default int getValue(int id, int def) {
        return def;
    }

    /** Returns a long value for the given flag. */
    default long getValue(int id, long def) {
        return def;
    }

    /** Returns a float value for the given flag. */
    default float getValue(int id, float def) {
        return def;
    }

    /** Returns a double value for the given flag. */
    default double getValue(int id, double def) {
        return def;
    }
}
+46 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.flags;

import android.content.Context;
import android.content.res.Resources;
import android.util.SparseArray;

@@ -25,6 +26,9 @@ import androidx.annotation.Nullable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.FlagReaderPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.util.wrapper.BuildInfo;

import javax.inject.Inject;
@@ -54,18 +58,60 @@ import javax.inject.Inject;
public class FeatureFlagReader {
    private final Resources mResources;
    private final boolean mAreFlagsOverrideable;
    private final PluginManager mPluginManager;
    private final SystemPropertiesHelper mSystemPropertiesHelper;
    private final SparseArray<CachedFlag> mCachedFlags = new SparseArray<>();

    private FlagReaderPlugin mPlugin = new FlagReaderPlugin(){};

    @Inject
    public FeatureFlagReader(
            @Main Resources resources,
            BuildInfo build,
            PluginManager pluginManager,
            SystemPropertiesHelper systemPropertiesHelper) {
        mResources = resources;
        mPluginManager = pluginManager;
        mSystemPropertiesHelper = systemPropertiesHelper;
        mAreFlagsOverrideable =
                build.isDebuggable() && mResources.getBoolean(R.bool.are_flags_overrideable);

        mPluginManager.addPluginListener(mPluginListener, FlagReaderPlugin.class);
    }

    private final PluginListener<FlagReaderPlugin> mPluginListener =
            new PluginListener<FlagReaderPlugin>() {
                public void onPluginConnected(FlagReaderPlugin plugin, Context context) {
                    mPlugin = plugin;
                }

                public void onPluginDisconnected(FlagReaderPlugin plugin) {
                    mPlugin = new FlagReaderPlugin() {};
                }
            };

    boolean isEnabled(BooleanFlag flag) {
        return mPlugin.isEnabled(flag.getId(), flag.getDefault());
    }

    String getValue(StringFlag flag) {
        return mPlugin.getValue(flag.getId(), flag.getDefault());
    }

    int getValue(IntFlag flag) {
        return mPlugin.getValue(flag.getId(), flag.getDefault());
    }

    long getValue(LongFlag flag) {
        return mPlugin.getValue(flag.getId(), flag.getDefault());
    }

    float getValue(FloatFlag flag) {
        return mPlugin.getValue(flag.getId(), flag.getDefault());
    }

    double getValue(DoubleFlag flag) {
        return mPlugin.getValue(flag.getId(), flag.getDefault());
    }

    /**
+79 −0
Original line number Diff line number Diff line
@@ -22,6 +22,10 @@ import android.util.FeatureFlagUtils;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import javax.inject.Inject;

/**
@@ -40,6 +44,54 @@ public class FeatureFlags {
        mContext = context;
    }

    /**
     * @param flag The {@link BooleanFlag} of interest.
     * @return The value of the flag.
     */
    public boolean isEnabled(BooleanFlag flag) {
        return mFlagReader.isEnabled(flag);
    }

    /**
     * @param flag The {@link StringFlag} of interest.
     * @return The value of the flag.
     */
    public String getValue(StringFlag flag) {
        return mFlagReader.getValue(flag);
    }

    /**
     * @param flag The {@link IntFlag} of interest.
     * @return The value of the flag.
     */
    public int getValue(IntFlag flag) {
        return mFlagReader.getValue(flag);
    }

    /**
     * @param flag The {@link LongFlag} of interest.
     * @return The value of the flag.
     */
    public long getValue(LongFlag flag) {
        return mFlagReader.getValue(flag);
    }

    /**
     * @param flag The {@link FloatFlag} of interest.
     * @return The value of the flag.
     */
    public float getValue(FloatFlag flag) {
        return mFlagReader.getValue(flag);
    }

    /**
     * @param flag The {@link DoubleFlag} of interest.
     * @return The value of the flag.
     */
    public double getValue(DoubleFlag flag) {
        return mFlagReader.getValue(flag);
    }

    public boolean isNewNotifPipelineEnabled() {
        return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2);
    }
@@ -107,4 +159,31 @@ public class FeatureFlags {
    public static boolean isProviderModelSettingEnabled(Context context) {
        return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
    }

    private Map<Integer, Flag<?>> collectFlags() {
        Map<Integer, Flag<?>> flags = new HashMap<>();

        Field[] fields = this.getClass().getFields();

        for (Field field : fields) {
            Class<?> t = field.getType();
            if (Flag.class.isAssignableFrom(t)) {
                try {
                    //flags.add((Flag<?>) field.get(null));
                    Flag flag = (Flag) field.get(null);
                    flags.put(flag.getId(), flag);
                } catch (IllegalAccessException e) {
                    // no-op
                }
            }
        }

        return flags;
    }

    /** Simple interface for beinga alerted when a specific flag changes value. */
    public interface Listener {
        /** */
        void onFlagChanged(Flag<?> flag);
    }
}
Loading