Extend 'phone cc set-value' to support bundle-valued carrier config
1. Created new command "set-values-from-xml" to allow setting config
using an XML file that follows AOSP CarrierConfig format from stdin
E.g.
$ adb shell cmd phone cc set-values-from-xml < test.xml
Previous value:
inflate_signal_strength_bool
BOOLEAN true
New value:
inflate_signal_strength_bool
BOOLEAN true
Previous value:
opportunistic.5g_data_switch_hysteresis_time_long_bundle
PERSISTABLE_BUNDLE PersistableBundle[{}]
New value:
opportunistic.5g_data_switch_hysteresis_time_long_bundle
PERSISTABLE_BUNDLE PersistableBundle[{48=2000, 71=2000}]
2. Update "get-value" to support PersistableBundle type
3. Update "set-value" to notify user to use "set-values-from-xml" when
handling PersistableBundle type config
Test: manual tests
Bug: 222332191
Change-Id: Id26fcbbd11a7486f87e3b034c0badf923c63b8f6
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 2726855..ceaca25 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -57,6 +57,7 @@
import com.android.modules.utils.BasicShellCommandHandler;
import com.android.phone.callcomposer.CallComposerPictureManager;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -113,6 +114,7 @@
private static final String CC_GET_VALUE = "get-value";
private static final String CC_SET_VALUE = "set-value";
+ private static final String CC_SET_VALUES_FROM_XML = "set-values-from-xml";
private static final String CC_CLEAR_VALUES = "clear-values";
private static final String GBA_SUBCOMMAND = "gba";
@@ -184,7 +186,7 @@
private enum CcType {
BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
- STRING_ARRAY, UNKNOWN
+ STRING_ARRAY, PERSISTABLE_BUNDLE, UNKNOWN
}
private class CcOptionParseResult {
@@ -582,9 +584,17 @@
pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with");
pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\"");
+ pw.println(" cc set-values-from-xml [-s SLOT_ID] [-p] < XML_FILE_PATH");
+ pw.println(" Set carrier config based on the contents of the XML_FILE. File must be");
+ pw.println(" provided through standard input and follow CarrierConfig XML format.");
+ pw.println(" Example: packages/apps/CarrierConfig/assets/*.xml");
+ pw.println(" Options are:");
+ pw.println(" -s: The SIM slot ID to set carrier config value for. If no option");
+ pw.println(" is specified, it will choose the default voice SIM slot.");
+ pw.println(" -p: Value will be stored persistent");
pw.println(" cc clear-values [-s SLOT_ID]");
pw.println(" Clear all carrier override values that has previously been set");
- pw.println(" with set-value");
+ pw.println(" with set-value or set-values-from-xml");
pw.println(" Options are:");
pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option");
pw.println(" is specified, it will choose the default voice SIM slot.");
@@ -1503,6 +1513,9 @@
case CC_SET_VALUE: {
return handleCcSetValue();
}
+ case CC_SET_VALUES_FROM_XML: {
+ return handleCcSetValuesFromXml();
+ }
case CC_CLEAR_VALUES: {
return handleCcClearValues();
}
@@ -1520,7 +1533,7 @@
String key = null;
// Parse all options
- CcOptionParseResult options = parseCcOptions(tag, false);
+ CcOptionParseResult options = parseCcOptions(tag, false);
if (options == null) {
return -1;
}
@@ -1560,7 +1573,7 @@
String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
// Parse all options
- CcOptionParseResult options = parseCcOptions(tag, true);
+ CcOptionParseResult options = parseCcOptions(tag, true);
if (options == null) {
return -1;
}
@@ -1597,6 +1610,11 @@
errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
return -1;
}
+ if (type == CcType.PERSISTABLE_BUNDLE) {
+ errPw.println(tag + "ERROR: Overriding of persistable bundle type is not supported. "
+ + "Use set-values-from-xml instead.");
+ return -1;
+ }
// Create an override bundle containing the key and value that should be overriden.
PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
@@ -1623,13 +1641,79 @@
return 0;
}
+ // cc set-values-from-xml
+ private int handleCcSetValuesFromXml() {
+ PrintWriter errPw = getErrPrintWriter();
+ String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUES_FROM_XML + ": ";
+
+ // Parse all options
+ CcOptionParseResult options = parseCcOptions(tag, false);
+ if (options == null) {
+ return -1;
+ }
+
+ // Get bundle containing all current carrier configuration values.
+ PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
+ if (originalValues == null) {
+ errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
+ return -1;
+ }
+
+ PersistableBundle overrideBundle = readPersistableBundleFromXml(tag);
+ if (overrideBundle == null) {
+ return -1;
+ }
+
+ // Verify all values are valid types
+ for (String key : overrideBundle.keySet()) {
+ CcType type = getType(tag, key, originalValues);
+ if (type == CcType.UNKNOWN) {
+ errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
+ return -1;
+ }
+ }
+
+ // Override the value
+ mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
+
+ // Find bundle containing all new carrier configuration values after the override.
+ PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
+ if (newValues == null) {
+ errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
+ return -1;
+ }
+
+ // Print the original and new values
+ overrideBundle.keySet().forEach(key -> {
+ CcType type = getType(tag, key, originalValues);
+ String originalValueString = ccValueToString(key, type, originalValues);
+ String newValueString = ccValueToString(key, type, newValues);
+ getOutPrintWriter().println("Previous value: \n" + originalValueString);
+ getOutPrintWriter().println("New value: \n" + newValueString);
+ });
+
+ return 0;
+ }
+
+ private PersistableBundle readPersistableBundleFromXml(String tag) {
+ PersistableBundle subIdBundles;
+ try {
+ subIdBundles = PersistableBundle.readFromStream(getRawInputStream());
+ } catch (IOException | RuntimeException e) {
+ PrintWriter errPw = getErrPrintWriter();
+ errPw.println(tag + e);
+ return null;
+ }
+
+ return subIdBundles;
+ }
+
// cc clear-values
private int handleCcClearValues() {
- PrintWriter errPw = getErrPrintWriter();
String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
// Parse all options
- CcOptionParseResult options = parseCcOptions(tag, false);
+ CcOptionParseResult options = parseCcOptions(tag, false);
if (options == null) {
return -1;
}
@@ -1650,23 +1734,34 @@
} else if (value != null) {
if (value instanceof Boolean) {
return CcType.BOOLEAN;
- } else if (value instanceof Double) {
+ }
+ if (value instanceof Double) {
return CcType.DOUBLE;
- } else if (value instanceof double[]) {
+ }
+ if (value instanceof double[]) {
return CcType.DOUBLE_ARRAY;
- } else if (value instanceof Integer) {
+ }
+ if (value instanceof Integer) {
return CcType.INT;
- } else if (value instanceof int[]) {
+ }
+ if (value instanceof int[]) {
return CcType.INT_ARRAY;
- } else if (value instanceof Long) {
+ }
+ if (value instanceof Long) {
return CcType.LONG;
- } else if (value instanceof long[]) {
+ }
+ if (value instanceof long[]) {
return CcType.LONG_ARRAY;
- } else if (value instanceof String) {
+ }
+ if (value instanceof String) {
return CcType.STRING;
- } else if (value instanceof String[]) {
+ }
+ if (value instanceof String[]) {
return CcType.STRING_ARRAY;
}
+ if (value instanceof PersistableBundle) {
+ return CcType.PERSISTABLE_BUNDLE;
+ }
} else {
// Current value was null and can therefore not be used in order to find the type.
// Check the name of the key to infer the type. This check is not needed for primitive
@@ -1686,6 +1781,9 @@
if (key.endsWith("string_array") || key.endsWith("strings")) {
return CcType.STRING_ARRAY;
}
+ if (key.endsWith("bundle")) {
+ return CcType.PERSISTABLE_BUNDLE;
+ }
}
// Not possible to infer the type by looking at the current value or the key.