am ddd017f8: Merge change I8daabf26 into eclair-mr2

Merge commit 'ddd017f872bee40450c0e73dcf6608a9fdc49a05' into eclair-mr2-plus-aosp

* commit 'ddd017f872bee40450c0e73dcf6608a9fdc49a05':
  Modify vCard exporter code so that it does not emit non-Ascii type.
diff --git a/core/java/android/pim/vcard/JapaneseUtils.java b/core/java/android/pim/vcard/JapaneseUtils.java
index b596e86..875c29e 100644
--- a/core/java/android/pim/vcard/JapaneseUtils.java
+++ b/core/java/android/pim/vcard/JapaneseUtils.java
@@ -370,7 +370,7 @@
      * @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 51701c6..408d0ce 100644
--- a/core/java/android/pim/vcard/VCardBuilder.java
+++ b/core/java/android/pim/vcard/VCardBuilder.java
@@ -835,66 +835,90 @@
      * @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 @@
             return new PostalStruct(
                     reallyUseQuotedPrintable, appendCharset, addressBuffer.toString());
         }
-        return null;  // There's no data available.
     }
 
     public VCardBuilder appendIms(final List<ContentValues> contentValuesList) {
@@ -1653,13 +1676,22 @@
         // 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 8404da0..885f7ba 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 @@
      * 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 @@
         }
 
         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 @@
         }
     }
 
-    /**
-     * 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 @@
         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 @@
      * 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<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;
             }
         }
@@ -442,11 +420,10 @@
      *       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 @@
         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 @@
      * @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 @@
         }
     }
 
+    /**
+     * @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 4eb47c0..190a355 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 @@
         return addNodeWithOrder(propName, propValue, null, null, contentValues, null, null);
     }
 
+    public PropertyNodesVerifierElem addNodeWithOrder(String propName,
+            List<String> propValueList, ContentValues contentValues) {
+        return addNodeWithOrder(propName, null, propValueList,
+                null, contentValues, null, null);
+    }
+
     public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue,
             List<String> propValueList) {
         return addNodeWithOrder(propName, propValue, propValueList, null, null, null, null);
@@ -157,8 +163,7 @@
 
     public PropertyNodesVerifierElem addNodeWithOrder(String propName,
             List<String> 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 @@
     public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue,
             List<String> 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 @@
         return addNodeWithoutOrder(propName, propValue, null, null, contentValues, null, null);
     }
 
+    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName,
+            List<String> propValueList, ContentValues contentValues) {
+        return addNodeWithoutOrder(propName, null,
+                propValueList, null, contentValues, null, null);
+    }
+
     public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue,
             List<String> propValueList) {
         return addNodeWithoutOrder(propName, propValue, propValueList, null, null, null, null);
     }
 
-    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, List<String> propValueList) {
-        final String propValue = concatinateListWithSemiColon(propValueList);
-        return addNodeWithoutOrder(propName, propValue, propValueList,
+    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName,
+            List<String> propValueList) {
+        return addNodeWithoutOrder(propName, null, propValueList,
                 null, null, null, null);
     }
 
@@ -238,6 +252,9 @@
     public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue,
             List<String> 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 a1db051..616d451 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 @@
         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 @@
                 .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 @@
                 .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 0522867..dd20ec6 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 @@
         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 @@
         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 @@
         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 @@
     /**
      * 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 6202bdb..592c285 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 @@
 
 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 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 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"));