Handle custom labels correctly.
Previous implementation uses upper-case strings instead of original
expressions in vCard, so "X-Custom" becomes the custom type "CUSTOM"
Add test case for this fix.
Bug: 3207011
Change-Id: I287fd595a80453e18b2bb57600ea8d0bd8b78ffd
diff --git a/java/com/android/vcard/VCardEntry.java b/java/com/android/vcard/VCardEntry.java
index 66104bf..655a80f 100644
--- a/java/com/android/vcard/VCardEntry.java
+++ b/java/com/android/vcard/VCardEntry.java
@@ -871,34 +871,34 @@
int type = -1;
String label = "";
boolean isPrimary = false;
- Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
+ final Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
if (typeCollection != null) {
- for (String typeString : typeCollection) {
- typeString = typeString.toUpperCase();
- if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
+ for (final String typeStringOrg : typeCollection) {
+ final String typeStringUpperCase = typeStringOrg.toUpperCase();
+ if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_PREF)) {
isPrimary = true;
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_HOME)) {
+ } else if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_HOME)) {
type = StructuredPostal.TYPE_HOME;
label = "";
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_WORK) ||
- typeString.equalsIgnoreCase(VCardConstants.PARAM_EXTRA_TYPE_COMPANY)) {
+ } else if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_WORK) ||
+ typeStringUpperCase.equalsIgnoreCase(
+ VCardConstants.PARAM_EXTRA_TYPE_COMPANY)) {
// "COMPANY" seems emitted by Windows Mobile, which is not
// specifically supported by vCard 2.1. We assume this is same
// as "WORK".
type = StructuredPostal.TYPE_WORK;
label = "";
- } else if (typeString.equals(VCardConstants.PARAM_ADR_TYPE_PARCEL) ||
- typeString.equals(VCardConstants.PARAM_ADR_TYPE_DOM) ||
- typeString.equals(VCardConstants.PARAM_ADR_TYPE_INTL)) {
+ } else if (typeStringUpperCase.equals(VCardConstants.PARAM_ADR_TYPE_PARCEL) ||
+ typeStringUpperCase.equals(VCardConstants.PARAM_ADR_TYPE_DOM) ||
+ typeStringUpperCase.equals(VCardConstants.PARAM_ADR_TYPE_INTL)) {
// We do not have any appropriate way to store this information.
- } else {
- if (typeString.startsWith("X-") && type < 0) {
- typeString = typeString.substring(2);
- }
- // vCard 3.0 allows iana-token. Also some vCard 2.1 exporters
- // emit non-standard types. We do not handle their values now.
+ } else if (type < 0) { // If no other type is specified before
type = StructuredPostal.TYPE_CUSTOM;
- label = typeString;
+ if (typeStringUpperCase.startsWith("X-")) { // If X- or x-
+ label = typeStringOrg.substring(2);
+ } else {
+ label = typeStringOrg;
+ }
}
}
}
@@ -912,27 +912,25 @@
int type = -1;
String label = null;
boolean isPrimary = false;
- Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
+ final Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
if (typeCollection != null) {
- for (String typeString : typeCollection) {
- typeString = typeString.toUpperCase();
- if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
+ for (final String typeStringOrg : typeCollection) {
+ final String typeStringUpperCase = typeStringOrg.toUpperCase();
+ if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_PREF)) {
isPrimary = true;
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_HOME)) {
+ } else if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_HOME)) {
type = Email.TYPE_HOME;
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_WORK)) {
+ } else if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_WORK)) {
type = Email.TYPE_WORK;
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_CELL)) {
+ } else if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_CELL)) {
type = Email.TYPE_MOBILE;
- } else {
- if (typeString.startsWith("X-") && type < 0) {
- typeString = typeString.substring(2);
+ } else if (type < 0) { // If no other type is specified before
+ if (typeStringUpperCase.startsWith("X-")) { // If X- or x-
+ label = typeStringOrg.substring(2);
+ } else {
+ label = typeStringOrg;
}
- // vCard 3.0 allows iana-token.
- // We may have INTERNET (specified in vCard spec),
- // SCHOOL, etc.
type = Email.TYPE_CUSTOM;
- label = typeString;
}
}
}
diff --git a/java/com/android/vcard/VCardUtils.java b/java/com/android/vcard/VCardUtils.java
index a6eba12..1bd35ba 100644
--- a/java/com/android/vcard/VCardUtils.java
+++ b/java/com/android/vcard/VCardUtils.java
@@ -167,23 +167,27 @@
boolean hasPref = false;
if (types != null) {
- for (String typeString : types) {
- if (typeString == null) {
+ for (final String typeStringOrg : types) {
+ if (typeStringOrg == null) {
continue;
}
- typeString = typeString.toUpperCase();
- if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) {
+ final String typeStringUpperCase = typeStringOrg.toUpperCase();
+ if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_PREF)) {
hasPref = true;
- } else if (typeString.equals(VCardConstants.PARAM_TYPE_FAX)) {
+ } else if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_FAX)) {
isFax = true;
} else {
- if (typeString.startsWith("X-") && type < 0) {
- typeString = typeString.substring(2);
+ final String labelCandidate;
+ if (typeStringUpperCase.startsWith("X-") && type < 0) {
+ labelCandidate = typeStringOrg.substring(2);
+ } else {
+ labelCandidate = typeStringOrg;
}
- if (typeString.length() == 0) {
+ if (labelCandidate.length() == 0) {
continue;
}
- final Integer tmp = sKnownPhoneTypeMap_StoI.get(typeString);
+ // e.g. "home" -> TYPE_HOME
+ final Integer tmp = sKnownPhoneTypeMap_StoI.get(labelCandidate.toUpperCase());
if (tmp != null) {
final int typeCandidate = tmp;
// TYPE_PAGER is prefered when the number contains @ surronded by
@@ -201,7 +205,7 @@
}
} else if (type < 0) {
type = Phone.TYPE_CUSTOM;
- label = typeString;
+ label = labelCandidate;
}
}
}
diff --git a/tests/res/raw/v21_x_param.vcf b/tests/res/raw/v21_x_param.vcf
new file mode 100644
index 0000000..e47ea5e
--- /dev/null
+++ b/tests/res/raw/v21_x_param.vcf
@@ -0,0 +1,9 @@
+BEGIN:VCARD
+VERSION:2.1
+N:Ando;Roid;
+ADR;X-custom:pobox;street
+TEL;X-CuStoMpRop:1
+TEL;custompropertywithoutx:2
+EMAIL;X-cUstomPrOperty:email@example.com
+EMAIL;CUSTOMPROPERTYWITHOUTX:email2@example.com
+END:VCARD
diff --git a/tests/src/com/android/vcard/tests/VCardImporterTests.java b/tests/src/com/android/vcard/tests/VCardImporterTests.java
index 2900106..716c866 100644
--- a/tests/src/com/android/vcard/tests/VCardImporterTests.java
+++ b/tests/src/com/android/vcard/tests/VCardImporterTests.java
@@ -1158,4 +1158,49 @@
elem.addExpected(SipAddress.CONTENT_ITEM_TYPE)
.put(SipAddress.SIP_ADDRESS, "example@example.com");
}
+
+ public void testCustomPropertyV21_Parse() {
+ mVerifier.initForImportTest(V21, R.raw.v21_x_param);
+ mVerifier.addPropertyNodesVerifierElem()
+ .addExpectedNodeWithOrder("N", "Ando;Roid;", Arrays.asList("Ando", "Roid", ""))
+ .addExpectedNodeWithOrder("ADR", "pobox;street", Arrays.asList("pobox", "street"),
+ new TypeSet("X-custom"))
+ .addExpectedNodeWithOrder("TEL", "1", new TypeSet("X-CuStoMpRop"))
+ .addExpectedNodeWithOrder("TEL", "2", new TypeSet("custompropertywithoutx"))
+ .addExpectedNodeWithOrder("EMAIL", "email@example.com",
+ new TypeSet("X-cUstomPrOperty"))
+ .addExpectedNodeWithOrder("EMAIL", "email2@example.com",
+ new TypeSet("CUSTOMPROPERTYWITHOUTX"));
+ }
+
+ public void testCustomPropertyV21() {
+ mVerifier.initForImportTest(V21, R.raw.v21_x_param);
+ final ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
+ elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
+ .put(StructuredName.FAMILY_NAME, "Ando")
+ .put(StructuredName.GIVEN_NAME, "Roid")
+ .put(StructuredName.DISPLAY_NAME, "Roid Ando");
+ elem.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
+ .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
+ .put(StructuredPostal.LABEL, "custom")
+ .put(StructuredPostal.POBOX, "pobox")
+ .put(StructuredPostal.STREET, "street")
+ .put(StructuredPostal.FORMATTED_ADDRESS, "pobox street");
+ elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+ .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+ .put(Phone.LABEL, "CuStoMpRop")
+ .put(Phone.NUMBER, "1");
+ elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+ .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+ .put(Phone.LABEL, "custompropertywithoutx")
+ .put(Phone.NUMBER, "2");
+ elem.addExpected(Email.CONTENT_ITEM_TYPE)
+ .put(Email.TYPE, Email.TYPE_CUSTOM)
+ .put(Email.LABEL, "cUstomPrOperty")
+ .put(Email.ADDRESS, "email@example.com");
+ elem.addExpected(Email.CONTENT_ITEM_TYPE)
+ .put(Email.TYPE, Email.TYPE_CUSTOM)
+ .put(Email.LABEL, "CUSTOMPROPERTYWITHOUTX")
+ .put(Email.ADDRESS, "email2@example.com");
+ }
}