Merge "Update the format of RCS provisioning config XML"

This commit is contained in:
Hui Wang
2021-05-11 20:18:26 +00:00
committed by Gerrit Code Review

View File

@@ -22,10 +22,10 @@ import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.os.Build; import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Telephony.SimInfo; import android.provider.Telephony.SimInfo;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.telephony.Rlog; import com.android.telephony.Rlog;
@@ -36,7 +36,9 @@ import org.xmlpull.v1.XmlPullParserFactory;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
@@ -44,23 +46,138 @@ import java.util.zip.GZIPOutputStream;
* RCS config data and methods to process the config * RCS config data and methods to process the config
* @hide * @hide
*/ */
public final class RcsConfig implements Parcelable { public final class RcsConfig {
private static final String LOG_TAG = "RcsConfig"; private static final String LOG_TAG = "RcsConfig";
private static final boolean DBG = Build.IS_ENG; private static final boolean DBG = Build.IS_ENG;
// Tag for Rcs Volte single registration defined in RCC.07 A.1.6.2 // Tag and attribute defined in RCC.07 A.2
private static final String TAG_SINGLE_REGISTRATION = "rcsVolteSingleRegistration"; private static final String TAG_CHARACTERISTIC = "characteristic";
private static final String TAG_PARM = "parm";
private static final String ATTRIBUTE_TYPE = "type";
private static final String ATTRIBUTE_NAME = "name";
private static final String ATTRIBUTE_VALUE = "value";
// Keyword for Rcs Volte single registration defined in RCC.07 A.1.6.2
private static final String PARM_SINGLE_REGISTRATION = "rcsVolteSingleRegistration";
private final HashMap<String, String> mValues = new HashMap<>(); /**
* Characteristic of the RCS provisioning config
*/
public static class Characteristic {
private String mType;
private final Map<String, String> mParms = new ArrayMap<>();
private final Set<Characteristic> mSubs = new ArraySet<>();
private final Characteristic mParent;
private RcsConfig(HashMap<String, String> values) { private Characteristic(String type, Characteristic parent) {
mValues.putAll(values); mType = type;
mParent = parent;
}
private String getType() {
return mType;
}
private Map<String, String> getParms() {
return mParms;
}
private Set<Characteristic> getSubs() {
return mSubs;
}
private Characteristic getParent() {
return mParent;
}
private Characteristic getSubByType(String type) {
if (TextUtils.equals(mType, type)) {
return this;
}
Characteristic result = null;
for (Characteristic sub : mSubs) {
result = sub.getSubByType(type);
if (result != null) {
break;
}
}
return result;
}
private boolean hasSubByType(String type) {
return getSubByType(type) != null;
}
private String getParmValue(String name) {
String value = mParms.get(name);
if (value == null) {
for (Characteristic sub : mSubs) {
value = sub.getParmValue(name);
if (value != null) {
break;
}
}
}
return value;
}
boolean hasParm(String name) {
if (mParms.containsKey(name)) {
return true;
}
for (Characteristic sub : mSubs) {
if (sub.hasParm(name)) {
return true;
}
}
return false;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("[" + mType + "]: ");
if (DBG) {
sb.append(mParms);
}
for (Characteristic sub : mSubs) {
sb.append("\n");
sb.append(sub.toString().replace("\n", "\n\t"));
}
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Characteristic)) {
return false;
}
Characteristic o = (Characteristic) obj;
return TextUtils.equals(mType, o.mType) && mParms.equals(o.mParms)
&& mSubs.equals(o.mSubs);
}
@Override
public int hashCode() {
return Objects.hash(mType, mParms, mSubs);
}
} }
private final Characteristic mRoot;
private Characteristic mCurrent;
private final byte[] mData;
public RcsConfig(byte[] data) throws IllegalArgumentException { public RcsConfig(byte[] data) throws IllegalArgumentException {
if (data == null || data.length == 0) { if (data == null || data.length == 0) {
throw new IllegalArgumentException("Empty data"); throw new IllegalArgumentException("Empty data");
} }
mRoot = new Characteristic(null, null);
mCurrent = mRoot;
mData = data;
Characteristic current = mRoot;
ByteArrayInputStream inputStream = new ByteArrayInputStream(data); ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
try { try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
@@ -69,16 +186,51 @@ public final class RcsConfig implements Parcelable {
xpp.setInput(inputStream, null); xpp.setInput(inputStream, null);
int eventType = xpp.getEventType(); int eventType = xpp.getEventType();
String tag = null; String tag = null;
while (eventType != XmlPullParser.END_DOCUMENT) { while (eventType != XmlPullParser.END_DOCUMENT && current != null) {
if (eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
tag = xpp.getName().trim(); tag = xpp.getName().trim().toLowerCase();
} else if (eventType == XmlPullParser.END_TAG) { if (TAG_CHARACTERISTIC.equals(tag)) {
tag = null; int count = xpp.getAttributeCount();
} else if (eventType == XmlPullParser.TEXT) { String type = null;
String value = xpp.getText().trim(); if (count > 0) {
if (!TextUtils.isEmpty(tag) && !TextUtils.isEmpty(value)) { for (int i = 0; i < count; i++) {
mValues.put(tag, value); String name = xpp.getAttributeName(i).trim().toLowerCase();
if (ATTRIBUTE_TYPE.equals(name)) {
type = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
name).trim().toLowerCase();
break;
}
}
}
Characteristic next = new Characteristic(type, current);
current.getSubs().add(next);
current = next;
} else if (TAG_PARM.equals(tag)) {
int count = xpp.getAttributeCount();
String key = null;
String value = null;
if (count > 1) {
for (int i = 0; i < count; i++) {
String name = xpp.getAttributeName(i).trim().toLowerCase();
if (ATTRIBUTE_NAME.equals(name)) {
key = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
name).trim().toLowerCase();
} else if (ATTRIBUTE_VALUE.equals(name)) {
value = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
name).trim();
}
}
}
if (key != null && value != null) {
current.getParms().put(key, value);
}
} }
} else if (eventType == XmlPullParser.END_TAG) {
tag = xpp.getName().trim().toLowerCase();
if (TAG_CHARACTERISTIC.equals(tag)) {
current = current.getParent();
}
tag = null;
} }
eventType = xpp.next(); eventType = xpp.next();
} }
@@ -102,7 +254,8 @@ public final class RcsConfig implements Parcelable {
* @return Returns the config value if it exists, or defaultVal. * @return Returns the config value if it exists, or defaultVal.
*/ */
public @Nullable String getString(@NonNull String tag, @Nullable String defaultVal) { public @Nullable String getString(@NonNull String tag, @Nullable String defaultVal) {
return mValues.containsKey(tag) ? mValues.get(tag) : defaultVal; String value = mCurrent.getParmValue(tag.trim().toLowerCase());
return value != null ? value : defaultVal;
} }
/** /**
@@ -115,7 +268,7 @@ public final class RcsConfig implements Parcelable {
*/ */
public int getInteger(@NonNull String tag, int defaultVal) { public int getInteger(@NonNull String tag, int defaultVal) {
try { try {
return Integer.parseInt(mValues.get(tag)); return Integer.parseInt(getString(tag, null));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
logd("error to getInteger for " + tag + " due to " + e); logd("error to getInteger for " + tag + " due to " + e);
} }
@@ -131,10 +284,8 @@ public final class RcsConfig implements Parcelable {
* @return Returns the config value if it exists, or defaultVal. * @return Returns the config value if it exists, or defaultVal.
*/ */
public boolean getBoolean(@NonNull String tag, boolean defaultVal) { public boolean getBoolean(@NonNull String tag, boolean defaultVal) {
if (!mValues.containsKey(tag)) { String value = getString(tag, null);
return defaultVal; return value != null ? Boolean.parseBoolean(value) : defaultVal;
}
return Boolean.parseBoolean(mValues.get(tag));
} }
/** /**
@@ -145,15 +296,70 @@ public final class RcsConfig implements Parcelable {
* @return Returns true if it exists, or false. * @return Returns true if it exists, or false.
*/ */
public boolean hasConfig(@NonNull String tag) { public boolean hasConfig(@NonNull String tag) {
return mValues.containsKey(tag); return mCurrent.hasParm(tag.trim().toLowerCase());
}
/**
* Return the Characteristic with the given type
*/
public @Nullable Characteristic getCharacteristic(@NonNull String type) {
return mCurrent.getSubByType(type.trim().toLowerCase());
}
/**
* Check whether the Characteristic with the given type exists
*/
public boolean hasCharacteristic(@NonNull String type) {
return mCurrent.getSubByType(type.trim().toLowerCase()) != null;
}
/**
* Set current Characteristic to given Characteristic
*/
public void setCurrentCharacteristic(@NonNull Characteristic current) {
if (current != null) {
mCurrent = current;
}
}
/**
* Move current Characteristic to parent layer
*/
public boolean moveToParent() {
if (mCurrent.getParent() == null) {
return false;
}
mCurrent = mCurrent.getParent();
return true;
}
/**
* Move current Characteristic to the root
*/
public void moveToRoot() {
mCurrent = mRoot;
}
/**
* Return root Characteristic
*/
public @NonNull Characteristic getRoot() {
return mRoot;
}
/**
* Return current Characteristic
*/
public @NonNull Characteristic getCurrentCharacteristic() {
return mCurrent;
} }
/** /**
* Check whether Rcs Volte single registration is supported by the config. * Check whether Rcs Volte single registration is supported by the config.
*/ */
public boolean isRcsVolteSingleRegistrationSupported() { public boolean isRcsVolteSingleRegistrationSupported() {
return getBoolean(TAG_SINGLE_REGISTRATION, false) return getBoolean(PARM_SINGLE_REGISTRATION, false)
|| getInteger(TAG_SINGLE_REGISTRATION, 0) != 0; || getInteger(PARM_SINGLE_REGISTRATION, 0) != 0;
} }
@Override @Override
@@ -161,12 +367,10 @@ public final class RcsConfig implements Parcelable {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("[RCS Config]"); sb.append("[RCS Config]");
if (DBG) { if (DBG) {
mValues.forEach((t, v) -> { sb.append("=== Root ===\n");
sb.append("\n"); sb.append(mRoot);
sb.append(t); sb.append("=== Current ===\n");
sb.append(" : "); sb.append(mCurrent);
sb.append(v);
});
} }
return sb.toString(); return sb.toString();
} }
@@ -179,12 +383,12 @@ public final class RcsConfig implements Parcelable {
RcsConfig other = (RcsConfig) obj; RcsConfig other = (RcsConfig) obj;
return mValues.equals(other.mValues); return mRoot.equals(other.mRoot) && mCurrent.equals(other.mCurrent);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return mValues.hashCode(); return Objects.hash(mRoot, mCurrent);
} }
/** /**
@@ -275,38 +479,6 @@ public final class RcsConfig implements Parcelable {
return isCompressed ? data : decompressGzip(data); return isCompressed ? data : decompressGzip(data);
} }
/**
* {@link Parcelable#writeToParcel}
*/
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeMap(mValues);
}
/**
* {@link Parcelable.Creator}
*
*/
public static final @NonNull Parcelable.Creator<RcsConfig>
CREATOR = new Creator<RcsConfig>() {
@Override
public RcsConfig createFromParcel(Parcel in) {
HashMap<String, String> values = in.readHashMap(null);
return values == null ? null : new RcsConfig(values);
}
@Override
public RcsConfig[] newArray(int size) {
return new RcsConfig[size];
}
};
/**
* {@link Parcelable#describeContents}
*/
public int describeContents() {
return 0;
}
private static void logd(String msg) { private static void logd(String msg) {
Rlog.d(LOG_TAG, msg); Rlog.d(LOG_TAG, msg);
} }