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

Commit 155b0fe3 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add ability to set/erase flags via intents." into sc-v2-dev

parents c9048fa3 f6db05e5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -183,6 +183,9 @@
    <permission android:name="com.android.systemui.permission.PLUGIN"
            android:protectionLevel="signature" />

    <permission android:name="com.android.systemui.permission.FLAGS"
                android:protectionLevel="signature" />

    <!-- Adding Quick Settings tiles -->
    <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />

+39 −0
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.systemui.flags;

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

/**
 * List of {@link Flag} objects for use in SystemUI.
 *
@@ -26,4 +30,39 @@ package com.android.systemui.flags;
 */
public class Flags {
    public static final BooleanFlag THE_FIRST_FLAG = new BooleanFlag(1, false);


    // Pay no attention to the reflection behind the curtain.
    // ========================== Curtain ==========================
    // |                                                           |
    // |  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  |
    private static Map<Integer, Flag<?>> sFlagMap;
    static Map<Integer, Flag<?>> collectFlags() {
        if (sFlagMap != null) {
            return sFlagMap;
        }
        Map<Integer, Flag<?>> flags = new HashMap<>();

        Field[] fields = Flags.class.getFields();

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

        sFlagMap = flags;

        return sFlagMap;
    }
    // |  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  |
    // |                                                           |
    // \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

}
+75 −6
Original line number Diff line number Diff line
@@ -16,32 +16,55 @@

package com.android.systemui.flags;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;

import com.android.systemui.dagger.SysUISingleton;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.Map;

import javax.inject.Inject;

/**
 * Concrete implementation of the a Flag manager that returns default values for debug builds
 *
 * Flags can be set (or unset) via the following adb command:
 *
 *   adb shell am broadcast -a com.android.systemui.action.SET_FLAG --ei id <id> [--ez value <0|1>]
 *
 * To restore a flag back to its default, leave the `--ez value <0|1>` off of the command.
 */
@SysUISingleton
public class FeatureFlagManager implements FlagReader, FlagWriter {
    private static final String TAG = "SysUIFlags";

    private static final String SYSPROP_PREFIX = "persist.systemui.flag_";
    private static final String FIELD_TYPE = "type";
    private static final String FIELD_ID = "id";
    private static final String FIELD_VALUE = "value";
    private static final String TYPE_BOOLEAN = "boolean";
    private static final String ACTION_SET_FLAG = "com.android.systemui.action.SET_FLAG";
    private static final String FLAGS_PERMISSION = "com.android.systemui.permission.FLAGS";
    private final SystemPropertiesHelper mSystemPropertiesHelper;

    @Inject
    public FeatureFlagManager(SystemPropertiesHelper systemPropertiesHelper) {
    public FeatureFlagManager(SystemPropertiesHelper systemPropertiesHelper, Context context) {
        mSystemPropertiesHelper = systemPropertiesHelper;

        IntentFilter filter = new IntentFilter(ACTION_SET_FLAG);
        context.registerReceiver(mReceiver, filter, FLAGS_PERMISSION, null);
    }

    /** Return a {@link BooleanFlag}'s value. */
    public boolean isEnabled(int key, boolean defaultValue) {
        String data = mSystemPropertiesHelper.get(keyToSysPropKey(key));
    public boolean isEnabled(int id, boolean defaultValue) {
        String data = mSystemPropertiesHelper.get(keyToSysPropKey(id));
        if (data.isEmpty()) {
            return defaultValue;
        }
@@ -53,22 +76,31 @@ public class FeatureFlagManager implements FlagReader, FlagWriter {
            }
            return json.getBoolean(FIELD_VALUE);
        } catch (JSONException e) {
            // TODO: delete the property
            eraseFlag(id);
            return defaultValue;
        }
    }

    public void setEnabled(int key, boolean value) {
    /** Set whether a given {@link BooleanFlag} is enabled or not. */
    public void setEnabled(int id, boolean value) {
        JSONObject json = new JSONObject();
        try {
            json.put(FIELD_TYPE, TYPE_BOOLEAN);
            json.put(FIELD_VALUE, value);
            mSystemPropertiesHelper.set(keyToSysPropKey(key), json.toString());
            mSystemPropertiesHelper.set(keyToSysPropKey(id), json.toString());
            Log.i(TAG, "Set id " + id + " to  " + value);
        } catch (JSONException e) {
            // no-op
        }
    }

    /** Erase a flag's overridden value if there is one. */
    public void eraseFlag(int id) {
        // We can't actually "erase" things from sysprops, but we can set them to empty!
        mSystemPropertiesHelper.set(keyToSysPropKey(id), "");
        Log.i(TAG, "Erase id " + id);
    }

    public void addListener(Listener run) {}

    public void removeListener(Listener run) {}
@@ -85,4 +117,41 @@ public class FeatureFlagManager implements FlagReader, FlagWriter {
        }
    }

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action == null) {
                return;
            }

            if (ACTION_SET_FLAG.equals(action)) {
                handleSetFlag(intent.getExtras());
            }
        }

        private void handleSetFlag(Bundle extras) {
            int id = extras.getInt(FIELD_ID);
            if (id <= 0) {
                Log.w(TAG, "ID not set or less than  or equal to 0: " + id);
                return;
            }

            Map<Integer, Flag<?>> flagMap = Flags.collectFlags();
            if (!flagMap.containsKey(id)) {
                Log.w(TAG, "Tried to set unknown id: " + id);
                return;
            }
            Flag<?> flag = flagMap.get(id);

            if (!extras.containsKey(FIELD_VALUE)) {
                eraseFlag(id);
                return;
            }

            if (flag instanceof BooleanFlag) {
                setEnabled(id, extras.getBoolean(FIELD_VALUE));
            }
        }
    };
}