diff options
author | Daisuke Miyakawa <dmiyakawa@google.com> | 2009-11-20 16:09:34 +0900 |
---|---|---|
committer | Daisuke Miyakawa <dmiyakawa@google.com> | 2009-11-20 16:13:07 +0900 |
commit | a750fdd765ec253ffa8bf3d4848d5c3a35e1979b (patch) | |
tree | e423b7aec597ea8117ea767f9ea1516663d89939 | |
parent | b439f561a6aa3900f1850e71a4aa60618af13f90 (diff) | |
download | frameworks_base-a750fdd765ec253ffa8bf3d4848d5c3a35e1979b.zip frameworks_base-a750fdd765ec253ffa8bf3d4848d5c3a35e1979b.tar.gz frameworks_base-a750fdd765ec253ffa8bf3d4848d5c3a35e1979b.tar.bz2 |
Fix a problem in which Android custom fields are not emitted correctly in non-Ascii languages.
Internal issue number: 2195990
5 files changed, 116 insertions, 59 deletions
diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java index 3980940..09ac1fd 100644 --- a/core/java/android/pim/vcard/VCardBuilder.java +++ b/core/java/android/pim/vcard/VCardBuilder.java @@ -1536,13 +1536,10 @@ public class VCardBuilder { } public void appendAndroidSpecificProperty(final String mimeType, ContentValues contentValues) { - List<String> rawValueList = new ArrayList<String>(); - rawValueList.add(mimeType); - final List<String> columnNameList; if (!sAllowedAndroidPropertySet.contains(mimeType)) { return; } - + final List<String> rawValueList = new ArrayList<String>(); for (int i = 1; i <= VCardConstants.MAX_DATA_COLUMN; i++) { String value = contentValues.getAsString("data" + i); if (value == null) { @@ -1551,8 +1548,38 @@ public class VCardBuilder { rawValueList.add(value); } - appendLineWithCharsetAndQPDetection( - VCardConstants.PROPERTY_X_ANDROID_CUSTOM, rawValueList); + boolean needCharset = + (mShouldAppendCharsetParam && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); + boolean reallyUseQuotedPrintable = + (mShouldUseQuotedPrintable && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); + mBuilder.append(VCardConstants.PROPERTY_X_ANDROID_CUSTOM); + if (needCharset) { + mBuilder.append(VCARD_PARAM_SEPARATOR); + mBuilder.append(mVCardCharsetParameter); + } + if (reallyUseQuotedPrintable) { + mBuilder.append(VCARD_PARAM_SEPARATOR); + mBuilder.append(VCARD_PARAM_ENCODING_QP); + } + mBuilder.append(VCARD_DATA_SEPARATOR); + mBuilder.append(mimeType); // Should not be encoded. + for (String rawValue : rawValueList) { + final String encodedValue; + if (reallyUseQuotedPrintable) { + encodedValue = encodeQuotedPrintable(rawValue); + } else { + // TODO: one line may be too huge, which may be invalid in vCard 3.0 + // (which says "When generating a content line, lines longer than + // 75 characters SHOULD be folded"), though several + // (even well-known) applications do not care this. + encodedValue = escapeCharacters(rawValue); + } + mBuilder.append(VCARD_ITEM_SEPARATOR); + mBuilder.append(encodedValue); + } + mBuilder.append(VCARD_END_OF_LINE); } public void appendLineWithCharsetAndQPDetection(final String propertyName, @@ -1560,7 +1587,7 @@ public class VCardBuilder { appendLineWithCharsetAndQPDetection(propertyName, null, rawValue); } - private void appendLineWithCharsetAndQPDetection( + public void appendLineWithCharsetAndQPDetection( final String propertyName, final List<String> rawValueList) { appendLineWithCharsetAndQPDetection(propertyName, null, rawValueList); } @@ -1578,22 +1605,12 @@ public class VCardBuilder { public void appendLineWithCharsetAndQPDetection(final String propertyName, final List<String> parameterList, final List<String> rawValueList) { - boolean needCharset = false; - boolean reallyUseQuotedPrintable = false; - for (String rawValue : rawValueList) { - if (!needCharset && mShouldUseQuotedPrintable && - !VCardUtils.containsOnlyPrintableAscii(rawValue)) { - needCharset = true; - } - if (!reallyUseQuotedPrintable && - !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValue)) { - reallyUseQuotedPrintable = true; - } - if (needCharset && reallyUseQuotedPrintable) { - break; - } - } - + boolean needCharset = + (mShouldAppendCharsetParam && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); + boolean reallyUseQuotedPrintable = + (mShouldUseQuotedPrintable && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); appendLine(propertyName, parameterList, rawValueList, needCharset, reallyUseQuotedPrintable); } @@ -1610,8 +1627,9 @@ public class VCardBuilder { } public void appendLine(final String propertyName, - final String rawValue, final boolean needCharset, boolean needQuotedPrintable) { - appendLine(propertyName, null, rawValue, needCharset, needQuotedPrintable); + final String rawValue, final boolean needCharset, + boolean reallyUseQuotedPrintable) { + appendLine(propertyName, null, rawValue, needCharset, reallyUseQuotedPrintable); } public void appendLine(final String propertyName, final List<String> parameterList, @@ -1620,7 +1638,8 @@ public class VCardBuilder { } public void appendLine(final String propertyName, final List<String> parameterList, - final String rawValue, final boolean needCharset, boolean needQuotedPrintable) { + final String rawValue, final boolean needCharset, + boolean reallyUseQuotedPrintable) { mBuilder.append(propertyName); if (parameterList != null && parameterList.size() > 0) { mBuilder.append(VCARD_PARAM_SEPARATOR); @@ -1632,7 +1651,7 @@ public class VCardBuilder { } final String encodedValue; - if (needQuotedPrintable) { + if (reallyUseQuotedPrintable) { mBuilder.append(VCARD_PARAM_SEPARATOR); mBuilder.append(VCARD_PARAM_ENCODING_QP); encodedValue = encodeQuotedPrintable(rawValue); @@ -1664,14 +1683,16 @@ public class VCardBuilder { mBuilder.append(VCARD_PARAM_SEPARATOR); mBuilder.append(mVCardCharsetParameter); } + if (needQuotedPrintable) { + mBuilder.append(VCARD_PARAM_SEPARATOR); + mBuilder.append(VCARD_PARAM_ENCODING_QP); + } mBuilder.append(VCARD_DATA_SEPARATOR); boolean first = true; for (String rawValue : rawValueList) { final String encodedValue; if (needQuotedPrintable) { - mBuilder.append(VCARD_PARAM_SEPARATOR); - mBuilder.append(VCARD_PARAM_ENCODING_QP); encodedValue = encodeQuotedPrintable(rawValue); } else { // TODO: one line may be too huge, which may be invalid in vCard 3.0 diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java index ec569d4..e7c19cf 100644 --- a/core/java/android/pim/vcard/VCardParser_V21.java +++ b/core/java/android/pim/vcard/VCardParser_V21.java @@ -117,9 +117,6 @@ public class VCardParser_V21 extends VCardParser { this(detector.getEstimatedType()); } - /** - * TODO: Merge detector and parser mode. - */ public VCardParser_V21(int parseType) { super(parseType); if (parseType == VCardConfig.PARSE_TYPE_FOMA) { diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java index 80457bb..ec75a98 100644 --- a/core/java/android/pim/vcard/VCardUtils.java +++ b/core/java/android/pim/vcard/VCardUtils.java @@ -352,6 +352,13 @@ public class VCardUtils { if (values == null) { return true; } + return containsOnlyPrintableAscii(Arrays.asList(values)); + } + + public static boolean containsOnlyPrintableAscii(final Collection<String> values) { + if (values == null) { + return true; + } final int asciiFirst = 0x20; final int asciiLast = 0x7E; // included for (final String value : values) { @@ -378,6 +385,13 @@ public class VCardUtils { if (values == null) { return true; } + return containsOnlyNonCrLfPrintableAscii(Arrays.asList(values)); + } + + public static boolean containsOnlyNonCrLfPrintableAscii(final Collection<String> values) { + if (values == null) { + return true; + } final int asciiFirst = 0x20; final int asciiLast = 0x7E; // included for (final String value : values) { @@ -399,32 +413,6 @@ public class VCardUtils { new HashSet<Character>(Arrays.asList('[', ']', '=', ':', '.', ',', ' ')); /** - * <P> - * Returns true when the given String is categorized as "word" specified in vCard spec 2.1. - * </P> - * <P> - * vCard 2.1 specifies:<BR /> - * word = <any printable 7bit us-ascii except []=:., > - * </P> - */ - public static boolean isV21Word(final String value) { - if (TextUtils.isEmpty(value)) { - return true; - } - final int asciiFirst = 0x20; - final int asciiLast = 0x7E; // included - final int length = value.length(); - for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) { - final int c = value.codePointAt(i); - if (!(asciiFirst <= c && c <= asciiLast) || - sUnAcceptableAsciiInV21WordSet.contains((char)c)) { - return false; - } - } - return true; - } - - /** * This is useful since vCard 3.0 often requires the ("X-") properties and groups * should contain only alphabets, digits, and hyphen. * @@ -437,6 +425,13 @@ public class VCardUtils { if (values == null) { return true; } + return containsOnlyAlphaDigitHyphen(Arrays.asList(values)); + } + + public static boolean containsOnlyAlphaDigitHyphen(final Collection<String> values) { + if (values == null) { + return true; + } final int upperAlphabetFirst = 0x41; // A final int upperAlphabetAfterLast = 0x5b; // [ final int lowerAlphabetFirst = 0x61; // a @@ -461,7 +456,33 @@ public class VCardUtils { } return true; } - + + /** + * <P> + * Returns true when the given String is categorized as "word" specified in vCard spec 2.1. + * </P> + * <P> + * vCard 2.1 specifies:<BR /> + * word = <any printable 7bit us-ascii except []=:., > + * </P> + */ + public static boolean isV21Word(final String value) { + if (TextUtils.isEmpty(value)) { + return true; + } + final int asciiFirst = 0x20; + final int asciiLast = 0x7E; // included + final int length = value.length(); + for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) { + final int c = value.codePointAt(i); + if (!(asciiFirst <= c && c <= asciiLast) || + sUnAcceptableAsciiInV21WordSet.contains((char)c)) { + return false; + } + } + return true; + } + public static String toHalfWidthString(final String orgString) { if (TextUtils.isEmpty(orgString)) { return null; diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java index 967c22d..eea98c6 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java @@ -18,6 +18,7 @@ package com.android.unit_tests.vcard; import android.content.ContentValues; import android.pim.vcard.VCardConfig; +import android.provider.ContactsContract.CommonDataKinds.Nickname; import android.provider.ContactsContract.CommonDataKinds.Note; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.CommonDataKinds.StructuredName; @@ -418,4 +419,16 @@ public class VCardJapanizationTests extends VCardTestsBase { .addExpectedNode("ADR", "", new TypeSet("HOME")) .addExpectedNode("NOTE", "note1\nnote2\nnote3", mContentValuesForQP); } + + public void testAndroidCustomV21() { + mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8); + mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE) + .put(Nickname.NAME, "\u304D\u3083\u30FC\u30A8\u30C3\u30C1\u30FC"); + mVerifier.addPropertyNodesVerifierElemWithEmptyName() + .addExpectedNode("X-ANDROID-CUSTOM", + Arrays.asList(Nickname.CONTENT_ITEM_TYPE, + "\u304D\u3083\u30FC\u30A8\u30C3\u30C1\u30FC", + "", "", "", "", "", "", "", "", "", "", "", "", "", ""), + mContentValuesForQPAndUtf8); + } } diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardUtilsTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardUtilsTests.java index 592c285..9f173af 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardUtilsTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardUtilsTests.java @@ -20,10 +20,13 @@ import android.pim.vcard.VCardUtils; import junit.framework.TestCase; +import java.util.List; + public class VCardUtilsTests extends TestCase { public void testContainsOnlyPrintableAscii() { assertTrue(VCardUtils.containsOnlyPrintableAscii((String)null)); assertTrue(VCardUtils.containsOnlyPrintableAscii((String[])null)); + assertTrue(VCardUtils.containsOnlyPrintableAscii((List<String>)null)); assertTrue(VCardUtils.containsOnlyPrintableAscii("")); assertTrue(VCardUtils.containsOnlyPrintableAscii("abcdefghijklmnopqrstuvwxyz")); assertTrue(VCardUtils.containsOnlyPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); @@ -40,6 +43,7 @@ public class VCardUtilsTests extends TestCase { public void testContainsOnlyNonCrLfPrintableAscii() { assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String)null)); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String[])null)); + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((List<String>)null)); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("")); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz")); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); @@ -57,6 +61,7 @@ public class VCardUtilsTests extends TestCase { public void testContainsOnlyAlphaDigitHyphen() { assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String)null)); assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String[])null)); + assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((List<String>)null)); assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen("")); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz")); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); |