From c4b51712d89e9fb742b598911e611c80ad51de82 Mon Sep 17 00:00:00 2001 From: Daisuke Miyakawa Date: Thu, 19 Nov 2009 09:00:12 +0900 Subject: [PATCH] Modify vCard exporter code so that it does not emit non-Ascii type. Also add unit tests. Internal issue number: 2195990 --- .../java/android/pim/vcard/JapaneseUtils.java | 2 +- core/java/android/pim/vcard/VCardBuilder.java | 150 +++++++++------ core/java/android/pim/vcard/VCardUtils.java | 173 +++++++++--------- .../vcard/PropertyNodesVerifier.java | 27 ++- .../unit_tests/vcard/VCardExporterTests.java | 26 +-- .../vcard/VCardJapanizationTests.java | 47 ++++- .../unit_tests/vcard/VCardUtilsTests.java | 9 +- 7 files changed, 264 insertions(+), 170 deletions(-) diff --git a/core/java/android/pim/vcard/JapaneseUtils.java b/core/java/android/pim/vcard/JapaneseUtils.java index b596e868adc29..875c29ef1b11e 100644 --- a/core/java/android/pim/vcard/JapaneseUtils.java +++ b/core/java/android/pim/vcard/JapaneseUtils.java @@ -370,7 +370,7 @@ import java.util.Map; * @param ch input character * @return CharSequence object if the mapping for ch exists. Return null otherwise. */ - public static CharSequence tryGetHalfWidthText(char ch) { + public static String tryGetHalfWidthText(char ch) { if (sHalfWidthMap.containsKey(ch)) { return sHalfWidthMap.get(ch); } else { diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java index 51701c6f50268..408d0ce548581 100644 --- a/core/java/android/pim/vcard/VCardBuilder.java +++ b/core/java/android/pim/vcard/VCardBuilder.java @@ -835,66 +835,90 @@ public class VCardBuilder { * @return null when there's no information available to construct the data. */ private PostalStruct tryConstructPostalStruct(ContentValues contentValues) { - boolean reallyUseQuotedPrintable = false; - boolean appendCharset = false; - - boolean dataArrayExists = false; - String[] dataArray = VCardUtils.getVCardPostalElements(contentValues); - for (String data : dataArray) { - if (!TextUtils.isEmpty(data)) { - dataArrayExists = true; - if (!appendCharset && !VCardUtils.containsOnlyPrintableAscii(data)) { - appendCharset = true; - } - if (mShouldUseQuotedPrintable && - !VCardUtils.containsOnlyNonCrLfPrintableAscii(data)) { - reallyUseQuotedPrintable = true; - break; - } - } - } - - if (dataArrayExists) { - StringBuffer addressBuffer = new StringBuffer(); - boolean first = true; - for (String data : dataArray) { - if (first) { - first = false; - } else { - addressBuffer.append(VCARD_ITEM_SEPARATOR); - } - if (!TextUtils.isEmpty(data)) { - if (reallyUseQuotedPrintable) { - addressBuffer.append(encodeQuotedPrintable(data)); - } else { - addressBuffer.append(escapeCharacters(data)); - } - } - } - return new PostalStruct(reallyUseQuotedPrintable, appendCharset, - addressBuffer.toString()); - } - - String formattedAddress = - contentValues.getAsString(StructuredPostal.FORMATTED_ADDRESS); - if (!TextUtils.isEmpty(formattedAddress)) { - reallyUseQuotedPrintable = - !VCardUtils.containsOnlyPrintableAscii(formattedAddress); - appendCharset = - !VCardUtils.containsOnlyNonCrLfPrintableAscii(formattedAddress); + // adr-value = 0*6(text-value ";") text-value + // ; PO Box, Extended Address, Street, Locality, Region, Postal + // ; Code, Country Name + final String rawPoBox = contentValues.getAsString(StructuredPostal.POBOX); + final String rawExtendedAddress = contentValues.getAsString(StructuredPostal.NEIGHBORHOOD); + final String rawStreet = contentValues.getAsString(StructuredPostal.STREET); + final String rawLocality = contentValues.getAsString(StructuredPostal.CITY); + final String rawRegion = contentValues.getAsString(StructuredPostal.REGION); + final String rawPostalCode = contentValues.getAsString(StructuredPostal.POSTCODE); + final String rawCountry = contentValues.getAsString(StructuredPostal.COUNTRY); + final String[] rawAddressArray = new String[]{ + rawPoBox, rawExtendedAddress, rawStreet, rawLocality, + rawRegion, rawPostalCode, rawCountry}; + if (!VCardUtils.areAllEmpty(rawAddressArray)) { + final boolean reallyUseQuotedPrintable = + (mShouldUseQuotedPrintable && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawAddressArray)); + final boolean appendCharset = + !VCardUtils.containsOnlyPrintableAscii(rawAddressArray); + final String encodedPoBox; + final String encodedExtendedAddress; + final String encodedStreet; + final String encodedLocality; + final String encodedRegion; + final String encodedPostalCode; + final String encodedCountry; if (reallyUseQuotedPrintable) { - formattedAddress = encodeQuotedPrintable(formattedAddress); + encodedPoBox = encodeQuotedPrintable(rawPoBox); + encodedExtendedAddress = encodeQuotedPrintable(rawExtendedAddress); + encodedStreet = encodeQuotedPrintable(rawStreet); + encodedLocality = encodeQuotedPrintable(rawLocality); + encodedRegion = encodeQuotedPrintable(rawRegion); + encodedPostalCode = encodeQuotedPrintable(rawPostalCode); + encodedCountry = encodeQuotedPrintable(rawCountry); } else { - formattedAddress = escapeCharacters(formattedAddress); + encodedPoBox = escapeCharacters(rawPoBox); + encodedExtendedAddress = escapeCharacters(rawExtendedAddress); + encodedStreet = escapeCharacters(rawStreet); + encodedLocality = escapeCharacters(rawLocality); + encodedRegion = escapeCharacters(rawRegion); + encodedPostalCode = escapeCharacters(rawPostalCode); + encodedCountry = escapeCharacters(rawCountry); } - // We use the second value ("Extended Address"). - // - // adr-value = 0*6(text-value ";") text-value - // ; PO Box, Extended Address, Street, Locality, Region, Postal - // ; Code, Country Name - StringBuffer addressBuffer = new StringBuffer(); + final StringBuffer addressBuffer = new StringBuffer(); + addressBuffer.append(encodedPoBox); addressBuffer.append(VCARD_ITEM_SEPARATOR); - addressBuffer.append(formattedAddress); + addressBuffer.append(encodedExtendedAddress); + addressBuffer.append(VCARD_ITEM_SEPARATOR); + addressBuffer.append(encodedStreet); + addressBuffer.append(VCARD_ITEM_SEPARATOR); + addressBuffer.append(encodedLocality); + addressBuffer.append(VCARD_ITEM_SEPARATOR); + addressBuffer.append(encodedRegion); + addressBuffer.append(VCARD_ITEM_SEPARATOR); + addressBuffer.append(encodedPostalCode); + addressBuffer.append(VCARD_ITEM_SEPARATOR); + addressBuffer.append(encodedCountry); + return new PostalStruct( + reallyUseQuotedPrintable, appendCharset, addressBuffer.toString()); + } else { // VCardUtils.areAllEmpty(rawAddressArray) == true + // Try to use FORMATTED_ADDRESS instead. + final String rawFormattedAddress = + contentValues.getAsString(StructuredPostal.FORMATTED_ADDRESS); + if (TextUtils.isEmpty(rawFormattedAddress)) { + return null; + } + final boolean reallyUseQuotedPrintable = + (mShouldUseQuotedPrintable && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawFormattedAddress)); + final boolean appendCharset = + !VCardUtils.containsOnlyPrintableAscii(rawFormattedAddress); + final String encodedFormattedAddress; + if (reallyUseQuotedPrintable) { + encodedFormattedAddress = encodeQuotedPrintable(rawFormattedAddress); + } else { + encodedFormattedAddress = escapeCharacters(rawFormattedAddress); + } + + // We use the second value ("Extended Address") just because Japanese mobile phones + // do so. If the other importer expects the value be in the other field, some flag may + // be needed. + final StringBuffer addressBuffer = new StringBuffer(); + addressBuffer.append(VCARD_ITEM_SEPARATOR); + addressBuffer.append(encodedFormattedAddress); addressBuffer.append(VCARD_ITEM_SEPARATOR); addressBuffer.append(VCARD_ITEM_SEPARATOR); addressBuffer.append(VCARD_ITEM_SEPARATOR); @@ -903,7 +927,6 @@ public class VCardBuilder { return new PostalStruct( reallyUseQuotedPrintable, appendCharset, addressBuffer.toString()); } - return null; // There's no data available. } public VCardBuilder appendIms(final List contentValuesList) { @@ -1653,13 +1676,22 @@ public class VCardBuilder { // We may have to make this comma separated form like "TYPE=DOM,WORK" in the future, // which would be recommended way in vcard 3.0 though not valid in vCard 2.1. boolean first = true; - for (String type : types) { + for (final String typeValue : types) { + // Note: vCard 3.0 specifies the different type of acceptable type Strings, but + // 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.) + if (!VCardUtils.isV21Word(typeValue)) { + continue; + } if (first) { first = false; } else { mBuilder.append(VCARD_PARAM_SEPARATOR); } - appendTypeParameter(type); + appendTypeParameter(typeValue); } } diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java index 8404da02f7697..885f7ba7e3694 100644 --- a/core/java/android/pim/vcard/VCardUtils.java +++ b/core/java/android/pim/vcard/VCardUtils.java @@ -16,14 +16,12 @@ package android.pim.vcard; import android.content.ContentProviderOperation; -import android.content.ContentValues; import android.provider.ContactsContract.Data; import android.provider.ContactsContract.CommonDataKinds.Im; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; -import android.util.Log; import java.util.ArrayList; import java.util.Arrays; @@ -245,8 +243,7 @@ public class VCardUtils { * Inserts postal data into the builder object. * * Note that the data structure of ContactsContract is different from that defined in vCard. - * So some conversion may be performed in this method. See also - * {{@link #getVCardPostalElements(ContentValues)} + * So some conversion may be performed in this method. */ public static void insertStructuredPostalDataUsingContactsStruct(int vcardType, final ContentProviderOperation.Builder builder, @@ -260,9 +257,6 @@ public class VCardUtils { } builder.withValue(StructuredPostal.POBOX, postalData.pobox); - // TODO: Japanese phone seems to use this field for expressing all the address including - // region, city, etc. Not sure we're ok to store them into NEIGHBORHOOD, while it would be - // better than dropping them all. builder.withValue(StructuredPostal.NEIGHBORHOOD, postalData.extendedAddress); builder.withValue(StructuredPostal.STREET, postalData.street); builder.withValue(StructuredPostal.CITY, postalData.localty); @@ -277,59 +271,6 @@ public class VCardUtils { } } - /** - * Returns String[] containing address information based on vCard spec - * (PO Box, Extended Address, Street, Locality, Region, Postal Code, Country Name). - * All String objects are non-null ("" is used when the relevant data is empty). - * - * Note that the data structure of ContactsContract is different from that defined in vCard. - * So some conversion may be performed in this method. See also - * {{@link #insertStructuredPostalDataUsingContactsStruct(int, - * android.content.ContentProviderOperation.Builder, - * android.pim.vcard.VCardEntry.PostalData)} - */ - public static String[] getVCardPostalElements(ContentValues contentValues) { - // adr-value = 0*6(text-value ";") text-value - // ; PO Box, Extended Address, Street, Locality, Region, Postal - // ; Code, Country Name - String[] dataArray = new String[7]; - dataArray[0] = contentValues.getAsString(StructuredPostal.POBOX); - if (dataArray[0] == null) { - dataArray[0] = ""; - } - // We keep all the data in StructuredPostal, presuming NEIGHBORHOOD is - // similar to "Extended Address". - dataArray[1] = contentValues.getAsString(StructuredPostal.NEIGHBORHOOD); - if (dataArray[1] == null) { - dataArray[1] = ""; - } - dataArray[2] = contentValues.getAsString(StructuredPostal.STREET); - if (dataArray[2] == null) { - dataArray[2] = ""; - } - // Assume that localty == city - dataArray[3] = contentValues.getAsString(StructuredPostal.CITY); - if (dataArray[3] == null) { - dataArray[3] = ""; - } - String region = contentValues.getAsString(StructuredPostal.REGION); - if (!TextUtils.isEmpty(region)) { - dataArray[4] = region; - } else { - dataArray[4] = ""; - } - dataArray[5] = contentValues.getAsString(StructuredPostal.POSTCODE); - if (dataArray[5] == null) { - dataArray[5] = ""; - } - dataArray[6] = contentValues.getAsString(StructuredPostal.COUNTRY); - if (dataArray[6] == null) { - dataArray[6] = ""; - } - - return dataArray; - } - public static String constructNameFromElements(final int vcardType, final String familyName, final String middleName, final String givenName) { return constructNameFromElements(vcardType, familyName, middleName, givenName, @@ -394,18 +335,22 @@ public class VCardUtils { return list; } - public static boolean containsOnlyPrintableAscii(String str) { - if (TextUtils.isEmpty(str)) { + public static boolean containsOnlyPrintableAscii(final String...values) { + if (values == null) { return true; } - - final int length = str.length(); final int asciiFirst = 0x20; final int asciiLast = 0x7E; // included - for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) { - final int c = str.codePointAt(i); - if (!((asciiFirst <= c && c <= asciiLast) || c == '\r' || c == '\n')) { - return false; + for (final String value : values) { + if (TextUtils.isEmpty(value)) { + continue; + } + 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) || c == '\r' || c == '\n')) { + return false; + } } } return true; @@ -416,17 +361,50 @@ public class VCardUtils { * or not, which is required by vCard 2.1. * See the definition of "7bit" in vCard 2.1 spec for more information. */ - public static boolean containsOnlyNonCrLfPrintableAscii(String str) { - if (TextUtils.isEmpty(str)) { + public static boolean containsOnlyNonCrLfPrintableAscii(final String...values) { + if (values == null) { return true; } - - final int length = str.length(); final int asciiFirst = 0x20; final int asciiLast = 0x7E; // included - for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) { - final int c = str.codePointAt(i); - if (!(asciiFirst <= c && c <= asciiLast)) { + for (final String value : values) { + if (TextUtils.isEmpty(value)) { + continue; + } + 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)) { + return false; + } + } + } + return true; + } + + private static final Set sUnAcceptableAsciiInV21WordSet = + new HashSet(Arrays.asList('[', ']', '=', ':', '.', ',', ' ')); + + /** + *

+ * Returns true when the given String is categorized as "word" specified in vCard spec 2.1. + *

+ *

+ * vCard 2.1 specifies:
+ * word = <any printable 7bit us-ascii except []=:., > + *

+ */ + 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; } } @@ -442,11 +420,10 @@ public class VCardUtils { * such kind of input but must never output it unless the target is very specific * to the device which is able to parse the malformed input. */ - public static boolean containsOnlyAlphaDigitHyphen(String str) { - if (TextUtils.isEmpty(str)) { + public static boolean containsOnlyAlphaDigitHyphen(final String...values) { + if (values == null) { return true; } - final int upperAlphabetFirst = 0x41; // A final int upperAlphabetAfterLast = 0x5b; // [ final int lowerAlphabetFirst = 0x61; // a @@ -454,30 +431,35 @@ public class VCardUtils { final int digitFirst = 0x30; // 0 final int digitAfterLast = 0x3A; // : final int hyphen = '-'; - final int length = str.length(); - for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) { - int codepoint = str.codePointAt(i); - if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetAfterLast) || + for (final String str : values) { + if (TextUtils.isEmpty(str)) { + continue; + } + final int length = str.length(); + for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) { + int codepoint = str.codePointAt(i); + if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetAfterLast) || (upperAlphabetFirst <= codepoint && codepoint < upperAlphabetAfterLast) || (digitFirst <= codepoint && codepoint < digitAfterLast) || (codepoint == hyphen))) { - return false; + return false; + } } } return true; } - public static String toHalfWidthString(String orgString) { + public static String toHalfWidthString(final String orgString) { if (TextUtils.isEmpty(orgString)) { return null; } final StringBuilder builder = new StringBuilder(); final int length = orgString.length(); - for (int i = 0; i < length; i++) { + for (int i = 0; i < length; i = orgString.offsetByCodePoints(i, 1)) { // All Japanese character is able to be expressed by char. // Do not need to use String#codepPointAt(). final char ch = orgString.charAt(i); - CharSequence halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch); + final String halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch); if (halfWidthText != null) { builder.append(halfWidthText); } else { @@ -495,6 +477,9 @@ public class VCardUtils { * @return The image type or null when the type cannot be determined. */ public static String guessImageType(final byte[] input) { + if (input == null) { + return null; + } if (input.length >= 3 && input[0] == 'G' && input[1] == 'I' && input[2] == 'F') { return "GIF"; } else if (input.length >= 4 && input[0] == (byte) 0x89 @@ -511,6 +496,22 @@ public class VCardUtils { } } + /** + * @return True when all the given values are null or empty Strings. + */ + public static boolean areAllEmpty(final String...values) { + if (values == null) { + return true; + } + + for (final String value : values) { + if (!TextUtils.isEmpty(value)) { + return false; + } + } + return true; + } + private VCardUtils() { } } diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java index 4eb47c02001b3..190a3551bd752 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java @@ -139,6 +139,12 @@ class PropertyNodesVerifierElem { return addNodeWithOrder(propName, propValue, null, null, contentValues, null, null); } + public PropertyNodesVerifierElem addNodeWithOrder(String propName, + List propValueList, ContentValues contentValues) { + return addNodeWithOrder(propName, null, propValueList, + null, contentValues, null, null); + } + public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue, List propValueList) { return addNodeWithOrder(propName, propValue, propValueList, null, null, null, null); @@ -157,8 +163,7 @@ class PropertyNodesVerifierElem { public PropertyNodesVerifierElem addNodeWithOrder(String propName, List propValueList, TypeSet paramMap_TYPE) { - final String propValue = concatinateListWithSemiColon(propValueList); - return addNodeWithOrder(propName, propValue, propValueList, null, null, + return addNodeWithOrder(propName, null, propValueList, null, null, paramMap_TYPE, null); } @@ -177,6 +182,9 @@ class PropertyNodesVerifierElem { public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue, List propValueList, byte[] propValue_bytes, ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) { + if (propValue == null && propValueList != null) { + propValue = concatinateListWithSemiColon(propValueList); + } PropertyNode propertyNode = new PropertyNode(propName, propValue, propValueList, propValue_bytes, paramMap, paramMap_TYPE, propGroupSet); @@ -200,14 +208,20 @@ class PropertyNodesVerifierElem { return addNodeWithoutOrder(propName, propValue, null, null, contentValues, null, null); } + public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, + List propValueList, ContentValues contentValues) { + return addNodeWithoutOrder(propName, null, + propValueList, null, contentValues, null, null); + } + public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue, List propValueList) { return addNodeWithoutOrder(propName, propValue, propValueList, null, null, null, null); } - public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, List propValueList) { - final String propValue = concatinateListWithSemiColon(propValueList); - return addNodeWithoutOrder(propName, propValue, propValueList, + public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, + List propValueList) { + return addNodeWithoutOrder(propName, null, propValueList, null, null, null, null); } @@ -238,6 +252,9 @@ class PropertyNodesVerifierElem { public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue, List propValueList, byte[] propValue_bytes, ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) { + if (propValue == null && propValueList != null) { + propValue = concatinateListWithSemiColon(propValueList); + } mUnorderedNodeList.add(new PropertyNode(propName, propValue, propValueList, propValue_bytes, paramMap, paramMap_TYPE, propGroupSet)); return this; diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java index a1db05121a814..616d451325dd9 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java @@ -546,12 +546,9 @@ public class VCardExporterTests extends VCardTestsBase { testEmailPrefHandlingCommon(V30); } - private void testPostalOnlyWithStructuredDataCommon(int vcardType) { + private void testPostalAddressCommon(int vcardType) { VCardVerifier verifier = new VCardVerifier(vcardType); ContactEntry entry = verifier.addInputEntry(); - // adr-value = 0*6(text-value ";") text-value - // ; PO Box, Extended Address, Street, Locality, Region, Postal Code, - // ; Country Name entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE) .put(StructuredPostal.POBOX, "Pobox") .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood") @@ -559,27 +556,33 @@ public class VCardExporterTests extends VCardTestsBase { .put(StructuredPostal.CITY, "City") .put(StructuredPostal.REGION, "Region") .put(StructuredPostal.POSTCODE, "100") - .put(StructuredPostal.COUNTRY, "Country"); + .put(StructuredPostal.COUNTRY, "Country") + .put(StructuredPostal.FORMATTED_ADDRESS, "Formatted Address") + .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK); + // adr-value = 0*6(text-value ";") text-value + // ; PO Box, Extended Address, Street, Locality, Region, Postal Code, + // ; Country Name verifier.addPropertyNodesVerifierElemWithEmptyName() - .addNodeWithoutOrder("ADR", "Pobox;Neighborhood;Street;City;Region;100;Country", + .addNodeWithoutOrder("ADR", Arrays.asList("Pobox", "Neighborhood", "Street", "City", - "Region", "100", "Country"), new TypeSet("HOME")); + "Region", "100", "Country"), new TypeSet("WORK")); verifier.verify(); } - public void testPostalOnlyWithStructuredDataV21() { - testPostalOnlyWithStructuredDataCommon(V21); + public void testPostalAddressV21() { + testPostalAddressCommon(V21); } - public void testPostalOnlyWithStructuredDataV30() { - testPostalOnlyWithStructuredDataCommon(V30); + public void testPostalAddressV30() { + testPostalAddressCommon(V30); } private void testPostalOnlyWithFormattedAddressCommon(int vcardType) { VCardVerifier verifier = new VCardVerifier(vcardType); ContactEntry entry = verifier.addInputEntry(); entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE) + .put(StructuredPostal.REGION, "") // Must be ignored. .put(StructuredPostal.FORMATTED_ADDRESS, "Formatted address CA 123-334 United Statue"); @@ -587,7 +590,6 @@ public class VCardExporterTests extends VCardTestsBase { .addNodeWithOrder("ADR", ";Formatted address CA 123-334 United Statue;;;;;", Arrays.asList("", "Formatted address CA 123-334 United Statue", "", "", "", "", ""), new TypeSet("HOME")); - verifier.verify(); } 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 052286753b77b..dd20ec6868278 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java @@ -205,11 +205,50 @@ public class VCardJapanizationTests extends VCardTestsBase { verifier.verify(); } + private void testPostalAddressWithJapaneseCommon(int vcardType) { + VCardVerifier verifier = new VCardVerifier(vcardType); + ContactEntry entry = verifier.addInputEntry(); + entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE) + .put(StructuredPostal.POBOX, "\u79C1\u66F8\u7BB107") + .put(StructuredPostal.NEIGHBORHOOD, + "\u30A2\u30D1\u30FC\u30C8\u0020\u0033\u0034\u53F7\u5BA4") + .put(StructuredPostal.STREET, "\u96DB\u898B\u6CA2\u6751") + .put(StructuredPostal.CITY, "\u9E7F\u9AA8\u5E02") + .put(StructuredPostal.REGION, "\u00D7\u00D7\u770C") + .put(StructuredPostal.POSTCODE, "494-1313") + .put(StructuredPostal.COUNTRY, "\u65E5\u672C") + .put(StructuredPostal.FORMATTED_ADDRESS, + "\u3053\u3093\u306A\u3068\u3053\u308D\u3092\u898B" + + "\u308B\u306A\u3093\u3066\u6687\u4EBA\u3067\u3059\u304B\uFF1F") + .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM) + .put(StructuredPostal.LABEL, "\u304A\u3082\u3061\u304B\u3048\u308A"); + + ContentValues contentValues = (VCardConfig.usesShiftJis(vcardType) ? + (VCardConfig.isV30(vcardType) ? mContentValuesForSJis : + mContentValuesForQPAndSJis) : + (VCardConfig.isV30(vcardType) ? mContentValuesForUtf8 : + mContentValuesForQPAndUtf8)); + + PropertyNodesVerifierElem elem = verifier.addPropertyNodesVerifierElemWithEmptyName(); + // LABEL must be ignored in vCard 2.1. As for vCard 3.0, the current behavior is + // same as that in vCard 3.0, which can be changed in the future. + elem.addNodeWithoutOrder("ADR", Arrays.asList("\u79C1\u66F8\u7BB107", + "\u30A2\u30D1\u30FC\u30C8\u0020\u0033\u0034\u53F7\u5BA4", + "\u96DB\u898B\u6CA2\u6751", "\u9E7F\u9AA8\u5E02", "\u00D7\u00D7\u770C", + "494-1313", "\u65E5\u672C"), + contentValues); + verifier.verify(); + } + + public void testPostalAddresswithJapaneseV21() { + testPostalAddressWithJapaneseCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS); + } + /** * Verifies that only one address field is emitted toward DoCoMo phones. * Prefered type must (should?) be: HOME > WORK > OTHER > CUSTOM */ - public void testAdrressFieldEmittionForDoCoMo_1() { + public void testPostalAdrressForDoCoMo_1() { VCardVerifier verifier = new VCardVerifier(VCardConfig.VCARD_TYPE_DOCOMO); ContactEntry entry = verifier.addInputEntry(); entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE) @@ -238,7 +277,7 @@ public class VCardJapanizationTests extends VCardTestsBase { verifier.verify(); } - public void testAdrressFieldEmittionForDoCoMo_2() { + public void testPostalAdrressForDoCoMo_2() { VCardVerifier verifier = new VCardVerifier(VCardConfig.VCARD_TYPE_DOCOMO); ContactEntry entry = verifier.addInputEntry(); entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE) @@ -264,7 +303,7 @@ public class VCardJapanizationTests extends VCardTestsBase { verifier.verify(); } - public void testAdrressFieldEmittionForDoCoMo_3() { + public void testPostalAdrressForDoCoMo_3() { VCardVerifier verifier = new VCardVerifier(VCardConfig.VCARD_TYPE_DOCOMO); ContactEntry entry = verifier.addInputEntry(); entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE) @@ -293,7 +332,7 @@ public class VCardJapanizationTests extends VCardTestsBase { /** * Verifies the vCard exporter tolerates null TYPE. */ - public void testAdrressFieldEmittionForDoCoMo_4() { + public void testPostalAdrressForDoCoMo_4() { VCardVerifier verifier = new VCardVerifier(VCardConfig.VCARD_TYPE_DOCOMO); ContactEntry entry = verifier.addInputEntry(); entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE) 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 6202bdba29347..592c28596b55c 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardUtilsTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardUtilsTests.java @@ -22,7 +22,8 @@ import junit.framework.TestCase; public class VCardUtilsTests extends TestCase { public void testContainsOnlyPrintableAscii() { - assertTrue(VCardUtils.containsOnlyPrintableAscii(null)); + assertTrue(VCardUtils.containsOnlyPrintableAscii((String)null)); + assertTrue(VCardUtils.containsOnlyPrintableAscii((String[])null)); assertTrue(VCardUtils.containsOnlyPrintableAscii("")); assertTrue(VCardUtils.containsOnlyPrintableAscii("abcdefghijklmnopqrstuvwxyz")); assertTrue(VCardUtils.containsOnlyPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); @@ -37,7 +38,8 @@ public class VCardUtilsTests extends TestCase { } public void testContainsOnlyNonCrLfPrintableAscii() { - assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(null)); + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String)null)); + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String[])null)); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("")); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz")); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); @@ -53,7 +55,8 @@ public class VCardUtilsTests extends TestCase { } public void testContainsOnlyAlphaDigitHyphen() { - assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen(null)); + assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String)null)); + assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String[])null)); assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen("")); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz")); assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));