summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaisuke Miyakawa <dmiyakawa@google.com>2009-11-20 16:09:34 +0900
committerDaisuke Miyakawa <dmiyakawa@google.com>2009-11-20 16:13:07 +0900
commita750fdd765ec253ffa8bf3d4848d5c3a35e1979b (patch)
treee423b7aec597ea8117ea767f9ea1516663d89939
parentb439f561a6aa3900f1850e71a4aa60618af13f90 (diff)
downloadframeworks_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
-rw-r--r--core/java/android/pim/vcard/VCardBuilder.java79
-rw-r--r--core/java/android/pim/vcard/VCardParser_V21.java3
-rw-r--r--core/java/android/pim/vcard/VCardUtils.java75
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java13
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/VCardUtilsTests.java5
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 = &lt;any printable 7bit us-ascii except []=:., &gt;
- * </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 = &lt;any printable 7bit us-ascii except []=:., &gt;
+ * </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"));