Rename several files so that readers would not be confused.

Add unit tests around Phone-number handling and fix some bugs.

Internal issue number: 2195990
diff --git a/core/java/android/pim/vcard/Constants.java b/core/java/android/pim/vcard/Constants.java
index 1e2ccdf..9e4b13a 100644
--- a/core/java/android/pim/vcard/Constants.java
+++ b/core/java/android/pim/vcard/Constants.java
@@ -83,18 +83,6 @@
 
     public static final String PARAM_TYPE = "TYPE";
 
-    // How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0
-    //
-    // e.g.
-    // 1) Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..." 
-    // 2) Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."
-    // 3) Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."
-    //
-    // 2) has been the default of VCard exporter/importer in Android, but we can see the other
-    // formats in vCard data emitted by the other softwares/devices.
-    //
-    // So we are currently not sure which type is the best; probably we will have to change which
-    // type should be emitted depending on the device.
     public static final String PARAM_TYPE_HOME = "HOME";
     public static final String PARAM_TYPE_WORK = "WORK";
     public static final String PARAM_TYPE_FAX = "FAX";
@@ -117,7 +105,6 @@
     public static final String PARAM_TYPE_TLX = "TLX";  // Telex
 
     // Phone types existing in vCard 2.1 but not known to ContactsContract.
-    // TODO: should make parser make these TYPE_CUSTOM.
     public static final String PARAM_TYPE_MODEM = "MODEM";
     public static final String PARAM_TYPE_MSG = "MSG";
     public static final String PARAM_TYPE_BBS = "BBS";
@@ -156,9 +143,11 @@
         public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
     }
 
-    // TODO: Should be in ContactsContract?
     /* package */ static final int MAX_DATA_COLUMN = 15;
 
+    /* package */ static final int MAX_CHARACTER_NUMS_QP = 76;
+    static final int MAX_CHARACTER_NUMS_BASE64_V30 = 75;
+
     private Constants() {
     }
 }
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/JapaneseUtils.java b/core/java/android/pim/vcard/JapaneseUtils.java
new file mode 100644
index 0000000..b596e86
--- /dev/null
+++ b/core/java/android/pim/vcard/JapaneseUtils.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.pim.vcard;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * TextUtils especially for Japanese.
+ */
+/* package */ class JapaneseUtils {
+    static private final Map<Character, String> sHalfWidthMap =
+        new HashMap<Character, String>();
+
+    static {
+        // There's no logical mapping rule in Unicode. Sigh.
+        sHalfWidthMap.put('\u3001', "\uFF64");
+        sHalfWidthMap.put('\u3002', "\uFF61");
+        sHalfWidthMap.put('\u300C', "\uFF62");
+        sHalfWidthMap.put('\u300D', "\uFF63");
+        sHalfWidthMap.put('\u301C', "~");
+        sHalfWidthMap.put('\u3041', "\uFF67");
+        sHalfWidthMap.put('\u3042', "\uFF71");
+        sHalfWidthMap.put('\u3043', "\uFF68");
+        sHalfWidthMap.put('\u3044', "\uFF72");
+        sHalfWidthMap.put('\u3045', "\uFF69");
+        sHalfWidthMap.put('\u3046', "\uFF73");
+        sHalfWidthMap.put('\u3047', "\uFF6A");
+        sHalfWidthMap.put('\u3048', "\uFF74");
+        sHalfWidthMap.put('\u3049', "\uFF6B");
+        sHalfWidthMap.put('\u304A', "\uFF75");
+        sHalfWidthMap.put('\u304B', "\uFF76");
+        sHalfWidthMap.put('\u304C', "\uFF76\uFF9E");
+        sHalfWidthMap.put('\u304D', "\uFF77");
+        sHalfWidthMap.put('\u304E', "\uFF77\uFF9E");
+        sHalfWidthMap.put('\u304F', "\uFF78");
+        sHalfWidthMap.put('\u3050', "\uFF78\uFF9E");
+        sHalfWidthMap.put('\u3051', "\uFF79");
+        sHalfWidthMap.put('\u3052', "\uFF79\uFF9E");
+        sHalfWidthMap.put('\u3053', "\uFF7A");
+        sHalfWidthMap.put('\u3054', "\uFF7A\uFF9E");
+        sHalfWidthMap.put('\u3055', "\uFF7B");
+        sHalfWidthMap.put('\u3056', "\uFF7B\uFF9E");
+        sHalfWidthMap.put('\u3057', "\uFF7C");
+        sHalfWidthMap.put('\u3058', "\uFF7C\uFF9E");
+        sHalfWidthMap.put('\u3059', "\uFF7D");
+        sHalfWidthMap.put('\u305A', "\uFF7D\uFF9E");
+        sHalfWidthMap.put('\u305B', "\uFF7E");
+        sHalfWidthMap.put('\u305C', "\uFF7E\uFF9E");
+        sHalfWidthMap.put('\u305D', "\uFF7F");
+        sHalfWidthMap.put('\u305E', "\uFF7F\uFF9E");
+        sHalfWidthMap.put('\u305F', "\uFF80");
+        sHalfWidthMap.put('\u3060', "\uFF80\uFF9E");
+        sHalfWidthMap.put('\u3061', "\uFF81");
+        sHalfWidthMap.put('\u3062', "\uFF81\uFF9E");
+        sHalfWidthMap.put('\u3063', "\uFF6F");
+        sHalfWidthMap.put('\u3064', "\uFF82");
+        sHalfWidthMap.put('\u3065', "\uFF82\uFF9E");
+        sHalfWidthMap.put('\u3066', "\uFF83");
+        sHalfWidthMap.put('\u3067', "\uFF83\uFF9E");
+        sHalfWidthMap.put('\u3068', "\uFF84");
+        sHalfWidthMap.put('\u3069', "\uFF84\uFF9E");
+        sHalfWidthMap.put('\u306A', "\uFF85");
+        sHalfWidthMap.put('\u306B', "\uFF86");
+        sHalfWidthMap.put('\u306C', "\uFF87");
+        sHalfWidthMap.put('\u306D', "\uFF88");
+        sHalfWidthMap.put('\u306E', "\uFF89");
+        sHalfWidthMap.put('\u306F', "\uFF8A");
+        sHalfWidthMap.put('\u3070', "\uFF8A\uFF9E");
+        sHalfWidthMap.put('\u3071', "\uFF8A\uFF9F");
+        sHalfWidthMap.put('\u3072', "\uFF8B");
+        sHalfWidthMap.put('\u3073', "\uFF8B\uFF9E");
+        sHalfWidthMap.put('\u3074', "\uFF8B\uFF9F");
+        sHalfWidthMap.put('\u3075', "\uFF8C");
+        sHalfWidthMap.put('\u3076', "\uFF8C\uFF9E");
+        sHalfWidthMap.put('\u3077', "\uFF8C\uFF9F");
+        sHalfWidthMap.put('\u3078', "\uFF8D");
+        sHalfWidthMap.put('\u3079', "\uFF8D\uFF9E");
+        sHalfWidthMap.put('\u307A', "\uFF8D\uFF9F");
+        sHalfWidthMap.put('\u307B', "\uFF8E");
+        sHalfWidthMap.put('\u307C', "\uFF8E\uFF9E");
+        sHalfWidthMap.put('\u307D', "\uFF8E\uFF9F");
+        sHalfWidthMap.put('\u307E', "\uFF8F");
+        sHalfWidthMap.put('\u307F', "\uFF90");
+        sHalfWidthMap.put('\u3080', "\uFF91");
+        sHalfWidthMap.put('\u3081', "\uFF92");
+        sHalfWidthMap.put('\u3082', "\uFF93");
+        sHalfWidthMap.put('\u3083', "\uFF6C");
+        sHalfWidthMap.put('\u3084', "\uFF94");
+        sHalfWidthMap.put('\u3085', "\uFF6D");
+        sHalfWidthMap.put('\u3086', "\uFF95");
+        sHalfWidthMap.put('\u3087', "\uFF6E");
+        sHalfWidthMap.put('\u3088', "\uFF96");
+        sHalfWidthMap.put('\u3089', "\uFF97");
+        sHalfWidthMap.put('\u308A', "\uFF98");
+        sHalfWidthMap.put('\u308B', "\uFF99");
+        sHalfWidthMap.put('\u308C', "\uFF9A");
+        sHalfWidthMap.put('\u308D', "\uFF9B");
+        sHalfWidthMap.put('\u308E', "\uFF9C");
+        sHalfWidthMap.put('\u308F', "\uFF9C");
+        sHalfWidthMap.put('\u3090', "\uFF72");
+        sHalfWidthMap.put('\u3091', "\uFF74");
+        sHalfWidthMap.put('\u3092', "\uFF66");
+        sHalfWidthMap.put('\u3093', "\uFF9D");
+        sHalfWidthMap.put('\u309B', "\uFF9E");
+        sHalfWidthMap.put('\u309C', "\uFF9F");
+        sHalfWidthMap.put('\u30A1', "\uFF67");
+        sHalfWidthMap.put('\u30A2', "\uFF71");
+        sHalfWidthMap.put('\u30A3', "\uFF68");
+        sHalfWidthMap.put('\u30A4', "\uFF72");
+        sHalfWidthMap.put('\u30A5', "\uFF69");
+        sHalfWidthMap.put('\u30A6', "\uFF73");
+        sHalfWidthMap.put('\u30A7', "\uFF6A");
+        sHalfWidthMap.put('\u30A8', "\uFF74");
+        sHalfWidthMap.put('\u30A9', "\uFF6B");
+        sHalfWidthMap.put('\u30AA', "\uFF75");
+        sHalfWidthMap.put('\u30AB', "\uFF76");
+        sHalfWidthMap.put('\u30AC', "\uFF76\uFF9E");
+        sHalfWidthMap.put('\u30AD', "\uFF77");
+        sHalfWidthMap.put('\u30AE', "\uFF77\uFF9E");
+        sHalfWidthMap.put('\u30AF', "\uFF78");
+        sHalfWidthMap.put('\u30B0', "\uFF78\uFF9E");
+        sHalfWidthMap.put('\u30B1', "\uFF79");
+        sHalfWidthMap.put('\u30B2', "\uFF79\uFF9E");
+        sHalfWidthMap.put('\u30B3', "\uFF7A");
+        sHalfWidthMap.put('\u30B4', "\uFF7A\uFF9E");
+        sHalfWidthMap.put('\u30B5', "\uFF7B");
+        sHalfWidthMap.put('\u30B6', "\uFF7B\uFF9E");
+        sHalfWidthMap.put('\u30B7', "\uFF7C");
+        sHalfWidthMap.put('\u30B8', "\uFF7C\uFF9E");
+        sHalfWidthMap.put('\u30B9', "\uFF7D");
+        sHalfWidthMap.put('\u30BA', "\uFF7D\uFF9E");
+        sHalfWidthMap.put('\u30BB', "\uFF7E");
+        sHalfWidthMap.put('\u30BC', "\uFF7E\uFF9E");
+        sHalfWidthMap.put('\u30BD', "\uFF7F");
+        sHalfWidthMap.put('\u30BE', "\uFF7F\uFF9E");
+        sHalfWidthMap.put('\u30BF', "\uFF80");
+        sHalfWidthMap.put('\u30C0', "\uFF80\uFF9E");
+        sHalfWidthMap.put('\u30C1', "\uFF81");
+        sHalfWidthMap.put('\u30C2', "\uFF81\uFF9E");
+        sHalfWidthMap.put('\u30C3', "\uFF6F");
+        sHalfWidthMap.put('\u30C4', "\uFF82");
+        sHalfWidthMap.put('\u30C5', "\uFF82\uFF9E");
+        sHalfWidthMap.put('\u30C6', "\uFF83");
+        sHalfWidthMap.put('\u30C7', "\uFF83\uFF9E");
+        sHalfWidthMap.put('\u30C8', "\uFF84");
+        sHalfWidthMap.put('\u30C9', "\uFF84\uFF9E");
+        sHalfWidthMap.put('\u30CA', "\uFF85");
+        sHalfWidthMap.put('\u30CB', "\uFF86");
+        sHalfWidthMap.put('\u30CC', "\uFF87");
+        sHalfWidthMap.put('\u30CD', "\uFF88");
+        sHalfWidthMap.put('\u30CE', "\uFF89");
+        sHalfWidthMap.put('\u30CF', "\uFF8A");
+        sHalfWidthMap.put('\u30D0', "\uFF8A\uFF9E");
+        sHalfWidthMap.put('\u30D1', "\uFF8A\uFF9F");
+        sHalfWidthMap.put('\u30D2', "\uFF8B");
+        sHalfWidthMap.put('\u30D3', "\uFF8B\uFF9E");
+        sHalfWidthMap.put('\u30D4', "\uFF8B\uFF9F");
+        sHalfWidthMap.put('\u30D5', "\uFF8C");
+        sHalfWidthMap.put('\u30D6', "\uFF8C\uFF9E");
+        sHalfWidthMap.put('\u30D7', "\uFF8C\uFF9F");
+        sHalfWidthMap.put('\u30D8', "\uFF8D");
+        sHalfWidthMap.put('\u30D9', "\uFF8D\uFF9E");
+        sHalfWidthMap.put('\u30DA', "\uFF8D\uFF9F");
+        sHalfWidthMap.put('\u30DB', "\uFF8E");
+        sHalfWidthMap.put('\u30DC', "\uFF8E\uFF9E");
+        sHalfWidthMap.put('\u30DD', "\uFF8E\uFF9F");
+        sHalfWidthMap.put('\u30DE', "\uFF8F");
+        sHalfWidthMap.put('\u30DF', "\uFF90");
+        sHalfWidthMap.put('\u30E0', "\uFF91");
+        sHalfWidthMap.put('\u30E1', "\uFF92");
+        sHalfWidthMap.put('\u30E2', "\uFF93");
+        sHalfWidthMap.put('\u30E3', "\uFF6C");
+        sHalfWidthMap.put('\u30E4', "\uFF94");
+        sHalfWidthMap.put('\u30E5', "\uFF6D");
+        sHalfWidthMap.put('\u30E6', "\uFF95");
+        sHalfWidthMap.put('\u30E7', "\uFF6E");
+        sHalfWidthMap.put('\u30E8', "\uFF96");
+        sHalfWidthMap.put('\u30E9', "\uFF97");
+        sHalfWidthMap.put('\u30EA', "\uFF98");
+        sHalfWidthMap.put('\u30EB', "\uFF99");
+        sHalfWidthMap.put('\u30EC', "\uFF9A");
+        sHalfWidthMap.put('\u30ED', "\uFF9B");
+        sHalfWidthMap.put('\u30EE', "\uFF9C");
+        sHalfWidthMap.put('\u30EF', "\uFF9C");
+        sHalfWidthMap.put('\u30F0', "\uFF72");
+        sHalfWidthMap.put('\u30F1', "\uFF74");
+        sHalfWidthMap.put('\u30F2', "\uFF66");
+        sHalfWidthMap.put('\u30F3', "\uFF9D");
+        sHalfWidthMap.put('\u30F4', "\uFF73\uFF9E");
+        sHalfWidthMap.put('\u30F5', "\uFF76");
+        sHalfWidthMap.put('\u30F6', "\uFF79");
+        sHalfWidthMap.put('\u30FB', "\uFF65");
+        sHalfWidthMap.put('\u30FC', "\uFF70");
+        sHalfWidthMap.put('\uFF01', "!");
+        sHalfWidthMap.put('\uFF02', "\"");
+        sHalfWidthMap.put('\uFF03', "#");
+        sHalfWidthMap.put('\uFF04', "$");
+        sHalfWidthMap.put('\uFF05', "%");
+        sHalfWidthMap.put('\uFF06', "&");
+        sHalfWidthMap.put('\uFF07', "'");
+        sHalfWidthMap.put('\uFF08', "(");
+        sHalfWidthMap.put('\uFF09', ")");
+        sHalfWidthMap.put('\uFF0A', "*");
+        sHalfWidthMap.put('\uFF0B', "+");
+        sHalfWidthMap.put('\uFF0C', ",");
+        sHalfWidthMap.put('\uFF0D', "-");
+        sHalfWidthMap.put('\uFF0E', ".");
+        sHalfWidthMap.put('\uFF0F', "/");
+        sHalfWidthMap.put('\uFF10', "0");
+        sHalfWidthMap.put('\uFF11', "1");
+        sHalfWidthMap.put('\uFF12', "2");
+        sHalfWidthMap.put('\uFF13', "3");
+        sHalfWidthMap.put('\uFF14', "4");
+        sHalfWidthMap.put('\uFF15', "5");
+        sHalfWidthMap.put('\uFF16', "6");
+        sHalfWidthMap.put('\uFF17', "7");
+        sHalfWidthMap.put('\uFF18', "8");
+        sHalfWidthMap.put('\uFF19', "9");
+        sHalfWidthMap.put('\uFF1A', ":");
+        sHalfWidthMap.put('\uFF1B', ";");
+        sHalfWidthMap.put('\uFF1C', "<");
+        sHalfWidthMap.put('\uFF1D', "=");
+        sHalfWidthMap.put('\uFF1E', ">");
+        sHalfWidthMap.put('\uFF1F', "?");
+        sHalfWidthMap.put('\uFF20', "@");
+        sHalfWidthMap.put('\uFF21', "A");
+        sHalfWidthMap.put('\uFF22', "B");
+        sHalfWidthMap.put('\uFF23', "C");
+        sHalfWidthMap.put('\uFF24', "D");
+        sHalfWidthMap.put('\uFF25', "E");
+        sHalfWidthMap.put('\uFF26', "F");
+        sHalfWidthMap.put('\uFF27', "G");
+        sHalfWidthMap.put('\uFF28', "H");
+        sHalfWidthMap.put('\uFF29', "I");
+        sHalfWidthMap.put('\uFF2A', "J");
+        sHalfWidthMap.put('\uFF2B', "K");
+        sHalfWidthMap.put('\uFF2C', "L");
+        sHalfWidthMap.put('\uFF2D', "M");
+        sHalfWidthMap.put('\uFF2E', "N");
+        sHalfWidthMap.put('\uFF2F', "O");
+        sHalfWidthMap.put('\uFF30', "P");
+        sHalfWidthMap.put('\uFF31', "Q");
+        sHalfWidthMap.put('\uFF32', "R");
+        sHalfWidthMap.put('\uFF33', "S");
+        sHalfWidthMap.put('\uFF34', "T");
+        sHalfWidthMap.put('\uFF35', "U");
+        sHalfWidthMap.put('\uFF36', "V");
+        sHalfWidthMap.put('\uFF37', "W");
+        sHalfWidthMap.put('\uFF38', "X");
+        sHalfWidthMap.put('\uFF39', "Y");
+        sHalfWidthMap.put('\uFF3A', "Z");
+        sHalfWidthMap.put('\uFF3B', "[");
+        sHalfWidthMap.put('\uFF3C', "\\");
+        sHalfWidthMap.put('\uFF3D', "]");
+        sHalfWidthMap.put('\uFF3E', "^");
+        sHalfWidthMap.put('\uFF3F', "_");
+        sHalfWidthMap.put('\uFF41', "a");
+        sHalfWidthMap.put('\uFF42', "b");
+        sHalfWidthMap.put('\uFF43', "c");
+        sHalfWidthMap.put('\uFF44', "d");
+        sHalfWidthMap.put('\uFF45', "e");
+        sHalfWidthMap.put('\uFF46', "f");
+        sHalfWidthMap.put('\uFF47', "g");
+        sHalfWidthMap.put('\uFF48', "h");
+        sHalfWidthMap.put('\uFF49', "i");
+        sHalfWidthMap.put('\uFF4A', "j");
+        sHalfWidthMap.put('\uFF4B', "k");
+        sHalfWidthMap.put('\uFF4C', "l");
+        sHalfWidthMap.put('\uFF4D', "m");
+        sHalfWidthMap.put('\uFF4E', "n");
+        sHalfWidthMap.put('\uFF4F', "o");
+        sHalfWidthMap.put('\uFF50', "p");
+        sHalfWidthMap.put('\uFF51', "q");
+        sHalfWidthMap.put('\uFF52', "r");
+        sHalfWidthMap.put('\uFF53', "s");
+        sHalfWidthMap.put('\uFF54', "t");
+        sHalfWidthMap.put('\uFF55', "u");
+        sHalfWidthMap.put('\uFF56', "v");
+        sHalfWidthMap.put('\uFF57', "w");
+        sHalfWidthMap.put('\uFF58', "x");
+        sHalfWidthMap.put('\uFF59', "y");
+        sHalfWidthMap.put('\uFF5A', "z");
+        sHalfWidthMap.put('\uFF5B', "{");
+        sHalfWidthMap.put('\uFF5C', "|");
+        sHalfWidthMap.put('\uFF5D', "}");
+        sHalfWidthMap.put('\uFF5E', "~");
+        sHalfWidthMap.put('\uFF61', "\uFF61");
+        sHalfWidthMap.put('\uFF62', "\uFF62");
+        sHalfWidthMap.put('\uFF63', "\uFF63");
+        sHalfWidthMap.put('\uFF64', "\uFF64");
+        sHalfWidthMap.put('\uFF65', "\uFF65");
+        sHalfWidthMap.put('\uFF66', "\uFF66");
+        sHalfWidthMap.put('\uFF67', "\uFF67");
+        sHalfWidthMap.put('\uFF68', "\uFF68");
+        sHalfWidthMap.put('\uFF69', "\uFF69");
+        sHalfWidthMap.put('\uFF6A', "\uFF6A");
+        sHalfWidthMap.put('\uFF6B', "\uFF6B");
+        sHalfWidthMap.put('\uFF6C', "\uFF6C");
+        sHalfWidthMap.put('\uFF6D', "\uFF6D");
+        sHalfWidthMap.put('\uFF6E', "\uFF6E");
+        sHalfWidthMap.put('\uFF6F', "\uFF6F");
+        sHalfWidthMap.put('\uFF70', "\uFF70");
+        sHalfWidthMap.put('\uFF71', "\uFF71");
+        sHalfWidthMap.put('\uFF72', "\uFF72");
+        sHalfWidthMap.put('\uFF73', "\uFF73");
+        sHalfWidthMap.put('\uFF74', "\uFF74");
+        sHalfWidthMap.put('\uFF75', "\uFF75");
+        sHalfWidthMap.put('\uFF76', "\uFF76");
+        sHalfWidthMap.put('\uFF77', "\uFF77");
+        sHalfWidthMap.put('\uFF78', "\uFF78");
+        sHalfWidthMap.put('\uFF79', "\uFF79");
+        sHalfWidthMap.put('\uFF7A', "\uFF7A");
+        sHalfWidthMap.put('\uFF7B', "\uFF7B");
+        sHalfWidthMap.put('\uFF7C', "\uFF7C");
+        sHalfWidthMap.put('\uFF7D', "\uFF7D");
+        sHalfWidthMap.put('\uFF7E', "\uFF7E");
+        sHalfWidthMap.put('\uFF7F', "\uFF7F");
+        sHalfWidthMap.put('\uFF80', "\uFF80");
+        sHalfWidthMap.put('\uFF81', "\uFF81");
+        sHalfWidthMap.put('\uFF82', "\uFF82");
+        sHalfWidthMap.put('\uFF83', "\uFF83");
+        sHalfWidthMap.put('\uFF84', "\uFF84");
+        sHalfWidthMap.put('\uFF85', "\uFF85");
+        sHalfWidthMap.put('\uFF86', "\uFF86");
+        sHalfWidthMap.put('\uFF87', "\uFF87");
+        sHalfWidthMap.put('\uFF88', "\uFF88");
+        sHalfWidthMap.put('\uFF89', "\uFF89");
+        sHalfWidthMap.put('\uFF8A', "\uFF8A");
+        sHalfWidthMap.put('\uFF8B', "\uFF8B");
+        sHalfWidthMap.put('\uFF8C', "\uFF8C");
+        sHalfWidthMap.put('\uFF8D', "\uFF8D");
+        sHalfWidthMap.put('\uFF8E', "\uFF8E");
+        sHalfWidthMap.put('\uFF8F', "\uFF8F");
+        sHalfWidthMap.put('\uFF90', "\uFF90");
+        sHalfWidthMap.put('\uFF91', "\uFF91");
+        sHalfWidthMap.put('\uFF92', "\uFF92");
+        sHalfWidthMap.put('\uFF93', "\uFF93");
+        sHalfWidthMap.put('\uFF94', "\uFF94");
+        sHalfWidthMap.put('\uFF95', "\uFF95");
+        sHalfWidthMap.put('\uFF96', "\uFF96");
+        sHalfWidthMap.put('\uFF97', "\uFF97");
+        sHalfWidthMap.put('\uFF98', "\uFF98");
+        sHalfWidthMap.put('\uFF99', "\uFF99");
+        sHalfWidthMap.put('\uFF9A', "\uFF9A");
+        sHalfWidthMap.put('\uFF9B', "\uFF9B");
+        sHalfWidthMap.put('\uFF9C', "\uFF9C");
+        sHalfWidthMap.put('\uFF9D', "\uFF9D");
+        sHalfWidthMap.put('\uFF9E', "\uFF9E");
+        sHalfWidthMap.put('\uFF9F', "\uFF9F");
+        sHalfWidthMap.put('\uFFE5', "\u005C\u005C");
+    }
+
+    /**
+     * Return half-width version of that character if possible. Return null if not possible
+     * @param ch input character
+     * @return CharSequence object if the mapping for ch exists. Return null otherwise.
+     */
+    public static CharSequence tryGetHalfWidthText(char ch) {
+        if (sHalfWidthMap.containsKey(ch)) {
+            return sHalfWidthMap.get(ch);
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index bbd19fb..71f947c 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -196,7 +196,7 @@
      * An useful example handler, which emits VCard String to outputstream one by one.
      * </p>
      * <p>
-     * The input OutputStream object is closed() on {{@link #onTerminate()}.
+     * The input OutputStream object is closed() on {@link #onTerminate()}.
      * Must not close the stream outside.
      * </p>
      */
@@ -353,7 +353,8 @@
     /**
      * Construct for supporting call log entry vCard composing.
      */
-    public VCardComposer(Context context, int vcardType, boolean careHandlerErrors) {
+    public VCardComposer(final Context context, final int vcardType,
+            final boolean careHandlerErrors) {
         mContext = context;
         mVCardType = vcardType;
         mCareHandlerErrors = careHandlerErrors;
@@ -403,7 +404,7 @@
     }
 
     /**
-     * Must call before {{@link #init()}.
+     * Must be called before {@link #init()}.
      */
     public void addHandler(OneEntryHandler handler) {
         if (handler != null) {
@@ -510,8 +511,7 @@
         } catch (OutOfMemoryError error) {
             // Maybe some data (e.g. photo) is too big to have in memory. But it
             // should be rare.
-            Log.e(LOG_TAG, "OutOfMemoryError occured. Ignore the entry: "
-                    + name);
+            Log.e(LOG_TAG, "OutOfMemoryError occured. Ignore the entry: " + name);
             System.gc();
             // TODO: should tell users what happened?
             return true;
@@ -676,7 +676,7 @@
         }
     }
 
-    private boolean containsNonEmptyName(ContentValues contentValues) {
+    private boolean containsNonEmptyName(final ContentValues contentValues) {
         final String familyName = contentValues.getAsString(StructuredName.FAMILY_NAME);
         final String middleName = contentValues.getAsString(StructuredName.MIDDLE_NAME);
         final String givenName = contentValues.getAsString(StructuredName.GIVEN_NAME);
@@ -715,7 +715,7 @@
             } else if (primaryContentValues == null) {
                 // We choose the first "primary" ContentValues
                 // if "super primary" ContentValues does not exist.
-                Integer isPrimary = contentValues.getAsInteger(StructuredName.IS_PRIMARY);
+                final Integer isPrimary = contentValues.getAsInteger(StructuredName.IS_PRIMARY);
                 if (isPrimary != null && isPrimary > 0 &&
                         containsNonEmptyName(contentValues)) {
                     primaryContentValues = contentValues;
@@ -897,11 +897,11 @@
         final String phoneticMiddleName;
         final String phoneticGivenName;
         {
-            String tmpPhoneticFamilyName =
+            final String tmpPhoneticFamilyName =
                 primaryContentValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
-            String tmpPhoneticMiddleName =
+            final String tmpPhoneticMiddleName =
                 primaryContentValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
-            String tmpPhoneticGivenName =
+            final String tmpPhoneticGivenName =
                 primaryContentValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
             if (mNeedsToConvertPhoneticString) {
                 phoneticFamilyName = VCardUtils.toHalfWidthString(tmpPhoneticFamilyName);
@@ -913,10 +913,11 @@
                 phoneticGivenName = tmpPhoneticGivenName;
             }
         }
+
         if (!(TextUtils.isEmpty(phoneticFamilyName)
                 && TextUtils.isEmpty(phoneticMiddleName)
                 && TextUtils.isEmpty(phoneticGivenName))) {
-
+            // Try to emit the field(s) related to phonetic name.
             if (mIsV30) {
                 final String sortString = VCardUtils
                         .constructNameFromElements(mVCardType,
@@ -937,6 +938,12 @@
                 //       since it is supported by
                 //       a lot of Japanese mobile phones. This is "X-" property, so
                 //       any parser hopefully would not get confused with this.
+                //
+                //       Also, DoCoMo's specification requires vCard composer to use just the first
+                //       column.
+                //       i.e.
+                //       o  SOUND;X-IRMC-N:Miyakawa Daisuke;;;;
+                //       x  SOUND;X-IRMC-N:Miyakawa;Daisuke;;;
                 builder.append(Constants.PROPERTY_SOUND);
                 builder.append(VCARD_PARAM_SEPARATOR);
                 builder.append(Constants.PARAM_TYPE_X_IRMC_N);
@@ -970,8 +977,6 @@
                     builder.append(mVCardCharsetParameter);
                 }
                 builder.append(VCARD_DATA_SEPARATOR);
-                // DoCoMo's specification requires vCard composer to use just the first
-                // column.
                 {
                     boolean first = true;
                     if (!TextUtils.isEmpty(encodedPhoneticFamilyName)) {
@@ -999,16 +1004,18 @@
                 builder.append(VCARD_ITEM_SEPARATOR);
                 builder.append(VCARD_END_OF_LINE);
             }
-        } else if (mIsDoCoMo) {
-            builder.append(Constants.PROPERTY_SOUND);
-            builder.append(VCARD_PARAM_SEPARATOR);
-            builder.append(Constants.PARAM_TYPE_X_IRMC_N);
-            builder.append(VCARD_DATA_SEPARATOR);
-            builder.append(VCARD_ITEM_SEPARATOR);
-            builder.append(VCARD_ITEM_SEPARATOR);
-            builder.append(VCARD_ITEM_SEPARATOR);
-            builder.append(VCARD_ITEM_SEPARATOR);
-            builder.append(VCARD_END_OF_LINE);
+        } else {  // If phonetic name fields are all empty
+            if (mIsDoCoMo) {
+                builder.append(Constants.PROPERTY_SOUND);
+                builder.append(VCARD_PARAM_SEPARATOR);
+                builder.append(Constants.PARAM_TYPE_X_IRMC_N);
+                builder.append(VCARD_DATA_SEPARATOR);
+                builder.append(VCARD_ITEM_SEPARATOR);
+                builder.append(VCARD_ITEM_SEPARATOR);
+                builder.append(VCARD_ITEM_SEPARATOR);
+                builder.append(VCARD_ITEM_SEPARATOR);
+                builder.append(VCARD_END_OF_LINE);
+            }
         }
 
         if (mUsesDefactProperty) {
@@ -1252,48 +1259,50 @@
         }
     }
 
+    private static final Map<Integer, Integer> sPostalTypePriorityMap;
+
+    static {
+        sPostalTypePriorityMap = new HashMap<Integer, Integer>();
+        sPostalTypePriorityMap.put(StructuredPostal.TYPE_HOME, 0);
+        sPostalTypePriorityMap.put(StructuredPostal.TYPE_WORK, 1);
+        sPostalTypePriorityMap.put(StructuredPostal.TYPE_OTHER, 2);
+        sPostalTypePriorityMap.put(StructuredPostal.TYPE_CUSTOM, 3);
+    }
+
     /**
      * Tries to append just one line. If there's no appropriate address
      * information, append an empty line.
      */
     private void appendPostalsForDoCoMo(final StringBuilder builder,
             final List<ContentValues> contentValuesList) {
-        // TODO: from old, inefficient code. fix this.
-        if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
-                StructuredPostal.TYPE_HOME)) {
-            return;
-        }
-        if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
-                StructuredPostal.TYPE_WORK)) {
-            return;
-        }
-        if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
-                StructuredPostal.TYPE_OTHER)) {
-            return;
-        }
-        if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
-                StructuredPostal.TYPE_CUSTOM)) {
-            return;
-        }
-
-        Log.w(LOG_TAG,
-                "Should not come here. Must have at least one postal data.");
-    }
-
-    private boolean appendPostalsForDoCoMoInternal(final StringBuilder builder,
-            final List<ContentValues> contentValuesList, Integer preferedType) {
+        int currentPriority = Integer.MAX_VALUE;
+        int currentType = Integer.MAX_VALUE;
+        ContentValues currentContentValues = null;
         for (ContentValues contentValues : contentValuesList) {
-            final Integer type = contentValues.getAsInteger(StructuredPostal.TYPE);
-            final String label = contentValues.getAsString(StructuredPostal.LABEL);
-            if (type == preferedType) {
-                // Note: Not sure why we need to emit "empty" line even when actual
-                //       data does not exist. There may be some reason or may not.
-                //       We keep safer side since the previous implementation did so.
-                appendVCardPostalLine(builder, type, label, contentValues, true, true);
-                return true;
+            if (contentValues == null) {
+                continue;
+            }
+            final Integer typeAsInteger = contentValues.getAsInteger(StructuredPostal.TYPE);
+            final Integer priorityAsInteger = sPostalTypePriorityMap.get(typeAsInteger);
+            final int priority =
+                    (priorityAsInteger != null ? priorityAsInteger : Integer.MAX_VALUE);
+            if (priority < currentPriority) {
+                currentPriority = priority;
+                currentType = typeAsInteger;
+                currentContentValues = contentValues;
+                if (priority == 0) {
+                    break;
+                }
             }
         }
-        return false;
+
+        if (currentContentValues == null) {
+            Log.w(LOG_TAG, "Should not come here. Must have at least one postal data.");
+            return;
+        }
+
+        final String label = currentContentValues.getAsString(StructuredPostal.LABEL);
+        appendVCardPostalLine(builder, currentType, label, currentContentValues, false, true);
     }
 
     private void appendPostalsForGeneric(final StringBuilder builder,
@@ -1302,9 +1311,9 @@
             if (contentValues == null) {
                 continue;
             }
-            final Integer typeAsObject = contentValues.getAsInteger(StructuredPostal.TYPE);
-            final int type = (typeAsObject != null ?
-                    typeAsObject : DEFAULT_POSTAL_TYPE);
+            final Integer typeAsInteger = contentValues.getAsInteger(StructuredPostal.TYPE);
+            final int type = (typeAsInteger != null ?
+                    typeAsInteger : DEFAULT_POSTAL_TYPE);
             final String label = contentValues.getAsString(StructuredPostal.LABEL);
             final Integer isPrimaryAsInteger =
                 contentValues.getAsInteger(StructuredPostal.IS_PRIMARY);
@@ -1525,9 +1534,9 @@
                     photoType = "GIF";
                 } else if (data.length >= 4 && data[0] == (byte) 0x89
                         && data[1] == 'P' && data[2] == 'N' && data[3] == 'G') {
-                    // Note: vCard 2.1 officially does not support PNG, but we may
-                    // have it and using X- word like "X-PNG" may not let importers
-                    // know it is PNG. So we use the String "PNG" as is...
+                    // Note: vCard 2.1 officially does not support PNG, but we may have it and
+                    //       using X- word like "X-PNG" may not let importers know it is PNG.
+                    //       So we use the String "PNG" as is...
                     photoType = "PNG";
                 } else if (data.length >= 2 && data[0] == (byte) 0xff
                         && data[1] == (byte) 0xd8) {
@@ -1599,7 +1608,7 @@
         rawDataList.add(mimeType);
         final List<String> columnNameList;
         if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            
+
         } else {
             // If you add the other field, please check all the columns are able to be
             // converted to String.
@@ -1851,7 +1860,7 @@
                 break;
             }
             case StructuredPostal.TYPE_CUSTOM: {
-                if (mUsesAndroidProperty && !TextUtils.isEmpty(label)
+                if (!TextUtils.isEmpty(label)
                         && VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
                     // We're not sure whether the label is valid in the spec
                     // ("IANA-token" in the vCard 3.0 is unclear...)
@@ -1871,17 +1880,14 @@
         }
 
         // Actual data construction starts from here.
-        // TODO: add a new version of appendVCardLine() for this purpose.
         
         builder.append(Constants.PROPERTY_ADR);
-        builder.append(VCARD_PARAM_SEPARATOR);
 
         // Parameters
         {
-            boolean shouldAppendParamSeparator = false;
             if (!parameterList.isEmpty()) {
+                builder.append(VCARD_PARAM_SEPARATOR);
                 appendTypeParameters(builder, parameterList);
-                shouldAppendParamSeparator = true;
             }
 
             if (appendCharset) {
@@ -1889,19 +1895,13 @@
                 // but we will add it since the information should be useful for importers,
                 //
                 // Assume no parser does not emit error with this parameter in vCard 3.0.
-                if (shouldAppendParamSeparator) {
-                    builder.append(VCARD_PARAM_SEPARATOR);
-                }
+                builder.append(VCARD_PARAM_SEPARATOR);
                 builder.append(mVCardCharsetParameter);
-                shouldAppendParamSeparator = true;
             }
 
             if (reallyUseQuotedPrintable) {
-                if (shouldAppendParamSeparator) {
-                    builder.append(VCARD_PARAM_SEPARATOR);
-                }
+                builder.append(VCARD_PARAM_SEPARATOR);
                 builder.append(VCARD_PARAM_ENCODING_QP);
-                shouldAppendParamSeparator = true;
             }
         }
 
@@ -1916,13 +1916,9 @@
         final String typeAsString;
         switch (type) {
             case Email.TYPE_CUSTOM: {
-                // For backward compatibility.
-                // Detail: Until Donut, there isn't TYPE_MOBILE for email while there is now.
-                //         To support mobile type at that time, this custom label had been used.
-                if (android.provider.Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME
-                        .equals(label)) {
+                if (VCardUtils.isMobilePhoneLabel(label)) {
                     typeAsString = Constants.PARAM_TYPE_CELL;
-                } else if (mUsesAndroidProperty && !TextUtils.isEmpty(label)
+                } else if (!TextUtils.isEmpty(label)
                         && VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
                     typeAsString = "X-" + label;
                 } else {
@@ -1966,102 +1962,126 @@
     }
 
     private void appendVCardTelephoneLine(final StringBuilder builder,
-            final Integer typeAsObject, final String label,
+            final Integer typeAsInteger, final String label,
             final String encodedData, boolean isPrimary) {
         builder.append(Constants.PROPERTY_TEL);
         builder.append(VCARD_PARAM_SEPARATOR);
 
-        final int typeAsPrimitive;
-        if (typeAsObject == null) {
-            typeAsPrimitive = Phone.TYPE_OTHER;
+        final int type;
+        if (typeAsInteger == null) {
+            type = Phone.TYPE_OTHER;
         } else {
-            typeAsPrimitive = typeAsObject;
+            type = typeAsInteger;
         }
 
         ArrayList<String> parameterList = new ArrayList<String>();
-        switch (typeAsPrimitive) {
-        case Phone.TYPE_HOME:
-            parameterList.addAll(
-                    Arrays.asList(Constants.PARAM_TYPE_HOME));
-            break;
-        case Phone.TYPE_WORK:
-            parameterList.addAll(
-                    Arrays.asList(Constants.PARAM_TYPE_WORK));
-            break;
-        case Phone.TYPE_FAX_HOME:
-            parameterList.addAll(
-                    Arrays.asList(Constants.PARAM_TYPE_HOME, Constants.PARAM_TYPE_FAX));
-            break;
-        case Phone.TYPE_FAX_WORK:
-            parameterList.addAll(
-                    Arrays.asList(Constants.PARAM_TYPE_WORK, Constants.PARAM_TYPE_FAX));
-            break;
-        case Phone.TYPE_MOBILE:
-            parameterList.add(Constants.PARAM_TYPE_CELL);
-            break;
-        case Phone.TYPE_PAGER:
-            if (mIsDoCoMo) {
-                // Not sure about the reason, but previous implementation had
-                // used "VOICE" instead of "PAGER"
-                parameterList.add(Constants.PARAM_TYPE_VOICE);
-            } else {
-                parameterList.add(Constants.PARAM_TYPE_PAGER);
+        switch (type) {
+            case Phone.TYPE_HOME: {
+                parameterList.addAll(
+                        Arrays.asList(Constants.PARAM_TYPE_HOME));
+                break;
             }
-            break;
-        case Phone.TYPE_OTHER:
-            parameterList.add(Constants.PARAM_TYPE_VOICE);
-            break;
-        case Phone.TYPE_CAR:
-            parameterList.add(Constants.PARAM_TYPE_CAR);
-            break;
-        case Phone.TYPE_COMPANY_MAIN:
-            // There's no relevant field in vCard (at least 2.1).
-            parameterList.add(Constants.PARAM_TYPE_WORK);
-            isPrimary = true;
-            break;
-        case Phone.TYPE_ISDN:
-            parameterList.add(Constants.PARAM_TYPE_ISDN);
-            break;
-        case Phone.TYPE_MAIN:
-            isPrimary = true;
-            break;
-        case Phone.TYPE_OTHER_FAX:
-            parameterList.add(Constants.PARAM_TYPE_FAX);
-            break;
-        case Phone.TYPE_TELEX:
-            parameterList.add(Constants.PARAM_TYPE_TLX);
-            break;
-        case Phone.TYPE_WORK_MOBILE:
-            parameterList.addAll(
-                    Arrays.asList(Constants.PARAM_TYPE_WORK, Constants.PARAM_TYPE_CELL));
-            break;
-        case Phone.TYPE_WORK_PAGER:
-            parameterList.add(Constants.PARAM_TYPE_WORK);
-            // See above.
-            if (mIsDoCoMo) {
-                parameterList.add(Constants.PARAM_TYPE_VOICE);
-            } else {
-                parameterList.add(Constants.PARAM_TYPE_PAGER);
+            case Phone.TYPE_WORK: {
+                parameterList.addAll(
+                        Arrays.asList(Constants.PARAM_TYPE_WORK));
+                break;
             }
-            break;
-        case Phone.TYPE_MMS:
-            parameterList.add(Constants.PARAM_TYPE_MSG);
-            break;
-        case Phone.TYPE_CUSTOM:
-            if (mUsesAndroidProperty && !TextUtils.isEmpty(label)
-                        && VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
-                // Note: Strictly, vCard 2.1 does not allow "X-" parameter without
-                //       "TYPE=" string.
-                parameterList.add("X-" + label);
-            } else {
-                // Just ignore the custom type.
-                parameterList.add(Constants.PARAM_TYPE_VOICE);
+            case Phone.TYPE_FAX_HOME: {
+                parameterList.addAll(
+                        Arrays.asList(Constants.PARAM_TYPE_HOME, Constants.PARAM_TYPE_FAX));
+                break;
             }
-            break;
-        case Phone.TYPE_RADIO:
-        case Phone.TYPE_TTY_TDD:
-        default:
-            break;
+            case Phone.TYPE_FAX_WORK: {
+                parameterList.addAll(
+                        Arrays.asList(Constants.PARAM_TYPE_WORK, Constants.PARAM_TYPE_FAX));
+                break;
+            }
+            case Phone.TYPE_MOBILE: {
+                parameterList.add(Constants.PARAM_TYPE_CELL);
+                break;
+            }
+            case Phone.TYPE_PAGER: {
+                if (mIsDoCoMo) {
+                    // Not sure about the reason, but previous implementation had
+                    // used "VOICE" instead of "PAGER"
+                    parameterList.add(Constants.PARAM_TYPE_VOICE);
+                } else {
+                    parameterList.add(Constants.PARAM_TYPE_PAGER);
+                }
+                break;
+            }
+            case Phone.TYPE_OTHER: {
+                parameterList.add(Constants.PARAM_TYPE_VOICE);
+                break;
+            }
+            case Phone.TYPE_CAR: {
+                parameterList.add(Constants.PARAM_TYPE_CAR);
+                break;
+            }
+            case Phone.TYPE_COMPANY_MAIN: {
+                // There's no relevant field in vCard (at least 2.1).
+                parameterList.add(Constants.PARAM_TYPE_WORK);
+                isPrimary = true;
+                break;
+            }
+            case Phone.TYPE_ISDN: {
+                parameterList.add(Constants.PARAM_TYPE_ISDN);
+                break;
+            }
+            case Phone.TYPE_MAIN: {
+                isPrimary = true;
+                break;
+            }
+            case Phone.TYPE_OTHER_FAX: {
+                parameterList.add(Constants.PARAM_TYPE_FAX);
+                break;
+            }
+            case Phone.TYPE_TELEX: {
+                parameterList.add(Constants.PARAM_TYPE_TLX);
+                break;
+            }
+            case Phone.TYPE_WORK_MOBILE: {
+                parameterList.addAll(
+                        Arrays.asList(Constants.PARAM_TYPE_WORK, Constants.PARAM_TYPE_CELL));
+                break;
+            }
+            case Phone.TYPE_WORK_PAGER: {
+                parameterList.add(Constants.PARAM_TYPE_WORK);
+                // See above.
+                if (mIsDoCoMo) {
+                    parameterList.add(Constants.PARAM_TYPE_VOICE);
+                } else {
+                    parameterList.add(Constants.PARAM_TYPE_PAGER);
+                }
+                break;
+            }
+            case Phone.TYPE_MMS: {
+                parameterList.add(Constants.PARAM_TYPE_MSG);
+                break;
+            }
+            case Phone.TYPE_CUSTOM: {
+                if (TextUtils.isEmpty(label)) {
+                    // Just ignore the custom type.
+                    parameterList.add(Constants.PARAM_TYPE_VOICE);
+                } else if (VCardUtils.isMobilePhoneLabel(label)) {
+                    parameterList.add(Constants.PARAM_TYPE_CELL);
+                } else {
+                    final String upperLabel = label.toUpperCase();
+                    if (VCardUtils.isValidInV21ButUnknownToContactsPhoteType(upperLabel)) {
+                        parameterList.add(upperLabel);
+                    } else if (VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
+                        // Note: Strictly, vCard 2.1 does not allow "X-" parameter without
+                        //       "TYPE=" string.
+                        parameterList.add("X-" + label);
+                    }
+                }
+                break;
+            }
+            case Phone.TYPE_RADIO:
+            case Phone.TYPE_TTY_TDD:
+            default: {
+                break;
+            }
         }
 
         if (isPrimary) {
@@ -2069,7 +2089,7 @@
         }
 
         if (parameterList.isEmpty()) {
-            appendUncommonPhoneType(builder, typeAsPrimitive);
+            appendUncommonPhoneType(builder, type);
         } else {
             appendTypeParameters(builder, parameterList);
         }
@@ -2203,7 +2223,7 @@
             final String propertyName,
             final List<String> parameterList,
             final List<String> rawDataList, final boolean needCharset,
-            boolean needQuotedPrintable) {
+            final boolean needQuotedPrintable) {
         builder.append(propertyName);
         if (parameterList != null && parameterList.size() > 0) {
             builder.append(VCARD_PARAM_SEPARATOR);
@@ -2223,8 +2243,10 @@
                 builder.append(VCARD_PARAM_ENCODING_QP);
                 encodedData = encodeQuotedPrintable(rawData);
             } else {
-                // TODO: one line may be too huge, which may be invalid in vCard spec, though
-                //       several (even well-known) applications do not care this.
+                // 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.
                 encodedData = escapeCharacters(rawData);
             }
 
@@ -2305,7 +2327,7 @@
         }
         {
             // Replace "\n" and "\r" with "\r\n".
-            StringBuilder tmpBuilder = new StringBuilder();
+            final StringBuilder tmpBuilder = new StringBuilder();
             int length = str.length();
             for (int i = 0; i < length; i++) {
                 char ch = str.charAt(i);
diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java
index fff4c82..9a7fb21 100644
--- a/core/java/android/pim/vcard/VCardConfig.java
+++ b/core/java/android/pim/vcard/VCardConfig.java
@@ -159,17 +159,31 @@
 
     /**
      * <P>
-     * The flag indicating the vCard composer "for 2.1" emits "TYPE=" string every time
-     * possible. The default behavior does not emit it and is valid, while adding "TYPE="
-     * is also valid. In vCrad 3.0, this flag is unnecessary, since "TYPE=" is MUST in
-     * vCard 3.0 specification.
-     *
-     * If you are targeting to some importer which cannot accept type parameters
-     * without "TYPE=" string (which should be rare though), please use this flag.
-     *
-     * XXX: Really rare?
-     *
-     * e.g. int vcardType = (VCARD_TYPE_V21_GENERIC | FLAG_APPEND_TYPE_PARAM);
+     * The flag indicating the vCard composer "for 2.1" emits "TYPE=" string toward TYPE params
+     * every time possible. The default behavior does not emit it and is valid in the spec.
+     * In vCrad 3.0, this flag is unnecessary, since "TYPE=" is MUST in vCard 3.0 specification.
+     * </P>
+     * <P>
+     * Detail:
+     * How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0.
+     * </p>
+     * <P>
+     * e.g.<BR />
+     * 1) Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..."<BR />
+     * 2) Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."<BR />
+     * 3) Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."<BR />
+     * </P>
+     * <P>
+     * 2) had been the default of VCard exporter/importer in Android, but it is found that
+     * some external exporter is not able to parse the type format like 2) but only 3).
+     * </P>
+     * <P>
+     * If you are targeting to the importer which cannot accept TYPE params without "TYPE="
+     * strings (which should be rare though), please use this flag.
+     * </P>
+     * <P>
+     * Example usage: int vcardType = (VCARD_TYPE_V21_GENERIC | FLAG_APPEND_TYPE_PARAM);
+     * </P>
      */
     public static final int FLAG_APPEND_TYPE_PARAM = 0x04000000;
 
@@ -177,13 +191,13 @@
 
     /**
      * <P>
-     * General vCard format with the version 2.1. Uses UTF-8 for the charset.
+     * Generic vCard format with the vCard 2.1. Uses UTF-8 for the charset.
      * When composing a vCard entry, the US convension will be used toward formatting
-     * some values
+     * some values.
      * </P>
      * <P>
      * e.g. The order of the display name would be "Prefix Given Middle Family Suffix",
-     * while it should be "Prefix Family Middle Given Suffix" in Japan.
+     * while it should be "Prefix Family Middle Given Suffix" in Japan for example.
      * </P>
      */
     public static final int VCARD_TYPE_V21_GENERIC_UTF8 =
@@ -197,7 +211,7 @@
      * General vCard format with the version 3.0. Uses UTF-8 for the charset.
      * </P>
      * <P>
-     * Not ready yet. Use with caution when you use this.
+     * Not fully ready yet. Use with caution when you use this.
      * </P>
      */
     public static final int VCARD_TYPE_V30_GENERIC_UTF8 =
@@ -220,7 +234,7 @@
     
     /**
      * <P>
-     * General vCard format with the version 3.0 with some Europe convension. Uses UTF-8
+     * General vCard format with the version 3.0 with some Europe convension. Uses UTF-8.
      * </P>
      * <P>
      * Not ready yet. Use with caution when you use this.
@@ -407,6 +421,9 @@
      * applied to creating "formatted" something like FORMATTED_ADDRESS.
      */
     public static boolean isJapaneseDevice(final int vcardType) {
+        // TODO: Some mask will be required so that this method wrongly interpret
+        //        Japanese"-like" vCard type.
+        //        e.g. VCARD_TYPE_V21_JAPANESE_SJIS | FLAG_APPEND_TYPE_PARAMS
         return sJapaneseMobileTypeSet.contains(vcardType);
     }
 
diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/VCardEntry.java
similarity index 98%
rename from core/java/android/pim/vcard/ContactStruct.java
rename to core/java/android/pim/vcard/VCardEntry.java
index 530d5ad..c1b4c03 100644
--- a/core/java/android/pim/vcard/ContactStruct.java
+++ b/core/java/android/pim/vcard/VCardEntry.java
@@ -54,8 +54,11 @@
 /**
  * This class bridges between data structure of Contact app and VCard data.
  */
-public class ContactStruct {
-    private static final String LOG_TAG = "vcard.ContactStruct";
+public class VCardEntry {
+    private static final String LOG_TAG = "VCardEntry";
+
+    private static final String ACCOUNT_TYPE_GOOGLE = "com.google";
+    private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts";
 
     // Key: the name shown in VCard. e.g. "X-AIM", "X-ICQ"
     // Value: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
@@ -72,7 +75,7 @@
         sImMap.put(Constants.ImportOnly.PROPERTY_X_GOOGLE_TALK_WITH_SPACE,
                 Im.PROTOCOL_GOOGLE_TALK);
     }
-    
+
     static public class PhoneData {
         public final int type;
         public final String data;
@@ -448,15 +451,15 @@
     private final int mVCardType;
     private final Account mAccount;
 
-    public ContactStruct() {
+    public VCardEntry() {
         this(VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
     }
 
-    public ContactStruct(int vcardType) {
+    public VCardEntry(int vcardType) {
         this(vcardType, null);
     }
 
-    public ContactStruct(int vcardType, Account account) {
+    public VCardEntry(int vcardType, Account account) {
         mVCardType = vcardType;
         mAccount = account;
     }
@@ -921,16 +924,14 @@
         } else if (propName.equals(Constants.PROPERTY_X_SKYPE_PSTNNUMBER)) {
             // The phone number available via Skype.
             Collection<String> typeCollection = paramMap.get(Constants.PARAM_TYPE);
-            // XXX: should use TYPE_CUSTOM + the label "Skype"? (which may need localization)
-            int type = Phone.TYPE_OTHER;
-            final String label = null;
+            final int type = Phone.TYPE_OTHER;
             final boolean isPrimary;
             if (typeCollection != null && typeCollection.contains(Constants.PARAM_TYPE_PREF)) {
                 isPrimary = true;
             } else {
                 isPrimary = false;
             }
-            addPhone(type, propValue, label, isPrimary);
+            addPhone(type, propValue, null, isPrimary);
         } else if (sImMap.containsKey(propName)) {
             final int protocol = sImMap.get(propName);
             boolean isPrimary = false;
@@ -1045,10 +1046,6 @@
         }
     }
 
-    // From GoogleSource.java in Contacts app.
-    private static final String ACCOUNT_TYPE_GOOGLE = "com.google";
-    private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts";
-
     public void pushIntoContentResolver(ContentResolver resolver) {
         ArrayList<ContentProviderOperation> operationList =
             new ArrayList<ContentProviderOperation>();  
@@ -1060,7 +1057,6 @@
             builder.withValue(RawContacts.ACCOUNT_TYPE, mAccount.type);
 
             // Assume that caller side creates this group if it does not exist.
-            // TODO: refactor this code along with the change in GoogleSource.java
             if (ACCOUNT_TYPE_GOOGLE.equals(mAccount.type)) {
                 final Cursor cursor = resolver.query(Groups.CONTENT_URI, new String[] {
                         Groups.SOURCE_ID },
@@ -1293,11 +1289,11 @@
         }
     }
 
-    public static ContactStruct buildFromResolver(ContentResolver resolver) {
+    public static VCardEntry buildFromResolver(ContentResolver resolver) {
         return buildFromResolver(resolver, Contacts.CONTENT_URI);
     }
 
-    public static ContactStruct buildFromResolver(ContentResolver resolver, Uri uri) {
+    public static VCardEntry buildFromResolver(ContentResolver resolver, Uri uri) {
 
         return null;
     }
diff --git a/core/java/android/pim/vcard/EntryCommitter.java b/core/java/android/pim/vcard/VCardEntryCommitter.java
similarity index 70%
rename from core/java/android/pim/vcard/EntryCommitter.java
rename to core/java/android/pim/vcard/VCardEntryCommitter.java
index 3f1655d..a340cca 100644
--- a/core/java/android/pim/vcard/EntryCommitter.java
+++ b/core/java/android/pim/vcard/VCardEntryCommitter.java
@@ -19,28 +19,33 @@
 import android.util.Log;
 
 /**
- * EntryHandler implementation which commits the entry to Contacts Provider 
+ * EntryHandler implementation which commits the entry to ContentResolver.
+ *
+ * Note:
+ * Each vCard may contain big photo images encoded by BASE64,
+ * If we store all vCard entries in memory, OutOfMemoryError may be thrown.
+ * Thus, this class push each VCard entry into ContentResolver immediately.
  */
-public class EntryCommitter implements EntryHandler {
+public class VCardEntryCommitter implements VCardEntryHandler {
     public static String LOG_TAG = "vcard.EntryComitter";
 
     private ContentResolver mContentResolver;
     private long mTimeToCommit;
     
-    public EntryCommitter(ContentResolver resolver) {
+    public VCardEntryCommitter(ContentResolver resolver) {
         mContentResolver = resolver;
     }
 
-    public void onParsingStart() {
+    public void onStart() {
     }
     
-    public void onParsingEnd() {
+    public void onEnd() {
         if (VCardConfig.showPerformanceLog()) {
             Log.d(LOG_TAG, String.format("time to commit entries: %d ms", mTimeToCommit));
         }
     }
 
-    public void onEntryCreated(final ContactStruct contactStruct) {
+    public void onEntryCreated(final VCardEntry contactStruct) {
         long start = System.currentTimeMillis();
         contactStruct.pushIntoContentResolver(mContentResolver);
         mTimeToCommit += System.currentTimeMillis() - start;
diff --git a/core/java/android/pim/vcard/VCardDataBuilder.java b/core/java/android/pim/vcard/VCardEntryConstructor.java
similarity index 89%
rename from core/java/android/pim/vcard/VCardDataBuilder.java
rename to core/java/android/pim/vcard/VCardEntryConstructor.java
index 76ad482..e82c0c2 100644
--- a/core/java/android/pim/vcard/VCardDataBuilder.java
+++ b/core/java/android/pim/vcard/VCardEntryConstructor.java
@@ -30,23 +30,17 @@
 import java.util.Collection;
 import java.util.List;
 
-/**
- * VBuilder for VCard. VCard may contain big photo images encoded by BASE64,
- * If we store all VNode entries in memory like VDataBuilder.java,
- * OutOfMemoryError may be thrown. Thus, this class push each VCard entry into
- * ContentResolver immediately.
- */
-public class VCardDataBuilder implements VCardBuilder {
-    static private String LOG_TAG = "VCardDataBuilder"; 
+public class VCardEntryConstructor implements VCardInterpreter {
+    private static String LOG_TAG = "VCardEntryConstructor";
     
     /**
      * If there's no other information available, this class uses this charset for encoding
      * byte arrays.
      */
     static public String TARGET_CHARSET = "UTF-8"; 
-    
-    private ContactStruct.Property mCurrentProperty = new ContactStruct.Property();
-    private ContactStruct mCurrentContactStruct;
+
+    private VCardEntry.Property mCurrentProperty = new VCardEntry.Property();
+    private VCardEntry mCurrentContactStruct;
     private String mParamType;
     
     /**
@@ -66,23 +60,20 @@
     // Just for testing.
     private long mTimePushIntoContentResolver;
     
-    private List<EntryHandler> mEntryHandlers = new ArrayList<EntryHandler>();
+    private List<VCardEntryHandler> mEntryHandlers = new ArrayList<VCardEntryHandler>();
     
-    public VCardDataBuilder() {
+    public VCardEntryConstructor() {
         this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8, null);
     }
 
-    /**
-     * @hide 
-     */
-    public VCardDataBuilder(int vcardType) {
+    public VCardEntryConstructor(int vcardType) {
         this(null, null, false, vcardType, null);
     }
 
     /**
      * @hide 
      */
-    public VCardDataBuilder(String charset,
+    public VCardEntryConstructor(String charset,
             boolean strictLineBreakParsing, int vcardType, Account account) {
         this(null, charset, strictLineBreakParsing, vcardType, account);
     }
@@ -90,7 +81,7 @@
     /**
      * @hide
      */
-    public VCardDataBuilder(String sourceCharset,
+    public VCardEntryConstructor(String sourceCharset,
             String targetCharset,
             boolean strictLineBreakParsing,
             int vcardType,
@@ -109,20 +100,20 @@
         mVCardType = vcardType;
         mAccount = account;
     }
-    
-    public void addEntryHandler(EntryHandler entryHandler) {
+
+    public void addEntryHandler(VCardEntryHandler entryHandler) {
         mEntryHandlers.add(entryHandler);
     }
     
     public void start() {
-        for (EntryHandler entryHandler : mEntryHandlers) {
-            entryHandler.onParsingStart();
+        for (VCardEntryHandler entryHandler : mEntryHandlers) {
+            entryHandler.onStart();
         }
     }
 
     public void end() {
-        for (EntryHandler entryHandler : mEntryHandlers) {
-            entryHandler.onParsingEnd();
+        for (VCardEntryHandler entryHandler : mEntryHandlers) {
+            entryHandler.onEnd();
         }
     }
 
@@ -135,7 +126,7 @@
      */
     public void clear() {
         mCurrentContactStruct = null;
-        mCurrentProperty = new ContactStruct.Property();
+        mCurrentProperty = new VCardEntry.Property();
     }
 
     /**
@@ -153,12 +144,12 @@
             Log.e(LOG_TAG, "This is not VCARD!");
         }
 
-        mCurrentContactStruct = new ContactStruct(mVCardType, mAccount);
+        mCurrentContactStruct = new VCardEntry(mVCardType, mAccount);
     }
 
     public void endRecord() {
         mCurrentContactStruct.consolidateFields();
-        for (EntryHandler entryHandler : mEntryHandlers) {
+        for (VCardEntryHandler entryHandler : mEntryHandlers) {
             entryHandler.onEntryCreated(mCurrentContactStruct);
         }
         mCurrentContactStruct = null;
diff --git a/core/java/android/pim/vcard/VCardEntryCounter.java b/core/java/android/pim/vcard/VCardEntryCounter.java
index f99b46c..1c221eb 100644
--- a/core/java/android/pim/vcard/VCardEntryCounter.java
+++ b/core/java/android/pim/vcard/VCardEntryCounter.java
@@ -17,16 +17,16 @@
 
 import java.util.List;
 
-public class VCardEntryCounter implements VCardBuilder {
+public class VCardEntryCounter implements VCardInterpreter {
     private int mCount;
-    
+
     public int getCount() {
         return mCount;
     }
-    
+
     public void start() {
     }
-    
+
     public void end() {
     }
 
@@ -36,10 +36,10 @@
     public void endRecord() {
         mCount++;
     }
-    
+
     public void startProperty() {
     }
-    
+
     public void endProperty() {
     }
 
diff --git a/core/java/android/pim/vcard/EntryHandler.java b/core/java/android/pim/vcard/VCardEntryHandler.java
similarity index 73%
rename from core/java/android/pim/vcard/EntryHandler.java
rename to core/java/android/pim/vcard/VCardEntryHandler.java
index 7fb8114..3b6bad5 100644
--- a/core/java/android/pim/vcard/EntryHandler.java
+++ b/core/java/android/pim/vcard/VCardEntryHandler.java
@@ -15,24 +15,20 @@
  */
 package android.pim.vcard;
 
-/**
- * Unlike {@link VCardBuilder}, this (and {@link VCardDataBuilder}) assumes
- * "each VCard entry should be correctly parsed and passed to each EntryHandler object",
- */
-public interface EntryHandler {
+public interface VCardEntryHandler {
     /**
      * Called when the parsing started.
      */
-    public void onParsingStart();
+    public void onStart();
 
     /**
      * The method called when one VCard entry is successfully created
      */
-    public void onEntryCreated(final ContactStruct entry);
+    public void onEntryCreated(final VCardEntry entry);
 
     /**
      * Called when the parsing ended.
      * Able to be use this method for showing performance log, etc.
      */
-    public void onParsingEnd();
+    public void onEnd();
 }
diff --git a/core/java/android/pim/vcard/VCardBuilderCollection.java b/core/java/android/pim/vcard/VCardInterPreterCollection.java
similarity index 64%
rename from core/java/android/pim/vcard/VCardBuilderCollection.java
rename to core/java/android/pim/vcard/VCardInterPreterCollection.java
index e3985b6..19f0406 100644
--- a/core/java/android/pim/vcard/VCardBuilderCollection.java
+++ b/core/java/android/pim/vcard/VCardInterPreterCollection.java
@@ -18,81 +18,81 @@
 import java.util.Collection;
 import java.util.List;
 
-public class VCardBuilderCollection implements VCardBuilder {
+public class VCardInterPreterCollection implements VCardInterpreter {
 
-    private final Collection<VCardBuilder> mVCardBuilderCollection;
+    private final Collection<VCardInterpreter> mVCardBuilderCollection;
     
-    public VCardBuilderCollection(Collection<VCardBuilder> vBuilderCollection) {
+    public VCardInterPreterCollection(Collection<VCardInterpreter> vBuilderCollection) {
         mVCardBuilderCollection = vBuilderCollection; 
     }
     
-    public Collection<VCardBuilder> getVCardBuilderBaseCollection() {
+    public Collection<VCardInterpreter> getCollection() {
         return mVCardBuilderCollection;
     }
     
     public void start() {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.start();
         }
     }
     
     public void end() {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.end();
         }
     }
 
     public void startRecord(String type) {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.startRecord(type);
         }
     }
     
     public void endRecord() {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.endRecord();
         }
     }
 
     public void startProperty() {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.startProperty();
         }
     }
 
     
     public void endProperty() {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.endProperty();
         }
     }
 
     public void propertyGroup(String group) {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.propertyGroup(group);
         }
     }
 
     public void propertyName(String name) {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.propertyName(name);
         }
     }
 
     public void propertyParamType(String type) {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.propertyParamType(type);
         }
     }
 
     public void propertyParamValue(String value) {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.propertyParamValue(value);
         }
     }
 
     public void propertyValues(List<String> values) {
-        for (VCardBuilder builder : mVCardBuilderCollection) {
+        for (VCardInterpreter builder : mVCardBuilderCollection) {
             builder.propertyValues(values);
         }
     }
diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardInterpreter.java
similarity index 95%
rename from core/java/android/pim/vcard/VCardBuilder.java
rename to core/java/android/pim/vcard/VCardInterpreter.java
index e1c4b33..1f2408d 100644
--- a/core/java/android/pim/vcard/VCardBuilder.java
+++ b/core/java/android/pim/vcard/VCardInterpreter.java
@@ -17,7 +17,7 @@
 
 import java.util.List;
 
-public interface VCardBuilder {
+public interface VCardInterpreter {
     void start();
 
     void end();
@@ -27,7 +27,7 @@
      */
     void startRecord(String type);
 
-    /** END:VXX */
+    /** END:VCARD */
     void endRecord();
 
     void startProperty();
diff --git a/core/java/android/pim/vcard/VCardParser.java b/core/java/android/pim/vcard/VCardParser.java
index 462e22c..44c6fcd 100644
--- a/core/java/android/pim/vcard/VCardParser.java
+++ b/core/java/android/pim/vcard/VCardParser.java
@@ -64,7 +64,7 @@
      * @return Returns true for success. Otherwise returns false.
      * @throws IOException, VCardException
      */
-    public abstract boolean parse(InputStream is, VCardBuilder builder)
+    public abstract boolean parse(InputStream is, VCardInterpreter builder)
             throws IOException, VCardException;
     
     /**
@@ -82,7 +82,7 @@
      * @return Returns true when successful. Otherwise returns false.
      * @throws IOException, VCardException
      */
-    public abstract boolean parse(InputStream is, String charset, VCardBuilder builder)
+    public abstract boolean parse(InputStream is, String charset, VCardInterpreter builder)
             throws IOException, VCardException;
     
     /**
@@ -91,7 +91,7 @@
      * @hide 
      */
     public abstract void parse(InputStream is, String charset,
-            VCardBuilder builder, boolean canceled)
+            VCardInterpreter builder, boolean canceled)
         throws IOException, VCardException;
     
     /**
diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java
index 251db68..3bbf698 100644
--- a/core/java/android/pim/vcard/VCardParser_V21.java
+++ b/core/java/android/pim/vcard/VCardParser_V21.java
@@ -72,7 +72,7 @@
     private String mPreviousLine;
     
     /** The builder to build parsed data */
-    protected VCardBuilder mBuilder = null;
+    protected VCardInterpreter mBuilder = null;
 
     /** 
      * The encoding type. "Encoding" in vCard is different from "Charset".
@@ -876,13 +876,13 @@
     }
     
     @Override
-    public boolean parse(final InputStream is, final VCardBuilder builder)
+    public boolean parse(final InputStream is, final VCardInterpreter builder)
             throws IOException, VCardException {
         return parse(is, VCardConfig.DEFAULT_CHARSET, builder);
     }
     
     @Override
-    public boolean parse(InputStream is, String charset, VCardBuilder builder)
+    public boolean parse(InputStream is, String charset, VCardInterpreter builder)
             throws IOException, VCardException {
         if (charset == null) {
             charset = VCardConfig.DEFAULT_CHARSET;
@@ -914,7 +914,7 @@
     }
     
     @Override
-    public void parse(InputStream is, String charset, VCardBuilder builder, boolean canceled)
+    public void parse(InputStream is, String charset, VCardInterpreter builder, boolean canceled)
             throws IOException, VCardException {
         mCanceled = canceled;
         parse(is, charset, builder);
diff --git a/core/java/android/pim/vcard/VCardSourceDetector.java b/core/java/android/pim/vcard/VCardSourceDetector.java
index 7e2be2b..01c1300 100644
--- a/core/java/android/pim/vcard/VCardSourceDetector.java
+++ b/core/java/android/pim/vcard/VCardSourceDetector.java
@@ -25,7 +25,7 @@
  * Currently this implementation is very premature.
  * @hide
  */
-public class VCardSourceDetector implements VCardBuilder {
+public class VCardSourceDetector implements VCardInterpreter {
     // Should only be used in package. 
     static final int TYPE_UNKNOWN = 0;
     static final int TYPE_APPLE = 1;
diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java
index 00679bd..d1e1ec3 100644
--- a/core/java/android/pim/vcard/VCardUtils.java
+++ b/core/java/android/pim/vcard/VCardUtils.java
@@ -23,9 +23,9 @@
 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;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -37,19 +37,14 @@
  * Utilities for VCard handling codes.
  */
 public class VCardUtils {
-    /*
-     * TODO: some of methods in this class should be placed to the more appropriate place...
-     */
-
     // Note that not all types are included in this map/set, since, for example, TYPE_HOME_FAX is
     // converted to two parameter Strings. These only contain some minor fields valid in both
     // vCard and current (as of 2009-08-07) Contacts structure. 
     private static final Map<Integer, String> sKnownPhoneTypesMap_ItoS;
-    private static final Set<String> sPhoneTypesSetUnknownToContacts;
-
+    private static final Set<String> sPhoneTypesUnknownToContactsSet;
     private static final Map<String, Integer> sKnownPhoneTypeMap_StoI;
-
     private static final Map<Integer, String> sKnownImPropNameMap_ItoS;
+    private static final Set<String> sMobilePhoneLabelSet;
 
     static {
         sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>();
@@ -75,10 +70,10 @@
         sKnownPhoneTypeMap_StoI.put(Constants.PARAM_PHONE_EXTRA_TYPE_ASSISTANT,
                 Phone.TYPE_ASSISTANT);
 
-        sPhoneTypesSetUnknownToContacts = new HashSet<String>();
-        sPhoneTypesSetUnknownToContacts.add(Constants.PARAM_TYPE_MODEM);
-        sPhoneTypesSetUnknownToContacts.add(Constants.PARAM_TYPE_BBS);
-        sPhoneTypesSetUnknownToContacts.add(Constants.PARAM_TYPE_VIDEO);
+        sPhoneTypesUnknownToContactsSet = new HashSet<String>();
+        sPhoneTypesUnknownToContactsSet.add(Constants.PARAM_TYPE_MODEM);
+        sPhoneTypesUnknownToContactsSet.add(Constants.PARAM_TYPE_BBS);
+        sPhoneTypesUnknownToContactsSet.add(Constants.PARAM_TYPE_VIDEO);
 
         sKnownImPropNameMap_ItoS = new HashMap<Integer, String>();
         sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_AIM, Constants.PROPERTY_X_AIM);
@@ -90,6 +85,14 @@
         sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_JABBER, Constants.PROPERTY_X_JABBER);
         sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_QQ, Constants.PROPERTY_X_QQ);
         sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_NETMEETING, Constants.PROPERTY_X_NETMEETING);
+
+        // \u643A\u5E2F\u96FB\u8A71 = Full-width Hiragana "Keitai-Denwa" (mobile phone)
+        // \u643A\u5E2F = Full-width Hiragana "Keitai" (mobile phone)
+        // \u30B1\u30A4\u30BF\u30A4 = Full-width Katakana "Keitai" (mobile phone)
+        // \uFF79\uFF72\uFF80\uFF72 = Half-width Katakana "Keitai" (mobile phone)
+        sMobilePhoneLabelSet = new HashSet<String>(Arrays.asList(
+                "MOBILE", "\u643A\u5E2F\u96FB\u8A71", "\u643A\u5E2F", "\u30B1\u30A4\u30BF\u30A4",
+                "\uFF79\uFF72\uFF80\uFF72"));
     }
 
     public static String getPhoneTypeString(Integer type) {
@@ -112,7 +115,10 @@
         
         if (types != null) {
             for (String typeString : types) {
-                typeString = typeString.toUpperCase(); 
+                if (typeString == null) {
+                    continue;
+                }
+                typeString = typeString.toUpperCase();
                 if (typeString.equals(Constants.PARAM_TYPE_PREF)) {
                     hasPref = true;
                 } else if (typeString.equals(Constants.PARAM_TYPE_FAX)) {
@@ -121,7 +127,10 @@
                     if (typeString.startsWith("X-") && type < 0) {
                         typeString = typeString.substring(2);
                     }
-                    Integer tmp = sKnownPhoneTypeMap_StoI.get(typeString);
+                    if (typeString.length() == 0) {
+                        continue;
+                    }
+                    final Integer tmp = sKnownPhoneTypeMap_StoI.get(typeString);
                     if (tmp != null) {
                         final int typeCandidate = tmp;
                         // TYPE_PAGER is prefered when the number contains @ surronded by
@@ -168,20 +177,23 @@
         }
     }
 
-    public static String getPropertyNameForIm(int protocol) {
+    @SuppressWarnings("deprecation")
+    public static boolean isMobilePhoneLabel(final String label) {
+        // For backward compatibility.
+        // Detail: Until Donut, there isn't TYPE_MOBILE for email while there is now.
+        //         To support mobile type at that time, this custom label had been used.
+        return (android.provider.Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME.equals(label)
+                || sMobilePhoneLabelSet.contains(label));
+    }
+
+    public static boolean isValidInV21ButUnknownToContactsPhoteType(final String label) {
+        return sPhoneTypesUnknownToContactsSet.contains(label);
+    }
+
+    public static String getPropertyNameForIm(final int protocol) {
         return sKnownImPropNameMap_ItoS.get(protocol);
     }
 
-    public static boolean isValidPhoneType(String phoneType, int vcardType) {
-        // TODO: check the following.
-        // - it may violate vCard spec
-        // - it may contain non-ASCII characters
-        //
-        // TODO: use vcardType
-        return (phoneType.startsWith("X-") || phoneType.startsWith("x-") ||
-                sPhoneTypesSetUnknownToContacts.contains(phoneType));
-    }
-    
     public static String[] sortNameElements(final int vcardType,
             final String familyName, final String middleName, final String givenName) {
         final String[] list = new String[3];
@@ -233,7 +245,7 @@
      */
     public static void insertStructuredPostalDataUsingContactsStruct(int vcardType,
             final ContentProviderOperation.Builder builder,
-            final ContactStruct.PostalData postalData) {
+            final VCardEntry.PostalData postalData) {
         builder.withValueBackReference(StructuredPostal.RAW_CONTACT_ID, 0);
         builder.withValue(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
 
@@ -269,7 +281,7 @@
      * So some conversion may be performed in this method. See also
      * {{@link #insertStructuredPostalDataUsingContactsStruct(int,
      * android.content.ContentProviderOperation.Builder,
-     * android.pim.vcard.ContactStruct.PostalData)}
+     * android.pim.vcard.VCardEntry.PostalData)}
      */
     public static String[] getVCardPostalElements(ContentValues contentValues) {
         // adr-value    = 0*6(text-value ";") text-value
@@ -517,364 +529,3 @@
     private VCardUtils() {
     }
 }
-
-/**
- * TextUtils especially for Japanese.
- * TODO: make this in android.text in the future
- */
-class JapaneseUtils {
-    static private final Map<Character, String> sHalfWidthMap =
-        new HashMap<Character, String>();
-
-    static {
-        // There's no logical mapping rule in Unicode. Sigh.
-        sHalfWidthMap.put('\u3001', "\uFF64");
-        sHalfWidthMap.put('\u3002', "\uFF61");
-        sHalfWidthMap.put('\u300C', "\uFF62");
-        sHalfWidthMap.put('\u300D', "\uFF63");
-        sHalfWidthMap.put('\u301C', "~");
-        sHalfWidthMap.put('\u3041', "\uFF67");
-        sHalfWidthMap.put('\u3042', "\uFF71");
-        sHalfWidthMap.put('\u3043', "\uFF68");
-        sHalfWidthMap.put('\u3044', "\uFF72");
-        sHalfWidthMap.put('\u3045', "\uFF69");
-        sHalfWidthMap.put('\u3046', "\uFF73");
-        sHalfWidthMap.put('\u3047', "\uFF6A");
-        sHalfWidthMap.put('\u3048', "\uFF74");
-        sHalfWidthMap.put('\u3049', "\uFF6B");
-        sHalfWidthMap.put('\u304A', "\uFF75");
-        sHalfWidthMap.put('\u304B', "\uFF76");
-        sHalfWidthMap.put('\u304C', "\uFF76\uFF9E");
-        sHalfWidthMap.put('\u304D', "\uFF77");
-        sHalfWidthMap.put('\u304E', "\uFF77\uFF9E");
-        sHalfWidthMap.put('\u304F', "\uFF78");
-        sHalfWidthMap.put('\u3050', "\uFF78\uFF9E");
-        sHalfWidthMap.put('\u3051', "\uFF79");
-        sHalfWidthMap.put('\u3052', "\uFF79\uFF9E");
-        sHalfWidthMap.put('\u3053', "\uFF7A");
-        sHalfWidthMap.put('\u3054', "\uFF7A\uFF9E");
-        sHalfWidthMap.put('\u3055', "\uFF7B");
-        sHalfWidthMap.put('\u3056', "\uFF7B\uFF9E");
-        sHalfWidthMap.put('\u3057', "\uFF7C");
-        sHalfWidthMap.put('\u3058', "\uFF7C\uFF9E");
-        sHalfWidthMap.put('\u3059', "\uFF7D");
-        sHalfWidthMap.put('\u305A', "\uFF7D\uFF9E");
-        sHalfWidthMap.put('\u305B', "\uFF7E");
-        sHalfWidthMap.put('\u305C', "\uFF7E\uFF9E");
-        sHalfWidthMap.put('\u305D', "\uFF7F");
-        sHalfWidthMap.put('\u305E', "\uFF7F\uFF9E");
-        sHalfWidthMap.put('\u305F', "\uFF80");
-        sHalfWidthMap.put('\u3060', "\uFF80\uFF9E");
-        sHalfWidthMap.put('\u3061', "\uFF81");
-        sHalfWidthMap.put('\u3062', "\uFF81\uFF9E");
-        sHalfWidthMap.put('\u3063', "\uFF6F");
-        sHalfWidthMap.put('\u3064', "\uFF82");
-        sHalfWidthMap.put('\u3065', "\uFF82\uFF9E");
-        sHalfWidthMap.put('\u3066', "\uFF83");
-        sHalfWidthMap.put('\u3067', "\uFF83\uFF9E");
-        sHalfWidthMap.put('\u3068', "\uFF84");
-        sHalfWidthMap.put('\u3069', "\uFF84\uFF9E");
-        sHalfWidthMap.put('\u306A', "\uFF85");
-        sHalfWidthMap.put('\u306B', "\uFF86");
-        sHalfWidthMap.put('\u306C', "\uFF87");
-        sHalfWidthMap.put('\u306D', "\uFF88");
-        sHalfWidthMap.put('\u306E', "\uFF89");
-        sHalfWidthMap.put('\u306F', "\uFF8A");
-        sHalfWidthMap.put('\u3070', "\uFF8A\uFF9E");
-        sHalfWidthMap.put('\u3071', "\uFF8A\uFF9F");
-        sHalfWidthMap.put('\u3072', "\uFF8B");
-        sHalfWidthMap.put('\u3073', "\uFF8B\uFF9E");
-        sHalfWidthMap.put('\u3074', "\uFF8B\uFF9F");
-        sHalfWidthMap.put('\u3075', "\uFF8C");
-        sHalfWidthMap.put('\u3076', "\uFF8C\uFF9E");
-        sHalfWidthMap.put('\u3077', "\uFF8C\uFF9F");
-        sHalfWidthMap.put('\u3078', "\uFF8D");
-        sHalfWidthMap.put('\u3079', "\uFF8D\uFF9E");
-        sHalfWidthMap.put('\u307A', "\uFF8D\uFF9F");
-        sHalfWidthMap.put('\u307B', "\uFF8E");
-        sHalfWidthMap.put('\u307C', "\uFF8E\uFF9E");
-        sHalfWidthMap.put('\u307D', "\uFF8E\uFF9F");
-        sHalfWidthMap.put('\u307E', "\uFF8F");
-        sHalfWidthMap.put('\u307F', "\uFF90");
-        sHalfWidthMap.put('\u3080', "\uFF91");
-        sHalfWidthMap.put('\u3081', "\uFF92");
-        sHalfWidthMap.put('\u3082', "\uFF93");
-        sHalfWidthMap.put('\u3083', "\uFF6C");
-        sHalfWidthMap.put('\u3084', "\uFF94");
-        sHalfWidthMap.put('\u3085', "\uFF6D");
-        sHalfWidthMap.put('\u3086', "\uFF95");
-        sHalfWidthMap.put('\u3087', "\uFF6E");
-        sHalfWidthMap.put('\u3088', "\uFF96");
-        sHalfWidthMap.put('\u3089', "\uFF97");
-        sHalfWidthMap.put('\u308A', "\uFF98");
-        sHalfWidthMap.put('\u308B', "\uFF99");
-        sHalfWidthMap.put('\u308C', "\uFF9A");
-        sHalfWidthMap.put('\u308D', "\uFF9B");
-        sHalfWidthMap.put('\u308E', "\uFF9C");
-        sHalfWidthMap.put('\u308F', "\uFF9C");
-        sHalfWidthMap.put('\u3090', "\uFF72");
-        sHalfWidthMap.put('\u3091', "\uFF74");
-        sHalfWidthMap.put('\u3092', "\uFF66");
-        sHalfWidthMap.put('\u3093', "\uFF9D");
-        sHalfWidthMap.put('\u309B', "\uFF9E");
-        sHalfWidthMap.put('\u309C', "\uFF9F");
-        sHalfWidthMap.put('\u30A1', "\uFF67");
-        sHalfWidthMap.put('\u30A2', "\uFF71");
-        sHalfWidthMap.put('\u30A3', "\uFF68");
-        sHalfWidthMap.put('\u30A4', "\uFF72");
-        sHalfWidthMap.put('\u30A5', "\uFF69");
-        sHalfWidthMap.put('\u30A6', "\uFF73");
-        sHalfWidthMap.put('\u30A7', "\uFF6A");
-        sHalfWidthMap.put('\u30A8', "\uFF74");
-        sHalfWidthMap.put('\u30A9', "\uFF6B");
-        sHalfWidthMap.put('\u30AA', "\uFF75");
-        sHalfWidthMap.put('\u30AB', "\uFF76");
-        sHalfWidthMap.put('\u30AC', "\uFF76\uFF9E");
-        sHalfWidthMap.put('\u30AD', "\uFF77");
-        sHalfWidthMap.put('\u30AE', "\uFF77\uFF9E");
-        sHalfWidthMap.put('\u30AF', "\uFF78");
-        sHalfWidthMap.put('\u30B0', "\uFF78\uFF9E");
-        sHalfWidthMap.put('\u30B1', "\uFF79");
-        sHalfWidthMap.put('\u30B2', "\uFF79\uFF9E");
-        sHalfWidthMap.put('\u30B3', "\uFF7A");
-        sHalfWidthMap.put('\u30B4', "\uFF7A\uFF9E");
-        sHalfWidthMap.put('\u30B5', "\uFF7B");
-        sHalfWidthMap.put('\u30B6', "\uFF7B\uFF9E");
-        sHalfWidthMap.put('\u30B7', "\uFF7C");
-        sHalfWidthMap.put('\u30B8', "\uFF7C\uFF9E");
-        sHalfWidthMap.put('\u30B9', "\uFF7D");
-        sHalfWidthMap.put('\u30BA', "\uFF7D\uFF9E");
-        sHalfWidthMap.put('\u30BB', "\uFF7E");
-        sHalfWidthMap.put('\u30BC', "\uFF7E\uFF9E");
-        sHalfWidthMap.put('\u30BD', "\uFF7F");
-        sHalfWidthMap.put('\u30BE', "\uFF7F\uFF9E");
-        sHalfWidthMap.put('\u30BF', "\uFF80");
-        sHalfWidthMap.put('\u30C0', "\uFF80\uFF9E");
-        sHalfWidthMap.put('\u30C1', "\uFF81");
-        sHalfWidthMap.put('\u30C2', "\uFF81\uFF9E");
-        sHalfWidthMap.put('\u30C3', "\uFF6F");
-        sHalfWidthMap.put('\u30C4', "\uFF82");
-        sHalfWidthMap.put('\u30C5', "\uFF82\uFF9E");
-        sHalfWidthMap.put('\u30C6', "\uFF83");
-        sHalfWidthMap.put('\u30C7', "\uFF83\uFF9E");
-        sHalfWidthMap.put('\u30C8', "\uFF84");
-        sHalfWidthMap.put('\u30C9', "\uFF84\uFF9E");
-        sHalfWidthMap.put('\u30CA', "\uFF85");
-        sHalfWidthMap.put('\u30CB', "\uFF86");
-        sHalfWidthMap.put('\u30CC', "\uFF87");
-        sHalfWidthMap.put('\u30CD', "\uFF88");
-        sHalfWidthMap.put('\u30CE', "\uFF89");
-        sHalfWidthMap.put('\u30CF', "\uFF8A");
-        sHalfWidthMap.put('\u30D0', "\uFF8A\uFF9E");
-        sHalfWidthMap.put('\u30D1', "\uFF8A\uFF9F");
-        sHalfWidthMap.put('\u30D2', "\uFF8B");
-        sHalfWidthMap.put('\u30D3', "\uFF8B\uFF9E");
-        sHalfWidthMap.put('\u30D4', "\uFF8B\uFF9F");
-        sHalfWidthMap.put('\u30D5', "\uFF8C");
-        sHalfWidthMap.put('\u30D6', "\uFF8C\uFF9E");
-        sHalfWidthMap.put('\u30D7', "\uFF8C\uFF9F");
-        sHalfWidthMap.put('\u30D8', "\uFF8D");
-        sHalfWidthMap.put('\u30D9', "\uFF8D\uFF9E");
-        sHalfWidthMap.put('\u30DA', "\uFF8D\uFF9F");
-        sHalfWidthMap.put('\u30DB', "\uFF8E");
-        sHalfWidthMap.put('\u30DC', "\uFF8E\uFF9E");
-        sHalfWidthMap.put('\u30DD', "\uFF8E\uFF9F");
-        sHalfWidthMap.put('\u30DE', "\uFF8F");
-        sHalfWidthMap.put('\u30DF', "\uFF90");
-        sHalfWidthMap.put('\u30E0', "\uFF91");
-        sHalfWidthMap.put('\u30E1', "\uFF92");
-        sHalfWidthMap.put('\u30E2', "\uFF93");
-        sHalfWidthMap.put('\u30E3', "\uFF6C");
-        sHalfWidthMap.put('\u30E4', "\uFF94");
-        sHalfWidthMap.put('\u30E5', "\uFF6D");
-        sHalfWidthMap.put('\u30E6', "\uFF95");
-        sHalfWidthMap.put('\u30E7', "\uFF6E");
-        sHalfWidthMap.put('\u30E8', "\uFF96");
-        sHalfWidthMap.put('\u30E9', "\uFF97");
-        sHalfWidthMap.put('\u30EA', "\uFF98");
-        sHalfWidthMap.put('\u30EB', "\uFF99");
-        sHalfWidthMap.put('\u30EC', "\uFF9A");
-        sHalfWidthMap.put('\u30ED', "\uFF9B");
-        sHalfWidthMap.put('\u30EE', "\uFF9C");
-        sHalfWidthMap.put('\u30EF', "\uFF9C");
-        sHalfWidthMap.put('\u30F0', "\uFF72");
-        sHalfWidthMap.put('\u30F1', "\uFF74");
-        sHalfWidthMap.put('\u30F2', "\uFF66");
-        sHalfWidthMap.put('\u30F3', "\uFF9D");
-        sHalfWidthMap.put('\u30F4', "\uFF73\uFF9E");
-        sHalfWidthMap.put('\u30F5', "\uFF76");
-        sHalfWidthMap.put('\u30F6', "\uFF79");
-        sHalfWidthMap.put('\u30FB', "\uFF65");
-        sHalfWidthMap.put('\u30FC', "\uFF70");
-        sHalfWidthMap.put('\uFF01', "!");
-        sHalfWidthMap.put('\uFF02', "\"");
-        sHalfWidthMap.put('\uFF03', "#");
-        sHalfWidthMap.put('\uFF04', "$");
-        sHalfWidthMap.put('\uFF05', "%");
-        sHalfWidthMap.put('\uFF06', "&");
-        sHalfWidthMap.put('\uFF07', "'");
-        sHalfWidthMap.put('\uFF08', "(");
-        sHalfWidthMap.put('\uFF09', ")");
-        sHalfWidthMap.put('\uFF0A', "*");
-        sHalfWidthMap.put('\uFF0B', "+");
-        sHalfWidthMap.put('\uFF0C', ",");
-        sHalfWidthMap.put('\uFF0D', "-");
-        sHalfWidthMap.put('\uFF0E', ".");
-        sHalfWidthMap.put('\uFF0F', "/");
-        sHalfWidthMap.put('\uFF10', "0");
-        sHalfWidthMap.put('\uFF11', "1");
-        sHalfWidthMap.put('\uFF12', "2");
-        sHalfWidthMap.put('\uFF13', "3");
-        sHalfWidthMap.put('\uFF14', "4");
-        sHalfWidthMap.put('\uFF15', "5");
-        sHalfWidthMap.put('\uFF16', "6");
-        sHalfWidthMap.put('\uFF17', "7");
-        sHalfWidthMap.put('\uFF18', "8");
-        sHalfWidthMap.put('\uFF19', "9");
-        sHalfWidthMap.put('\uFF1A', ":");
-        sHalfWidthMap.put('\uFF1B', ";");
-        sHalfWidthMap.put('\uFF1C', "<");
-        sHalfWidthMap.put('\uFF1D', "=");
-        sHalfWidthMap.put('\uFF1E', ">");
-        sHalfWidthMap.put('\uFF1F', "?");
-        sHalfWidthMap.put('\uFF20', "@");
-        sHalfWidthMap.put('\uFF21', "A");
-        sHalfWidthMap.put('\uFF22', "B");
-        sHalfWidthMap.put('\uFF23', "C");
-        sHalfWidthMap.put('\uFF24', "D");
-        sHalfWidthMap.put('\uFF25', "E");
-        sHalfWidthMap.put('\uFF26', "F");
-        sHalfWidthMap.put('\uFF27', "G");
-        sHalfWidthMap.put('\uFF28', "H");
-        sHalfWidthMap.put('\uFF29', "I");
-        sHalfWidthMap.put('\uFF2A', "J");
-        sHalfWidthMap.put('\uFF2B', "K");
-        sHalfWidthMap.put('\uFF2C', "L");
-        sHalfWidthMap.put('\uFF2D', "M");
-        sHalfWidthMap.put('\uFF2E', "N");
-        sHalfWidthMap.put('\uFF2F', "O");
-        sHalfWidthMap.put('\uFF30', "P");
-        sHalfWidthMap.put('\uFF31', "Q");
-        sHalfWidthMap.put('\uFF32', "R");
-        sHalfWidthMap.put('\uFF33', "S");
-        sHalfWidthMap.put('\uFF34', "T");
-        sHalfWidthMap.put('\uFF35', "U");
-        sHalfWidthMap.put('\uFF36', "V");
-        sHalfWidthMap.put('\uFF37', "W");
-        sHalfWidthMap.put('\uFF38', "X");
-        sHalfWidthMap.put('\uFF39', "Y");
-        sHalfWidthMap.put('\uFF3A', "Z");
-        sHalfWidthMap.put('\uFF3B', "[");
-        sHalfWidthMap.put('\uFF3C', "\\");
-        sHalfWidthMap.put('\uFF3D', "]");
-        sHalfWidthMap.put('\uFF3E', "^");
-        sHalfWidthMap.put('\uFF3F', "_");
-        sHalfWidthMap.put('\uFF41', "a");
-        sHalfWidthMap.put('\uFF42', "b");
-        sHalfWidthMap.put('\uFF43', "c");
-        sHalfWidthMap.put('\uFF44', "d");
-        sHalfWidthMap.put('\uFF45', "e");
-        sHalfWidthMap.put('\uFF46', "f");
-        sHalfWidthMap.put('\uFF47', "g");
-        sHalfWidthMap.put('\uFF48', "h");
-        sHalfWidthMap.put('\uFF49', "i");
-        sHalfWidthMap.put('\uFF4A', "j");
-        sHalfWidthMap.put('\uFF4B', "k");
-        sHalfWidthMap.put('\uFF4C', "l");
-        sHalfWidthMap.put('\uFF4D', "m");
-        sHalfWidthMap.put('\uFF4E', "n");
-        sHalfWidthMap.put('\uFF4F', "o");
-        sHalfWidthMap.put('\uFF50', "p");
-        sHalfWidthMap.put('\uFF51', "q");
-        sHalfWidthMap.put('\uFF52', "r");
-        sHalfWidthMap.put('\uFF53', "s");
-        sHalfWidthMap.put('\uFF54', "t");
-        sHalfWidthMap.put('\uFF55', "u");
-        sHalfWidthMap.put('\uFF56', "v");
-        sHalfWidthMap.put('\uFF57', "w");
-        sHalfWidthMap.put('\uFF58', "x");
-        sHalfWidthMap.put('\uFF59', "y");
-        sHalfWidthMap.put('\uFF5A', "z");
-        sHalfWidthMap.put('\uFF5B', "{");
-        sHalfWidthMap.put('\uFF5C', "|");
-        sHalfWidthMap.put('\uFF5D', "}");
-        sHalfWidthMap.put('\uFF5E', "~");
-        sHalfWidthMap.put('\uFF61', "\uFF61");
-        sHalfWidthMap.put('\uFF62', "\uFF62");
-        sHalfWidthMap.put('\uFF63', "\uFF63");
-        sHalfWidthMap.put('\uFF64', "\uFF64");
-        sHalfWidthMap.put('\uFF65', "\uFF65");
-        sHalfWidthMap.put('\uFF66', "\uFF66");
-        sHalfWidthMap.put('\uFF67', "\uFF67");
-        sHalfWidthMap.put('\uFF68', "\uFF68");
-        sHalfWidthMap.put('\uFF69', "\uFF69");
-        sHalfWidthMap.put('\uFF6A', "\uFF6A");
-        sHalfWidthMap.put('\uFF6B', "\uFF6B");
-        sHalfWidthMap.put('\uFF6C', "\uFF6C");
-        sHalfWidthMap.put('\uFF6D', "\uFF6D");
-        sHalfWidthMap.put('\uFF6E', "\uFF6E");
-        sHalfWidthMap.put('\uFF6F', "\uFF6F");
-        sHalfWidthMap.put('\uFF70', "\uFF70");
-        sHalfWidthMap.put('\uFF71', "\uFF71");
-        sHalfWidthMap.put('\uFF72', "\uFF72");
-        sHalfWidthMap.put('\uFF73', "\uFF73");
-        sHalfWidthMap.put('\uFF74', "\uFF74");
-        sHalfWidthMap.put('\uFF75', "\uFF75");
-        sHalfWidthMap.put('\uFF76', "\uFF76");
-        sHalfWidthMap.put('\uFF77', "\uFF77");
-        sHalfWidthMap.put('\uFF78', "\uFF78");
-        sHalfWidthMap.put('\uFF79', "\uFF79");
-        sHalfWidthMap.put('\uFF7A', "\uFF7A");
-        sHalfWidthMap.put('\uFF7B', "\uFF7B");
-        sHalfWidthMap.put('\uFF7C', "\uFF7C");
-        sHalfWidthMap.put('\uFF7D', "\uFF7D");
-        sHalfWidthMap.put('\uFF7E', "\uFF7E");
-        sHalfWidthMap.put('\uFF7F', "\uFF7F");
-        sHalfWidthMap.put('\uFF80', "\uFF80");
-        sHalfWidthMap.put('\uFF81', "\uFF81");
-        sHalfWidthMap.put('\uFF82', "\uFF82");
-        sHalfWidthMap.put('\uFF83', "\uFF83");
-        sHalfWidthMap.put('\uFF84', "\uFF84");
-        sHalfWidthMap.put('\uFF85', "\uFF85");
-        sHalfWidthMap.put('\uFF86', "\uFF86");
-        sHalfWidthMap.put('\uFF87', "\uFF87");
-        sHalfWidthMap.put('\uFF88', "\uFF88");
-        sHalfWidthMap.put('\uFF89', "\uFF89");
-        sHalfWidthMap.put('\uFF8A', "\uFF8A");
-        sHalfWidthMap.put('\uFF8B', "\uFF8B");
-        sHalfWidthMap.put('\uFF8C', "\uFF8C");
-        sHalfWidthMap.put('\uFF8D', "\uFF8D");
-        sHalfWidthMap.put('\uFF8E', "\uFF8E");
-        sHalfWidthMap.put('\uFF8F', "\uFF8F");
-        sHalfWidthMap.put('\uFF90', "\uFF90");
-        sHalfWidthMap.put('\uFF91', "\uFF91");
-        sHalfWidthMap.put('\uFF92', "\uFF92");
-        sHalfWidthMap.put('\uFF93', "\uFF93");
-        sHalfWidthMap.put('\uFF94', "\uFF94");
-        sHalfWidthMap.put('\uFF95', "\uFF95");
-        sHalfWidthMap.put('\uFF96', "\uFF96");
-        sHalfWidthMap.put('\uFF97', "\uFF97");
-        sHalfWidthMap.put('\uFF98', "\uFF98");
-        sHalfWidthMap.put('\uFF99', "\uFF99");
-        sHalfWidthMap.put('\uFF9A', "\uFF9A");
-        sHalfWidthMap.put('\uFF9B', "\uFF9B");
-        sHalfWidthMap.put('\uFF9C', "\uFF9C");
-        sHalfWidthMap.put('\uFF9D', "\uFF9D");
-        sHalfWidthMap.put('\uFF9E', "\uFF9E");
-        sHalfWidthMap.put('\uFF9F', "\uFF9F");
-        sHalfWidthMap.put('\uFFE5', "\u005C\u005C");
-    }
-
-    /**
-     * Return half-width version of that character if possible. Return null if not possible
-     * @param ch input character
-     * @return CharSequence object if the mapping for ch exists. Return null otherwise.
-     */
-    public static CharSequence tryGetHalfWidthText(char ch) {
-        if (sHalfWidthMap.containsKey(ch)) {
-            return sHalfWidthMap.get(ch);
-        } else {
-            return null;
-        }
-    }
-}
\ No newline at end of file
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java
index d93a41b..89134a1 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java
@@ -16,7 +16,8 @@
 package com.android.unit_tests.vcard;
 
 import android.content.ContentValues;
-import android.pim.vcard.ContactStruct;
+import android.pim.vcard.VCardEntry;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -28,7 +29,7 @@
  * Previously used in main vCard handling code but now exists only for testing.
  *
  * Especially useful for testing parser code (VCardParser), since all properties can be
- * checked via this class unlike {@link ContactStruct}, which only emits the result of
+ * checked via this class unlike {@link VCardEntry}, which only emits the result of
  * interpretation of the content of each vCard. We cannot know whether vCard parser or
  * ContactStruct is wrong withouth this class.
  */
@@ -123,7 +124,10 @@
             return false;
         } else if (!paramMap.equals(node.paramMap)) {
             return false;
-        } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
+        } else if (!(paramMap_TYPE.size() == node.paramMap_TYPE.size()) &&
+                !paramMap_TYPE.equals(node.paramMap_TYPE)) {
+            Log.d("@@@", "paramMap_Type: " + paramMap_TYPE.size() + ", "
+                    + node.paramMap_TYPE.size());
             return false;
         } else if (!propGroupSet.equals(node.propGroupSet)) {
             return false;
@@ -154,10 +158,33 @@
         builder.append(propName);
         builder.append(", paramMap: ");
         builder.append(paramMap.toString());
-        builder.append(", propmMap_TYPE: ");
-        builder.append(paramMap_TYPE.toString());
-        builder.append(", propGroupSet: ");
-        builder.append(propGroupSet.toString());
+        builder.append(", paramMap_TYPE: [");
+        boolean first = true;
+        for (String elem : paramMap_TYPE) {
+            if (first) {
+                first = false;
+            } else {
+                builder.append(", ");
+            }
+            builder.append('"');
+            builder.append(elem);
+            builder.append('"');
+        }
+        builder.append("]");
+        if (!propGroupSet.isEmpty()) {
+            builder.append(", propGroupSet: [");
+            for (String elem : propGroupSet) {
+                if (first) {
+                    first = false;
+                } else {
+                    builder.append(", ");
+                }
+                builder.append('"');
+                builder.append(elem);
+                builder.append('"');
+            }
+            builder.append("]");
+        }
         if (propValue_vector != null && propValue_vector.size() > 1) {
             builder.append(", propValue_vector size: ");
             builder.append(propValue_vector.size());
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 c8289dc..c1727de 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java
@@ -419,6 +419,62 @@
         testPhonePrefHandlingCommon(V30);
     }
 
+    private void testMiscPhoneTypeHandling(int vcardType) {
+        ExportTestResolver resolver = new ExportTestResolver();
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.NUMBER, "1")
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "Modem");
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.NUMBER, "2")
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "MSG");
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.NUMBER, "3")
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "BBS");
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.NUMBER, "4")
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "VIDEO");
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.NUMBER, "5")
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM);
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.NUMBER, "6")
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "_AUTO_CELL");  // The old indicator for the type mobile.
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.NUMBER, "7")
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "\u643A\u5E2F");  // Mobile phone in Japanese Kanji
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.NUMBER, "8")
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "invalid");
+
+        VCardVerifier verifier = new VCardVerifier(resolver, vcardType);
+        PropertyNodesVerifierElem elem = verifier.addPropertyNodesVerifierElemWithEmptyName();
+        elem.addNodeWithoutOrder("TEL", "1", new TypeSet("MODEM"))
+                .addNodeWithoutOrder("TEL", "2", new TypeSet("MSG"))
+                .addNodeWithoutOrder("TEL", "3", new TypeSet("BBS"))
+                .addNodeWithoutOrder("TEL", "4", new TypeSet("VIDEO"))
+                .addNodeWithoutOrder("TEL", "5", new TypeSet("VOICE"))
+                .addNodeWithoutOrder("TEL", "6", new TypeSet("CELL"))
+                .addNodeWithoutOrder("TEL", "7", new TypeSet("CELL"))
+                .addNodeWithoutOrder("TEL", "8", new TypeSet("X-invalid"));
+        verifier.verify();
+    }
+
+    public void testPhoneTypeHandlingV21() {
+        testMiscPhoneTypeHandling(V21);
+    }
+
+    public void testPhoneTypeHandlingV30() {
+        testMiscPhoneTypeHandling(V30);
+    }
+
     private void testEmailBasicCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
         resolver.buildContactEntry().buildData(Email.CONTENT_ITEM_TYPE)
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 70e4966..e561782 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java
@@ -19,6 +19,7 @@
 import android.content.ContentValues;
 import android.pim.vcard.VCardConfig;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 
 import com.android.unit_tests.vcard.PropertyNodesVerifierElem.TypeSet;
 
@@ -204,4 +205,125 @@
                 .put(StructuredName.DISPLAY_NAME, "\uFF94\uFF8F\uFF80\uFF9E \uFF80\uFF9B\uFF73");
         verifier.verify();
     }
+
+    /**
+     * Verifies that only one address field is emitted toward DoCoMo phones.
+     * Prefered type must (should?) be: HOME > WORK > OTHER > CUSTOM
+     */
+    public void testAdrressFieldEmittionForDoCoMo_1() {
+        ExportTestResolver resolver = new ExportTestResolver();
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
+                .put(StructuredPostal.POBOX, "1");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
+                .put(StructuredPostal.POBOX, "2");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
+                .put(StructuredPostal.POBOX, "3");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
+                .put(StructuredPostal.LABEL, "custom")
+                .put(StructuredPostal.POBOX, "4");
+
+        VCardVerifier verifier = new VCardVerifier(resolver, VCardConfig.VCARD_TYPE_DOCOMO);
+        verifier.addPropertyNodesVerifierElemWithEmptyName()
+                .addNodeWithoutOrder("TEL", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("EMAIL", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("X-CLASS", "PUBLIC")
+                .addNodeWithoutOrder("X-REDUCTION", "")
+                .addNodeWithoutOrder("X-NO", "")
+                .addNodeWithoutOrder("X-DCM-HMN-MODE", "")
+                .addNodeWithoutOrder("ADR",
+                        Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME"));
+        verifier.verify();
+    }
+
+    public void testAdrressFieldEmittionForDoCoMo_2() {
+        ExportTestResolver resolver = new ExportTestResolver();
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
+                .put(StructuredPostal.POBOX, "1");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
+                .put(StructuredPostal.POBOX, "2");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
+                .put(StructuredPostal.LABEL, "custom")
+                .put(StructuredPostal.POBOX, "3");
+
+        VCardVerifier verifier = new VCardVerifier(resolver, VCardConfig.VCARD_TYPE_DOCOMO);
+        verifier.addPropertyNodesVerifierElemWithEmptyName()
+                .addNodeWithoutOrder("TEL", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("EMAIL", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("X-CLASS", "PUBLIC")
+                .addNodeWithoutOrder("X-REDUCTION", "")
+                .addNodeWithoutOrder("X-NO", "")
+                .addNodeWithoutOrder("X-DCM-HMN-MODE", "")
+                .addNodeWithoutOrder("ADR",
+                        Arrays.asList("2", "", "", "", "", "", ""), new TypeSet("WORK"));
+        verifier.verify();
+    }
+
+    public void testAdrressFieldEmittionForDoCoMo_3() {
+        ExportTestResolver resolver = new ExportTestResolver();
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
+                .put(StructuredPostal.LABEL, "custom1")
+                .put(StructuredPostal.POBOX, "1");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
+                .put(StructuredPostal.POBOX, "2");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
+                .put(StructuredPostal.LABEL, "custom2")
+                .put(StructuredPostal.POBOX, "3");
+
+        VCardVerifier verifier = new VCardVerifier(resolver, VCardConfig.VCARD_TYPE_DOCOMO);
+        verifier.addPropertyNodesVerifierElemWithEmptyName()
+                .addNodeWithoutOrder("TEL", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("EMAIL", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("X-CLASS", "PUBLIC")
+                .addNodeWithoutOrder("X-REDUCTION", "")
+                .addNodeWithoutOrder("X-NO", "")
+                .addNodeWithoutOrder("X-DCM-HMN-MODE", "")
+                .addNodeWithoutOrder("ADR", Arrays.asList("2", "", "", "", "", "", ""));
+        verifier.verify();
+    }
+
+    /**
+     * Verifies the vCard exporter tolerates null TYPE.
+     */
+    public void testAdrressFieldEmittionForDoCoMo_4() {
+        ExportTestResolver resolver = new ExportTestResolver();
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.POBOX, "1");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
+                .put(StructuredPostal.POBOX, "2");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
+                .put(StructuredPostal.POBOX, "3");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
+                .put(StructuredPostal.POBOX, "4");
+        entry.buildData(StructuredPostal.CONTENT_ITEM_TYPE)
+                .put(StructuredPostal.POBOX, "5");
+
+        VCardVerifier verifier = new VCardVerifier(resolver, VCardConfig.VCARD_TYPE_DOCOMO);
+        verifier.addPropertyNodesVerifierElemWithEmptyName()
+                .addNodeWithoutOrder("TEL", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("EMAIL", "", new TypeSet("HOME"))
+                .addNodeWithoutOrder("X-CLASS", "PUBLIC")
+                .addNodeWithoutOrder("X-REDUCTION", "")
+                .addNodeWithoutOrder("X-NO", "")
+                .addNodeWithoutOrder("X-DCM-HMN-MODE", "")
+                .addNodeWithoutOrder("ADR",
+                        Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME"));
+        verifier.verify();
+    }
 }
\ No newline at end of file
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
index af8b718..6590855 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
@@ -33,14 +33,14 @@
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.pim.vcard.ContactStruct;
-import android.pim.vcard.EntryCommitter;
-import android.pim.vcard.EntryHandler;
-import android.pim.vcard.VCardBuilder;
-import android.pim.vcard.VCardBuilderCollection;
+import android.pim.vcard.VCardEntry;
+import android.pim.vcard.VCardEntryCommitter;
+import android.pim.vcard.VCardEntryHandler;
+import android.pim.vcard.VCardInterpreter;
+import android.pim.vcard.VCardInterPreterCollection;
 import android.pim.vcard.VCardComposer;
 import android.pim.vcard.VCardConfig;
-import android.pim.vcard.VCardDataBuilder;
+import android.pim.vcard.VCardEntryConstructor;
 import android.pim.vcard.VCardParser;
 import android.pim.vcard.VCardParser_V21;
 import android.pim.vcard.VCardParser_V30;
@@ -385,11 +385,11 @@
 
     class ImportVerifierElem {
         private final ImportTestResolver mResolver;
-        private final EntryHandler mHandler;
+        private final VCardEntryHandler mHandler;
 
         public ImportVerifierElem() {
             mResolver = new ImportTestResolver();
-            mHandler = new EntryCommitter(mResolver);
+            mHandler = new VCardEntryCommitter(mResolver);
         }
 
         public ContentValuesBuilder addExpected(String mimeType) {
@@ -411,8 +411,8 @@
             } else {
                 vCardParser = new VCardParser_V21();
             }
-            VCardDataBuilder builder =
-                    new VCardDataBuilder(null, null, false, vCardType, null);
+            VCardEntryConstructor builder =
+                    new VCardEntryConstructor(null, null, false, vCardType, null);
             builder.addEntryHandler(mHandler);
             try {
                 vCardParser.parse(is, builder);
@@ -432,19 +432,19 @@
         }
 
         public void onParsingStart() {
-            mHandler.onParsingStart();
+            mHandler.onStart();
         }
 
-        public void onEntryCreated(ContactStruct entry) {
+        public void onEntryCreated(VCardEntry entry) {
             mHandler.onEntryCreated(entry);
         }
 
         public void onParsingEnd() {
-            mHandler.onParsingEnd();
+            mHandler.onEnd();
         }
     }
 
-    class ImportVerifier implements EntryHandler {
+    class ImportVerifier implements VCardEntryHandler {
         private List<ImportVerifierElem> mImportVerifierElemList =
             new ArrayList<ImportVerifierElem>();
         private int mIndex;
@@ -476,8 +476,8 @@
 
         public void verify(InputStream is, int vCardType, final VCardParser vCardParser)
                 throws IOException, VCardException {
-            VCardDataBuilder builder =
-                new VCardDataBuilder(null, null, false, vCardType, null);
+            VCardEntryConstructor builder =
+                new VCardEntryConstructor(null, null, false, vCardType, null);
             builder.addEntryHandler(this);
             try {
                 vCardParser.parse(is, builder);
@@ -491,19 +491,19 @@
             }
         }
 
-        public void onParsingStart() {
+        public void onStart() {
             for (ImportVerifierElem elem : mImportVerifierElemList) {
                 elem.onParsingStart();
             }
         }
 
-        public void onEntryCreated(ContactStruct entry) {
+        public void onEntryCreated(VCardEntry entry) {
             assertTrue(mIndex < mImportVerifierElemList.size());
             mImportVerifierElemList.get(mIndex).onEntryCreated(entry);
             mIndex++;
         }
 
-        public void onParsingEnd() {
+        public void onEnd() {
             for (ImportVerifierElem elem : mImportVerifierElemList) {
                 elem.onParsingEnd();
                 elem.verifyResolver();
@@ -802,6 +802,7 @@
         private final ExportTestResolver mResolver;
         private final int mVCardType;
         private final boolean mIsV30;
+        private final boolean mIsDoCoMo;
 
         // To allow duplication, use list instead of set.
         // When null, we don't need to do the verification.
@@ -813,6 +814,7 @@
             mVCardVerifierInternal = new VCardVerifierInternal();
             mResolver = resolver;
             mIsV30 = VCardConfig.isV30(vcardType);
+            mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
             mVCardType = vcardType;
         }
 
@@ -831,6 +833,8 @@
             PropertyNodesVerifierElem elem = addPropertyNodesVerifierElem();
             if (mIsV30) {
                 elem.addNodeWithOrder("N", "").addNodeWithOrder("FN", "");
+            } else if (mIsDoCoMo) {
+                elem.addNodeWithOrder("N", "");
             }
             return elem;
         }
@@ -852,14 +856,14 @@
 
         private void verifyOneVCard(final String vcard) {
             // Log.d("@@@", vcard);
-            final VCardBuilder builder;
+            final VCardInterpreter builder;
             if (mImportVerifier != null) {
                 final VNodeBuilder vnodeBuilder = mPropertyNodesVerifier;
-                final VCardDataBuilder vcardDataBuilder =
-                        new VCardDataBuilder(mVCardType);
+                final VCardEntryConstructor vcardDataBuilder =
+                        new VCardEntryConstructor(mVCardType);
                 vcardDataBuilder.addEntryHandler(mImportVerifier);
                 if (mPropertyNodesVerifier != null) {
-                    builder = new VCardBuilderCollection(Arrays.asList(
+                    builder = new VCardInterPreterCollection(Arrays.asList(
                             mPropertyNodesVerifier, vcardDataBuilder));
                 } else {
                     builder = vnodeBuilder;
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java
index ce4de03..c38b54c 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java
@@ -16,7 +16,7 @@
 package com.android.unit_tests.vcard;
 
 import android.content.ContentValues;
-import android.pim.vcard.VCardBuilder;
+import android.pim.vcard.VCardInterpreter;
 import android.pim.vcard.VCardConfig;
 import android.util.CharsetUtils;
 import android.util.Log;
@@ -39,8 +39,8 @@
  *
  * Previously used in main vCard handling code but now exists only for testing.
  */
-public class VNodeBuilder implements VCardBuilder {
-    static private String LOG_TAG = "VDATABuilder"; 
+public class VNodeBuilder implements VCardInterpreter {
+    static private String LOG_TAG = "VNodeBuilder"; 
     
     /**
      * If there's no other information available, this class uses this charset for encoding