Add ability to set/erase flags via intents.
A flag can be set with a command like the following: adb shell am broadcast -a com.android.systemui.action.SET_FLAG \ --ei id 1 --ez value 1 A flag can be "erased" with the same command, but leaving the value unset. Bug: 202860494 Test: manual Change-Id: If1097e230692df49a6de7cbbb71ed37b0499c663
This commit is contained in:
@@ -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" />
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
// | . . . . . . . . . . . . . . . . . . . |
|
||||
// | |
|
||||
// \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user