am f996ed9f: Merge "Make vCard importer/exporter aware of multi-byte parameters." into gingerbread
Merge commit 'f996ed9f2e4a992e5d884077a15dcc23a8d90c44' into gingerbread-plus-aosp * commit 'f996ed9f2e4a992e5d884077a15dcc23a8d90c44': Make vCard importer/exporter aware of multi-byte parameters.
This commit is contained in:
@@ -1463,6 +1463,9 @@ public class VCardBuilder {
|
|||||||
parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
|
parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
|
||||||
} else if (VCardUtils.isMobilePhoneLabel(label)) {
|
} else if (VCardUtils.isMobilePhoneLabel(label)) {
|
||||||
parameterList.add(VCardConstants.PARAM_TYPE_CELL);
|
parameterList.add(VCardConstants.PARAM_TYPE_CELL);
|
||||||
|
} else if (mIsV30) {
|
||||||
|
// This label is appropriately encoded in appendTypeParameters.
|
||||||
|
parameterList.add(label);
|
||||||
} else {
|
} else {
|
||||||
final String upperLabel = label.toUpperCase();
|
final String upperLabel = label.toUpperCase();
|
||||||
if (VCardUtils.isValidInV21ButUnknownToContactsPhoteType(upperLabel)) {
|
if (VCardUtils.isValidInV21ButUnknownToContactsPhoteType(upperLabel)) {
|
||||||
@@ -1741,21 +1744,30 @@ public class VCardBuilder {
|
|||||||
// which would be recommended way in vcard 3.0 though not valid in vCard 2.1.
|
// which would be recommended way in vcard 3.0 though not valid in vCard 2.1.
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (final String typeValue : types) {
|
for (final String typeValue : types) {
|
||||||
// Note: vCard 3.0 specifies the different type of acceptable type Strings, but
|
if (VCardConfig.isV30(mVCardType)) {
|
||||||
// we don't emit that kind of vCard 3.0 specific type since there should be
|
// Note: vCard 3.0 specifies the different type of acceptable type Strings, but
|
||||||
// high probabilyty in which external importers cannot understand them.
|
// we don't emit that kind of vCard 3.0 specific type since there should be
|
||||||
//
|
// high probabilyty in which external importers cannot understand them.
|
||||||
// e.g. TYPE="\u578B\u306B\u3087" (vCard 3.0 allows non-Ascii characters if they
|
//
|
||||||
// are quoted.)
|
// e.g. TYPE="\u578B\u306B\u3087" (vCard 3.0 allows non-Ascii characters if they
|
||||||
if (!VCardUtils.isV21Word(typeValue)) {
|
// are quoted.)
|
||||||
continue;
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
mBuilder.append(VCARD_PARAM_SEPARATOR);
|
||||||
|
}
|
||||||
|
appendTypeParameter(VCardUtils.toStringAvailableAsV30ParameValue(typeValue));
|
||||||
|
} else { // vCard 2.1
|
||||||
|
if (!VCardUtils.isV21Word(typeValue)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
mBuilder.append(VCARD_PARAM_SEPARATOR);
|
||||||
|
}
|
||||||
|
appendTypeParameter(typeValue);
|
||||||
}
|
}
|
||||||
if (first) {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
mBuilder.append(VCARD_PARAM_SEPARATOR);
|
|
||||||
}
|
|
||||||
appendTypeParameter(typeValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -157,11 +157,15 @@ public class VCardEntryConstructor implements VCardInterpreter {
|
|||||||
mParamType = type;
|
mParamType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void propertyParamValue(String value) {
|
public void propertyParamValue(String value) {
|
||||||
if (mParamType == null) {
|
if (mParamType == null) {
|
||||||
// From vCard 2.1 specification. vCard 3.0 formally does not allow this case.
|
// From vCard 2.1 specification. vCard 3.0 formally does not allow this case.
|
||||||
mParamType = "TYPE";
|
mParamType = "TYPE";
|
||||||
}
|
}
|
||||||
|
if (!VCardUtils.containsOnlyAlphaDigitHyphen(value)) {
|
||||||
|
value = encodeString(value, mCharsetForDecodedBytes);
|
||||||
|
}
|
||||||
mCurrentProperty.addParameter(mParamType, value);
|
mCurrentProperty.addParameter(mParamType, value);
|
||||||
mParamType = null;
|
mParamType = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
package android.pim.vcard;
|
package android.pim.vcard;
|
||||||
|
|
||||||
import android.content.ContentProviderOperation;
|
import android.content.ContentProviderOperation;
|
||||||
import android.provider.ContactsContract.Data;
|
|
||||||
import android.provider.ContactsContract.CommonDataKinds.Im;
|
import android.provider.ContactsContract.CommonDataKinds.Im;
|
||||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||||
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
|
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
|
||||||
|
import android.provider.ContactsContract.Data;
|
||||||
import android.telephony.PhoneNumberUtils;
|
import android.telephony.PhoneNumberUtils;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
@@ -477,6 +477,43 @@ public class VCardUtils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <P>
|
||||||
|
* Returns String available as parameter value in vCard 3.0.
|
||||||
|
* </P>
|
||||||
|
* <P>
|
||||||
|
* RFC 2426 requires vCard composer to quote parameter values when it contains
|
||||||
|
* semi-colon, for example (See RFC 2426 for more information).
|
||||||
|
* This method checks whether the given String can be used without quotes.
|
||||||
|
* </P>
|
||||||
|
* <P>
|
||||||
|
* Note: We remove DQUOTE silently for now.
|
||||||
|
* </P>
|
||||||
|
*/
|
||||||
|
public static String toStringAvailableAsV30ParameValue(String value) {
|
||||||
|
if (TextUtils.isEmpty(value)) {
|
||||||
|
value = "";
|
||||||
|
}
|
||||||
|
final int asciiFirst = 0x20;
|
||||||
|
final int asciiLast = 0x7E; // included
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
final int length = value.length();
|
||||||
|
boolean needQuote = false;
|
||||||
|
for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
|
||||||
|
final int codePoint = value.codePointAt(i);
|
||||||
|
if (codePoint < asciiFirst || codePoint == '"') {
|
||||||
|
// CTL characters and DQUOTE are never accepted. Remove them.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
builder.appendCodePoint(codePoint);
|
||||||
|
if (codePoint == ':' || codePoint == ',' || codePoint == ' ') {
|
||||||
|
needQuote = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String result = builder.toString();
|
||||||
|
return ((needQuote || result.isEmpty()) ? ('"' + result + '"') : result);
|
||||||
|
}
|
||||||
|
|
||||||
public static String toHalfWidthString(final String orgString) {
|
public static String toHalfWidthString(final String orgString) {
|
||||||
if (TextUtils.isEmpty(orgString)) {
|
if (TextUtils.isEmpty(orgString)) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
5
core/tests/coretests/res/raw/v30_multibyte_param.vcf
Normal file
5
core/tests/coretests/res/raw/v30_multibyte_param.vcf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
BEGIN:VCARD
|
||||||
|
VERSION:3.0
|
||||||
|
N:F;G;M;;
|
||||||
|
TEL;TYPE="费":1
|
||||||
|
END:VCARD
|
||||||
@@ -1008,4 +1008,26 @@ public class VCardImporterTests extends VCardTestsBase {
|
|||||||
.put(Phone.TYPE, Phone.TYPE_PAGER)
|
.put(Phone.TYPE, Phone.TYPE_PAGER)
|
||||||
.put(Phone.NUMBER, "6101231234@pagersample.com");
|
.put(Phone.NUMBER, "6101231234@pagersample.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testMultiBytePropV30_Parse() {
|
||||||
|
mVerifier.initForImportTest(V30, R.raw.v30_multibyte_param);
|
||||||
|
mVerifier.addPropertyNodesVerifierElem()
|
||||||
|
.addExpectedNodeWithOrder("VERSION", "3.0")
|
||||||
|
.addExpectedNodeWithOrder("N", Arrays.asList("F", "G", "M", "", ""))
|
||||||
|
.addExpectedNodeWithOrder("TEL", "1", new TypeSet("\u8D39"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiBytePropV30() {
|
||||||
|
mVerifier.initForImportTest(V30, R.raw.v30_multibyte_param);
|
||||||
|
final ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
|
||||||
|
elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
|
||||||
|
.put(StructuredName.FAMILY_NAME, "F")
|
||||||
|
.put(StructuredName.MIDDLE_NAME, "M")
|
||||||
|
.put(StructuredName.GIVEN_NAME, "G")
|
||||||
|
.put(StructuredName.DISPLAY_NAME, "G M F");
|
||||||
|
elem.addExpected(Phone.CONTENT_ITEM_TYPE)
|
||||||
|
.put(Phone.TYPE, Phone.TYPE_CUSTOM)
|
||||||
|
.put(Phone.LABEL, "\u8D39")
|
||||||
|
.put(Phone.NUMBER, "1");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,4 +82,34 @@ public class VCardUtilsTests extends TestCase {
|
|||||||
assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
|
assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testToStringAvailableAsV30ParamValue() {
|
||||||
|
// Smoke tests.
|
||||||
|
assertEquals("HOME", VCardUtils.toStringAvailableAsV30ParameValue("HOME"));
|
||||||
|
assertEquals("TEL", VCardUtils.toStringAvailableAsV30ParameValue("TEL"));
|
||||||
|
assertEquals("PAGER", VCardUtils.toStringAvailableAsV30ParameValue("PAGER"));
|
||||||
|
|
||||||
|
assertEquals("\"\"", VCardUtils.toStringAvailableAsV30ParameValue(""));
|
||||||
|
|
||||||
|
// non-Ascii must be allowed
|
||||||
|
assertEquals("\u4E8B\u52D9\u6240",
|
||||||
|
VCardUtils.toStringAvailableAsV30ParameValue("\u4E8B\u52D9\u6240"));
|
||||||
|
// Reported as bug report.
|
||||||
|
assertEquals("\u8D39", VCardUtils.toStringAvailableAsV30ParameValue("\u8D39"));
|
||||||
|
assertEquals("\"comma,separated\"",
|
||||||
|
VCardUtils.toStringAvailableAsV30ParameValue("comma,separated"));
|
||||||
|
assertEquals("\"colon:aware\"",
|
||||||
|
VCardUtils.toStringAvailableAsV30ParameValue("colon:aware"));
|
||||||
|
// CTL characters.
|
||||||
|
assertEquals("CTLExample",
|
||||||
|
VCardUtils.toStringAvailableAsV30ParameValue("CTL\u0001Example"));
|
||||||
|
// DQUOTE must be removed.
|
||||||
|
assertEquals("quoted",
|
||||||
|
VCardUtils.toStringAvailableAsV30ParameValue("\"quoted\""));
|
||||||
|
// DQUOTE must be removed basically, but we should detect a space, which
|
||||||
|
// require us to use DQUOTE again.
|
||||||
|
// Right-side has one more illegal dquote to test quote-handle code thoroughly.
|
||||||
|
assertEquals("\"Already quoted\"",
|
||||||
|
VCardUtils.toStringAvailableAsV30ParameValue("\"Already quoted\"\""));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user