diff options
author | Android (Google) Code Review <android-gerrit@google.com> | 2009-11-15 23:51:34 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-11-15 23:51:34 -0800 |
commit | 9e807d7cc4e5deafc0744abd932e2b40e3f5e80b (patch) | |
tree | 7b2a190d3b6619bbf60f645e3a2ca9a625d1a89d | |
parent | 92c12fae9a977ea1dcb9f4de56257d4945101db7 (diff) | |
parent | 5a1f2d2de026b582fbe8b1a46a83ad33760a2c48 (diff) | |
download | frameworks_base-9e807d7cc4e5deafc0744abd932e2b40e3f5e80b.zip frameworks_base-9e807d7cc4e5deafc0744abd932e2b40e3f5e80b.tar.gz frameworks_base-9e807d7cc4e5deafc0744abd932e2b40e3f5e80b.tar.bz2 |
Merge change Iecf85b40 into eclair-mr2
* changes:
Rename several files so that readers would not be confused.
20 files changed, 969 insertions, 713 deletions
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 @@ package android.pim.vcard; 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 @@ package android.pim.vcard; 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 @@ package android.pim.vcard; 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 @@ public class VCardComposer { * 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 @@ public class VCardComposer { /** * 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 @@ public class VCardComposer { } /** - * Must call before {{@link #init()}. + * Must be called before {@link #init()}. */ public void addHandler(OneEntryHandler handler) { if (handler != null) { @@ -510,8 +511,7 @@ public class VCardComposer { } 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 @@ public class VCardComposer { } } - 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 @@ public class VCardComposer { } 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 @@ public class VCardComposer { 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 @@ public class VCardComposer { 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 @@ public class VCardComposer { // 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 @@ public class VCardComposer { 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 @@ public class VCardComposer { 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 @@ public class VCardComposer { } } + 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; + int currentPriority = Integer.MAX_VALUE; + int currentType = Integer.MAX_VALUE; + ContentValues currentContentValues = null; + for (ContentValues contentValues : contentValuesList) { + 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; + } + } } - if (appendPostalsForDoCoMoInternal(builder, contentValuesList, - StructuredPostal.TYPE_CUSTOM)) { + + if (currentContentValues == null) { + Log.w(LOG_TAG, "Should not come here. Must have at least one postal data."); 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) { - 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; - } - } - return false; + final String label = currentContentValues.getAsString(StructuredPostal.LABEL); + appendVCardPostalLine(builder, currentType, label, currentContentValues, false, true); } private void appendPostalsForGeneric(final StringBuilder builder, @@ -1302,9 +1311,9 @@ public class VCardComposer { 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 @@ public class VCardComposer { 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 @@ public class VCardComposer { 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 @@ public class VCardComposer { 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 @@ public class VCardComposer { } // 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 @@ public class VCardComposer { // 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 @@ public class VCardComposer { 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 @@ public class VCardComposer { } 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); - } - 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 (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. + switch (type) { + 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); + } + 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; } - break; - case Phone.TYPE_RADIO: - case Phone.TYPE_TTY_TDD: - default: - break; } if (isPrimary) { @@ -2069,7 +2089,7 @@ public class VCardComposer { } if (parameterList.isEmpty()) { - appendUncommonPhoneType(builder, typeAsPrimitive); + appendUncommonPhoneType(builder, type); } else { appendTypeParameters(builder, parameterList); } @@ -2203,7 +2223,7 @@ public class VCardComposer { 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 @@ public class VCardComposer { 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 @@ public class VCardComposer { } { // 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 @@ public class VCardConfig { /** * <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 @@ public class VCardConfig { /** * <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 @@ public class VCardConfig { * 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 @@ public class VCardConfig { /** * <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 @@ public class VCardConfig { * 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 index 530d5ad..c1b4c03 100644 --- a/core/java/android/pim/vcard/ContactStruct.java +++ b/core/java/android/pim/vcard/VCardEntry.java @@ -54,8 +54,11 @@ import java.util.Map; /** * 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 @@ public class ContactStruct { 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 @@ public class ContactStruct { 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 @@ public class ContactStruct { } 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 @@ public class ContactStruct { } } - // 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 @@ public class ContactStruct { 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 class ContactStruct { } } - 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 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.content.ContentResolver; 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 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.ArrayList; 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 @@ public class VCardDataBuilder implements VCardBuilder { // 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 @@ public class VCardDataBuilder implements VCardBuilder { /** * @hide */ - public VCardDataBuilder(String sourceCharset, + public VCardEntryConstructor(String sourceCharset, String targetCharset, boolean strictLineBreakParsing, int vcardType, @@ -109,20 +100,20 @@ public class VCardDataBuilder implements VCardBuilder { 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 class VCardDataBuilder implements VCardBuilder { */ public void clear() { mCurrentContactStruct = null; - mCurrentProperty = new ContactStruct.Property(); + mCurrentProperty = new VCardEntry.Property(); } /** @@ -153,12 +144,12 @@ public class VCardDataBuilder implements VCardBuilder { 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 @@ package android.pim.vcard; 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 class VCardEntryCounter implements VCardBuilder { 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 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 index e3985b6..19f0406 100644 --- a/core/java/android/pim/vcard/VCardBuilderCollection.java +++ b/core/java/android/pim/vcard/VCardInterPreterCollection.java @@ -18,81 +18,81 @@ package android.pim.vcard; 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 index e1c4b33..1f2408d 100644 --- a/core/java/android/pim/vcard/VCardBuilder.java +++ b/core/java/android/pim/vcard/VCardInterpreter.java @@ -17,7 +17,7 @@ package android.pim.vcard; import java.util.List; -public interface VCardBuilder { +public interface VCardInterpreter { void start(); void end(); @@ -27,7 +27,7 @@ public interface VCardBuilder { */ 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 @@ public abstract class VCardParser { * @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 @@ public abstract class VCardParser { * @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 @@ public abstract class VCardParser { * @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 @@ public class VCardParser_V21 extends VCardParser { 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 @@ public class VCardParser_V21 extends VCardParser { } @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 @@ public class VCardParser_V21 extends VCardParser { } @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 @@ import java.util.Set; * 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.Phone; import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; -import android.util.Log; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -37,19 +37,14 @@ import java.util.Set; * 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 @@ public class VCardUtils { 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 @@ public class VCardUtils { 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 @@ public class VCardUtils { 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 @@ public class VCardUtils { 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 class VCardUtils { } } - public static String getPropertyNameForIm(int protocol) { - return sKnownImPropNameMap_ItoS.get(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 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 boolean isValidInV21ButUnknownToContactsPhoteType(final String label) { + return sPhoneTypesUnknownToContactsSet.contains(label); } - + + public static String getPropertyNameForIm(final int protocol) { + return sKnownImPropNameMap_ItoS.get(protocol); + } + 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 class VCardUtils { */ 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 @@ public class VCardUtils { * 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 @@ public class VCardUtils { 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 @@ import java.util.Set; * 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 @@ public class PropertyNode { 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 @@ public class PropertyNode { 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 @@ public class VCardExporterTests extends VCardTestsBase { 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 @@ package com.android.unit_tests.vcard; 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 @@ public class VCardJapanizationTests extends VCardTestsBase { .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.net.Uri; 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 CustomMockContext extends MockContext { 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 @@ class CustomMockContext extends MockContext { } 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 @@ class CustomMockContext extends MockContext { } 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 @@ class CustomMockContext extends MockContext { 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 @@ class CustomMockContext extends MockContext { } } - 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 @@ class CustomMockContext extends MockContext { 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 @@ class CustomMockContext extends MockContext { mVCardVerifierInternal = new VCardVerifierInternal(); mResolver = resolver; mIsV30 = VCardConfig.isV30(vcardType); + mIsDoCoMo = VCardConfig.isDoCoMo(vcardType); mVCardType = vcardType; } @@ -831,6 +833,8 @@ class CustomMockContext extends MockContext { PropertyNodesVerifierElem elem = addPropertyNodesVerifierElem(); if (mIsV30) { elem.addNodeWithOrder("N", "").addNodeWithOrder("FN", ""); + } else if (mIsDoCoMo) { + elem.addNodeWithOrder("N", ""); } return elem; } @@ -852,14 +856,14 @@ class CustomMockContext extends MockContext { 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 @@ import java.util.List; * * 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 |