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

This commit is contained in:
TreeHugger Robot
2021-10-15 14:55:08 +00:00
committed by Android (Google) Code Review
3 changed files with 117 additions and 6 deletions

View File

@@ -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" />

View File

@@ -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;
}
// | . . . . . . . . . . . . . . . . . . . |
// | |
// \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
}

View File

@@ -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));
}
}
};
}