am 5e332efd: Merge change I903ce7b1 into eclair-mr2

Merge commit '5e332efd56ffc8bcc6c40b214aca66bec21648b7' into eclair-mr2-plus-aosp

* commit '5e332efd56ffc8bcc6c40b214aca66bec21648b7':
  Fix a problem in which Android custom fields are not emitted correctly in non-Ascii languages.
This commit is contained in:
Daisuke Miyakawa
2009-11-19 23:19:32 -08:00
committed by Android Git Automerger
5 changed files with 116 additions and 59 deletions

View File

@ -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

View File

@ -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) {

View File

@ -349,6 +349,13 @@ public class VCardUtils {
}
public static boolean containsOnlyPrintableAscii(final String...values) {
if (values == null) {
return true;
}
return containsOnlyPrintableAscii(Arrays.asList(values));
}
public static boolean containsOnlyPrintableAscii(final Collection<String> values) {
if (values == null) {
return true;
}
@ -375,6 +382,13 @@ public class VCardUtils {
* See the definition of "7bit" in vCard 2.1 spec for more information.
*/
public static boolean containsOnlyNonCrLfPrintableAscii(final String...values) {
if (values == null) {
return true;
}
return containsOnlyNonCrLfPrintableAscii(Arrays.asList(values));
}
public static boolean containsOnlyNonCrLfPrintableAscii(final Collection<String> values) {
if (values == null) {
return true;
}
@ -398,32 +412,6 @@ public class VCardUtils {
private static final Set<Character> sUnAcceptableAsciiInV21WordSet =
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.
@ -434,6 +422,13 @@ public class VCardUtils {
* to the device which is able to parse the malformed input.
*/
public static boolean containsOnlyAlphaDigitHyphen(final String...values) {
if (values == null) {
return true;
}
return containsOnlyAlphaDigitHyphen(Arrays.asList(values));
}
public static boolean containsOnlyAlphaDigitHyphen(final Collection<String> values) {
if (values == null) {
return true;
}
@ -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;

View File

@ -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);
}
}

View File

@ -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"));