Bluetooth : Modify build & parse vcard
If the contacts have "p"or "w" instead of "," or ";" when some carkits
are receiving them from andro id OS, some catkits cannot parse the
contacts.
Bug: 5178723
Change-Id: I536ca57aff561fb0637448bcddfd53a6ba8b28ef
diff --git a/java/com/android/vcard/VCardBuilder.java b/java/com/android/vcard/VCardBuilder.java
index ae778c5..969ac1b 100644
--- a/java/com/android/vcard/VCardBuilder.java
+++ b/java/com/android/vcard/VCardBuilder.java
@@ -31,6 +31,7 @@
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
@@ -846,17 +847,39 @@
appendTelLine(type, label, phoneNumber, isPrimary);
}
} else {
- final List<String> phoneNumberList = splitAndTrimPhoneNumbers(phoneNumber);
+ final List<String> phoneNumberList = splitPhoneNumbers(phoneNumber);
if (phoneNumberList.isEmpty()) {
continue;
}
phoneLineExists = true;
for (String actualPhoneNumber : phoneNumberList) {
if (!phoneSet.contains(actualPhoneNumber)) {
- final int phoneFormat = VCardUtils.getPhoneNumberFormat(mVCardType);
- String formatted =
- PhoneNumberUtilsPort.formatNumber(
- actualPhoneNumber, phoneFormat);
+ // 'p' and 'w' are the standard characters for pause and wait
+ // (see RFC 3601)
+ // so use those when exporting phone numbers via vCard.
+ String numberWithControlSequence = actualPhoneNumber
+ .replace(PhoneNumberUtils.PAUSE, 'p')
+ .replace(PhoneNumberUtils.WAIT, 'w');
+ String formatted;
+ // TODO: remove this code and relevant test cases. vCard and any other
+ // codes using it shouldn't rely on the formatter here.
+ if (TextUtils.equals(numberWithControlSequence, actualPhoneNumber)) {
+ StringBuilder digitsOnlyBuilder = new StringBuilder();
+ final int length = actualPhoneNumber.length();
+ for (int i = 0; i < length; i++) {
+ final char ch = actualPhoneNumber.charAt(i);
+ if (Character.isDigit(ch) || ch == '+') {
+ digitsOnlyBuilder.append(ch);
+ }
+ }
+ final int phoneFormat =
+ VCardUtils.getPhoneNumberFormat(mVCardType);
+ formatted = PhoneNumberUtilsPort.formatNumber(
+ digitsOnlyBuilder.toString(), phoneFormat);
+ } else {
+ // Be conservative.
+ formatted = numberWithControlSequence;
+ }
// In vCard 4.0, value type must be "a single URI value",
// not just a phone number. (Based on vCard 4.0 rev.13)
@@ -909,24 +932,23 @@
* Do not call this method when trimming is inappropriate for its receivers.
* </p>
*/
- private List<String> splitAndTrimPhoneNumbers(final String phoneNumber) {
+ private List<String> splitPhoneNumbers(final String phoneNumber) {
final List<String> phoneList = new ArrayList<String>();
StringBuilder builder = new StringBuilder();
final int length = phoneNumber.length();
for (int i = 0; i < length; i++) {
final char ch = phoneNumber.charAt(i);
- if (Character.isDigit(ch) || ch == '+') {
- builder.append(ch);
- } else if ((ch == ';' || ch == '\n') && builder.length() > 0) {
+ if (ch == '\n' && builder.length() > 0) {
phoneList.add(builder.toString());
builder = new StringBuilder();
+ } else {
+ builder.append(ch);
}
}
if (builder.length() > 0) {
phoneList.add(builder.toString());
}
-
return phoneList;
}
diff --git a/java/com/android/vcard/VCardEntry.java b/java/com/android/vcard/VCardEntry.java
index 4edd559..255697b 100644
--- a/java/com/android/vcard/VCardEntry.java
+++ b/java/com/android/vcard/VCardEntry.java
@@ -39,6 +39,7 @@
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
+import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Log;
@@ -1766,21 +1767,37 @@
mPhoneList = new ArrayList<PhoneData>();
}
final StringBuilder builder = new StringBuilder();
- final String trimed = data.trim();
+ final String trimmed = data.trim();
final String formattedNumber;
if (type == Phone.TYPE_PAGER || VCardConfig.refrainPhoneNumberFormatting(mVCardType)) {
- formattedNumber = trimed;
+ formattedNumber = trimmed;
} else {
- final int length = trimed.length();
+ // TODO: from the view of vCard spec these auto conversions should be removed.
+ // Note that some other codes (like the phone number formatter) or modules expect this
+ // auto conversion (bug 5178723), so just omitting this code won't be preferable enough
+ // (bug 4177894)
+ boolean hasPauseOrWait = false;
+ final int length = trimmed.length();
for (int i = 0; i < length; i++) {
- char ch = trimed.charAt(i);
- if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {
+ char ch = trimmed.charAt(i);
+ // See RFC 3601 and docs for PhoneNumberUtils for more info.
+ if (ch == 'p' || ch == 'P') {
+ builder.append(PhoneNumberUtils.PAUSE);
+ hasPauseOrWait = true;
+ } else if (ch == 'w' || ch == 'W') {
+ builder.append(PhoneNumberUtils.WAIT);
+ hasPauseOrWait = true;
+ } else if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {
builder.append(ch);
}
}
-
- final int formattingType = VCardUtils.getPhoneNumberFormat(mVCardType);
- formattedNumber = PhoneNumberUtilsPort.formatNumber(builder.toString(), formattingType);
+ if (!hasPauseOrWait) {
+ final int formattingType = VCardUtils.getPhoneNumberFormat(mVCardType);
+ formattedNumber = PhoneNumberUtilsPort.formatNumber(
+ builder.toString(), formattingType);
+ } else {
+ formattedNumber = builder.toString();
+ }
}
PhoneData phoneData = new PhoneData(formattedNumber, type, label, isPrimary);
mPhoneList.add(phoneData);
diff --git a/tests/res/raw/v30_pause_wait.vcf b/tests/res/raw/v30_pause_wait.vcf
new file mode 100644
index 0000000..e8fc2e9
--- /dev/null
+++ b/tests/res/raw/v30_pause_wait.vcf
@@ -0,0 +1,6 @@
+BEGIN:VCARD
+VERSION:3.0
+FN:Pause Wait
+N:Pause;Wait;;;
+TEL:p1234p5678w9
+END:VCARD
diff --git a/tests/src/com/android/vcard/tests/VCardExporterTests.java b/tests/src/com/android/vcard/tests/VCardExporterTests.java
index 76f4a8f..42f9445 100644
--- a/tests/src/com/android/vcard/tests/VCardExporterTests.java
+++ b/tests/src/com/android/vcard/tests/VCardExporterTests.java
@@ -19,8 +19,8 @@
import com.android.vcard.VCardConfig;
import com.android.vcard.tests.testutils.ContactEntry;
import com.android.vcard.tests.testutils.PropertyNodesVerifierElem;
-import com.android.vcard.tests.testutils.VCardTestsBase;
import com.android.vcard.tests.testutils.PropertyNodesVerifierElem.TypeSet;
+import com.android.vcard.tests.testutils.VCardTestsBase;
import android.content.ContentValues;
import android.provider.ContactsContract.CommonDataKinds.Email;
@@ -1209,8 +1209,8 @@
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
.put(Phone.TYPE, Phone.TYPE_HOME)
- .put(Phone.NUMBER, "111-222-3333 (Miami)\n444-5555-666 (Tokyo);"
- + "777-888-9999 (Chicago);111-222-3333 (Miami)");
+ .put(Phone.NUMBER, "111-222-3333 (Miami)\n444-5555-666 (Tokyo)\n"
+ + "777-888-9999 (Chicago)\n111-222-3333 (Miami)");
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
.addExpectedNode("TEL", "111-222-3333", new TypeSet("HOME"))
.addExpectedNode("TEL", "444-555-5666", new TypeSet("HOME"))
@@ -1292,6 +1292,22 @@
.addExpectedNode("IMPP", "sip:android@example.com");
}
+ public void testPauseAndWaitConversionV30() {
+ mVerifier.initForExportTest(V30);
+ final ContactEntry entry = mVerifier.addInputEntry();
+ // Insert numbers with PAUSE (',' internally, 'p' for outside) and
+ // WAIT (';' internally, 'w' for outside)
+ entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
+ .put(Phone.TYPE, Phone.TYPE_HOME)
+ .put(Phone.NUMBER, "111,222;333");
+ mVerifier.addLineVerifierElem()
+ .addExpected("N:")
+ .addExpected("FN:")
+ .addExpected("TEL;TYPE=HOME:111p222w333");
+ mVerifier.addPropertyNodesVerifierElemWithEmptyName()
+ .addExpectedNode("TEL", "111p222w333", new TypeSet("HOME"));
+ }
+
public void testSipAddressV40() {
mVerifier.initForExportTest(V40);
final ContactEntry entry = mVerifier.addInputEntry();
diff --git a/tests/src/com/android/vcard/tests/VCardImporterTests.java b/tests/src/com/android/vcard/tests/VCardImporterTests.java
index e1efec4..e1843a5 100644
--- a/tests/src/com/android/vcard/tests/VCardImporterTests.java
+++ b/tests/src/com/android/vcard/tests/VCardImporterTests.java
@@ -1239,4 +1239,26 @@
// Smoke test.
elem.addExpected("custom_mime4").put("data1", "z");
}
+
+ public void testPauseWaitV30_Parse() {
+ mVerifier.initForImportTest(V30, R.raw.v30_pause_wait);
+ mVerifier.addPropertyNodesVerifierElem()
+ .addExpectedNodeWithOrder("FN", "Pause Wait")
+ .addExpectedNodeWithOrder("N", "Pause;Wait;;;",
+ Arrays.asList("Pause", "Wait", "", "", ""))
+ .addExpectedNodeWithOrder("TEL", "p1234p5678w9");
+ }
+
+ public void testPauseWaitV30() {
+ mVerifier.initForImportTest(V30, R.raw.v30_pause_wait);
+ final ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
+ elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
+ .put(StructuredName.FAMILY_NAME, "Pause")
+ .put(StructuredName.GIVEN_NAME, "Wait")
+ .put(StructuredName.DISPLAY_NAME, "Pause Wait");
+ // See PhoneNumberUtils in Android SDK.
+ elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+ .put(Phone.TYPE, Phone.TYPE_HOME)
+ .put(Phone.NUMBER, ",1234,5678;9");
+ }
}