VCardConfig.java revision be378d5b188f51cf717e5309e3c39180e85833a8
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.vcard; 17 18import android.telephony.PhoneNumberUtils; 19import android.util.Log; 20 21import java.util.HashMap; 22import java.util.HashSet; 23import java.util.Map; 24import java.util.Set; 25 26/** 27 * The class representing VCard related configurations. Useful static methods are not in this class 28 * but in VCardUtils. 29 */ 30public class VCardConfig { 31 private static final String LOG_TAG = "VCardConfig"; 32 33 /* package */ static final int LOG_LEVEL_NONE = 0; 34 /* package */ static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1; 35 /* package */ static final int LOG_LEVEL_SHOW_WARNING = 0x2; 36 /* package */ static final int LOG_LEVEL_VERBOSE = 37 LOG_LEVEL_PERFORMANCE_MEASUREMENT | LOG_LEVEL_SHOW_WARNING; 38 39 /* package */ static final int LOG_LEVEL = LOG_LEVEL_NONE; 40 41 /** 42 * <p> 43 * The charset used during import. 44 * </p> 45 * <p> 46 * We cannot determine which charset should be used to interpret lines in vCard, 47 * while Java requires us to specify it when InputStream is used. 48 * We need to rely on the mechanism due to some performance reason. 49 * </p> 50 * <p> 51 * In order to avoid "misinterpretation" of charset and lose any data in vCard, 52 * "ISO-8859-1" is first used for reading the stream. 53 * When a charset is specified in a property (with "CHARSET=..." parameter), 54 * the string is decoded to raw bytes and encoded into the specific charset, 55 * </p> 56 * <p> 57 * Unicode specification there's a one to one mapping between each byte in ISO-8859-1 58 * and a codepoint, and Java specification requires runtime must have the charset. 59 * Thus, ISO-8859-1 is one effective mapping for intermediate mapping. 60 * </p> 61 */ 62 public static final String DEFAULT_INTERMEDIATE_CHARSET = "ISO-8859-1"; 63 64 /** 65 * The charset used when there's no information affbout what charset should be used to 66 * encode the binary given from vCard. 67 */ 68 public static final String DEFAULT_IMPORT_CHARSET = "UTF-8"; 69 public static final String DEFAULT_EXPORT_CHARSET = "UTF-8"; 70 71 public static final int VERSION_21 = 0; 72 public static final int VERSION_30 = 1; 73 public static final int VERSION_40 = 2; 74 public static final int VERSION_MASK = 3; 75 76 public static final int NAME_ORDER_DEFAULT = 0; 77 public static final int NAME_ORDER_EUROPE = 0x4; 78 public static final int NAME_ORDER_JAPANESE = 0x8; 79 private static final int NAME_ORDER_MASK = 0xC; 80 81 // 0x10 is reserved for safety 82 83 /** 84 * <p> 85 * The flag indicating the vCard composer will add some "X-" properties used only in Android 86 * when the formal vCard specification does not have appropriate fields for that data. 87 * </p> 88 * <p> 89 * For example, Android accepts nickname information while vCard 2.1 does not. 90 * When this flag is on, vCard composer emits alternative "X-" property (like "X-NICKNAME") 91 * instead of just dropping it. 92 * </p> 93 * <p> 94 * vCard parser code automatically parses the field emitted even when this flag is off. 95 * </p> 96 */ 97 private static final int FLAG_USE_ANDROID_PROPERTY = 0x80000000; 98 99 /** 100 * <p> 101 * The flag indicating the vCard composer will add some "X-" properties seen in the 102 * vCard data emitted by the other softwares/devices when the formal vCard specification 103 * does not have appropriate field(s) for that data. 104 * </p> 105 * <p> 106 * One example is X-PHONETIC-FIRST-NAME/X-PHONETIC-MIDDLE-NAME/X-PHONETIC-LAST-NAME, which are 107 * for phonetic name (how the name is pronounced), seen in the vCard emitted by some other 108 * non-Android devices/softwares. We chose to enable the vCard composer to use those 109 * defact properties since they are also useful for Android devices. 110 * </p> 111 * <p> 112 * Note for developers: only "X-" properties should be added with this flag. vCard 2.1/3.0 113 * allows any kind of "X-" properties but does not allow non-"X-" properties (except IANA tokens 114 * in vCard 3.0). Some external parsers may get confused with non-valid, non-"X-" properties. 115 * </p> 116 */ 117 private static final int FLAG_USE_DEFACT_PROPERTY = 0x40000000; 118 119 /** 120 * <p> 121 * The flag indicating some specific dialect seen in vCard of DoCoMo (one of Japanese 122 * mobile careers) should be used. This flag does not include any other information like 123 * that "the vCard is for Japanese". So it is "possible" that "the vCard should have DoCoMo's 124 * dialect but the name order should be European", but it is not recommended. 125 * </p> 126 */ 127 private static final int FLAG_DOCOMO = 0x20000000; 128 129 /** 130 * <p> 131 * The flag indicating the vCard composer does "NOT" use Quoted-Printable toward "primary" 132 * properties even though it is required by vCard 2.1 (QP is prohibited in vCard 3.0). 133 * </p> 134 * <p> 135 * We actually cannot define what is the "primary" property. Note that this is NOT defined 136 * in vCard specification either. Also be aware that it is NOT related to "primary" notion 137 * used in {@link android.provider.ContactsContract}. 138 * This notion is just for vCard composition in Android. 139 * </p> 140 * <p> 141 * We added this Android-specific notion since some (incomplete) vCard exporters for vCard 2.1 142 * do NOT use Quoted-Printable encoding toward some properties related names like "N", "FN", etc. 143 * even when their values contain non-ascii or/and CR/LF, while they use the encoding in the 144 * other properties like "ADR", "ORG", etc. 145 * <p> 146 * We are afraid of the case where some vCard importer also forget handling QP presuming QP is 147 * not used in such fields. 148 * </p> 149 * <p> 150 * This flag is useful when some target importer you are going to focus on does not accept 151 * such properties with Quoted-Printable encoding. 152 * </p> 153 * <p> 154 * Again, we should not use this flag at all for complying vCard 2.1 spec. 155 * </p> 156 * <p> 157 * In vCard 3.0, Quoted-Printable is explicitly "prohibitted", so we don't need to care this 158 * kind of problem (hopefully). 159 * </p> 160 * @hide 161 */ 162 public static final int FLAG_REFRAIN_QP_TO_NAME_PROPERTIES = 0x10000000; 163 164 /** 165 * <p> 166 * The flag indicating that phonetic name related fields must be converted to 167 * appropriate form. Note that "appropriate" is not defined in any vCard specification. 168 * This is Android-specific. 169 * </p> 170 * <p> 171 * One typical (and currently sole) example where we need this flag is the time when 172 * we need to emit Japanese phonetic names into vCard entries. The property values 173 * should be encoded into half-width katakana when the target importer is Japanese mobile 174 * phones', which are probably not able to parse full-width hiragana/katakana for 175 * historical reasons, while the vCard importers embedded to softwares for PC should be 176 * able to parse them as we expect. 177 * </p> 178 */ 179 public static final int FLAG_CONVERT_PHONETIC_NAME_STRINGS = 0x08000000; 180 181 /** 182 * <p> 183 * The flag indicating the vCard composer "for 2.1" emits "TYPE=" string toward TYPE params 184 * every time possible. The default behavior does not emit it and is valid in the spec. 185 * In vCrad 3.0, this flag is unnecessary, since "TYPE=" is MUST in vCard 3.0 specification. 186 * </p> 187 * <p> 188 * Detail: 189 * How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0. 190 * </p> 191 * <p> 192 * e.g. 193 * </p> 194 * <ol> 195 * <li>Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..."</li> 196 * <li>Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."</li> 197 * <li>Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."</li> 198 * </ol> 199 * <p> 200 * If you are targeting to the importer which cannot accept TYPE params without "TYPE=" 201 * strings (which should be rare though), please use this flag. 202 * </p> 203 * <p> 204 * Example usage: 205 * <pre class="prettyprint">int type = (VCARD_TYPE_V21_GENERIC | FLAG_APPEND_TYPE_PARAM);</pre> 206 * </p> 207 */ 208 public static final int FLAG_APPEND_TYPE_PARAM = 0x04000000; 209 210 /** 211 * <p> 212 * The flag indicating the vCard composer does touch nothing toward phone number Strings 213 * but leave it as is. 214 * </p> 215 * <p> 216 * The vCard specifications mention nothing toward phone numbers, while some devices 217 * do (wrongly, but with innevitable reasons). 218 * For example, there's a possibility Japanese mobile phones are expected to have 219 * just numbers, hypens, plus, etc. but not usual alphabets, while US mobile phones 220 * should get such characters. To make exported vCard simple for external parsers, 221 * we have used {@link PhoneNumberUtils#formatNumber(String)} during export, and 222 * removed unnecessary characters inside the number (e.g. "111-222-3333 (Miami)" 223 * becomes "111-222-3333"). 224 * Unfortunate side effect of that use was some control characters used in the other 225 * areas may be badly affected by the formatting. 226 * </p> 227 * <p> 228 * This flag disables that formatting, affecting both importer and exporter. 229 * If the user is aware of some side effects due to the implicit formatting, use this flag. 230 * </p> 231 */ 232 public static final int FLAG_REFRAIN_PHONE_NUMBER_FORMATTING = 0x02000000; 233 234 /** 235 * <p> 236 * For importer only. Ignored in exporter. 237 * </p> 238 * <p> 239 * The flag indicating the parser should handle a nested vCard, in which vCard clause starts 240 * in another vCard clause. Here's a typical example. 241 * </p> 242 * <pre class="prettyprint">BEGIN:VCARD 243 * BEGIN:VCARD 244 * VERSION:2.1 245 * ... 246 * END:VCARD 247 * END:VCARD</pre> 248 * <p> 249 * The vCard 2.1 specification allows the nest, but also let parsers ignore nested entries, 250 * while some mobile devices emit nested ones as primary data to be imported. 251 * </p> 252 * <p> 253 * This flag forces a vCard parser to torelate such a nest and understand its content. 254 * </p> 255 */ 256 public static final int FLAG_TORELATE_NEST = 0x01000000; 257 258 //// The followings are VCard types available from importer/exporter. //// 259 260 /** 261 * <p> 262 * The type indicating nothing. Used by {@link VCardSourceDetector} when it 263 * was not able to guess the exact vCard type. 264 * </p> 265 */ 266 public static final int VCARD_TYPE_UNKNOWN = 0; 267 268 /** 269 * <p> 270 * Generic vCard format with the vCard 2.1. When composing a vCard entry, 271 * the US convension will be used toward formatting some values. 272 * </p> 273 * <p> 274 * e.g. The order of the display name would be "Prefix Given Middle Family Suffix", 275 * while it should be "Prefix Family Middle Given Suffix" in Japan for example. 276 * </p> 277 * <p> 278 * Uses UTF-8 for the charset as a charset for exporting. Note that old vCard importer 279 * outside Android cannot accept it since vCard 2.1 specifically does not allow 280 * that charset, while we need to use it to support various languages around the world. 281 * </p> 282 * <p> 283 * If you want to use alternative charset, you should notify the charset to the other 284 * compontent to be used. 285 * </p> 286 */ 287 public static final int VCARD_TYPE_V21_GENERIC = 288 (VERSION_21 | NAME_ORDER_DEFAULT | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY); 289 290 /* package */ static String VCARD_TYPE_V21_GENERIC_STR = "v21_generic"; 291 292 /** 293 * <p> 294 * General vCard format with the version 3.0. Uses UTF-8 for the charset. 295 * </p> 296 * <p> 297 * Not fully ready yet. Use with caution when you use this. 298 * </p> 299 */ 300 public static final int VCARD_TYPE_V30_GENERIC = 301 (VERSION_30 | NAME_ORDER_DEFAULT | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY); 302 303 /* package */ static final String VCARD_TYPE_V30_GENERIC_STR = "v30_generic"; 304 305 /** 306 * General vCard format with the version 4.0. 307 */ 308 public static final int VCARD_TYPE_V40_GENERIC = 309 (VERSION_40 | NAME_ORDER_DEFAULT | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY); 310 311 /* package */ static final String VCARD_TYPE_V40_GENERIC_STR = "v40_generic"; 312 313 /** 314 * <p> 315 * General vCard format for the vCard 2.1 with some Europe convension. Uses Utf-8. 316 * Currently, only name order is considered ("Prefix Middle Given Family Suffix") 317 * </p> 318 */ 319 public static final int VCARD_TYPE_V21_EUROPE = 320 (VERSION_21 | NAME_ORDER_EUROPE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY); 321 322 /* package */ static final String VCARD_TYPE_V21_EUROPE_STR = "v21_europe"; 323 324 /** 325 * <p> 326 * General vCard format with the version 3.0 with some Europe convension. Uses UTF-8. 327 * </p> 328 * <p> 329 * Not ready yet. Use with caution when you use this. 330 * </p> 331 */ 332 public static final int VCARD_TYPE_V30_EUROPE = 333 (VERSION_30 | NAME_ORDER_EUROPE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY); 334 335 /* package */ static final String VCARD_TYPE_V30_EUROPE_STR = "v30_europe"; 336 337 /** 338 * <p> 339 * The vCard 2.1 format for miscellaneous Japanese devices, using UTF-8 as default charset. 340 * </p> 341 * <p> 342 * Not ready yet. Use with caution when you use this. 343 * </p> 344 */ 345 public static final int VCARD_TYPE_V21_JAPANESE = 346 (VERSION_21 | NAME_ORDER_JAPANESE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY); 347 348 /* package */ static final String VCARD_TYPE_V21_JAPANESE_STR = "v21_japanese_utf8"; 349 350 /** 351 * <p> 352 * The vCard 3.0 format for miscellaneous Japanese devices, using UTF-8 as default charset. 353 * </p> 354 * <p> 355 * Not ready yet. Use with caution when you use this. 356 * </p> 357 */ 358 public static final int VCARD_TYPE_V30_JAPANESE = 359 (VERSION_30 | NAME_ORDER_JAPANESE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY); 360 361 /* package */ static final String VCARD_TYPE_V30_JAPANESE_STR = "v30_japanese_utf8"; 362 363 /** 364 * <p> 365 * The vCard 2.1 based format which (partially) considers the convention in Japanese 366 * mobile phones, where phonetic names are translated to half-width katakana if 367 * possible, etc. It would be better to use Shift_JIS as a charset for maximum 368 * compatibility. 369 * </p> 370 * @hide Should not be available world wide. 371 */ 372 public static final int VCARD_TYPE_V21_JAPANESE_MOBILE = 373 (VERSION_21 | NAME_ORDER_JAPANESE | 374 FLAG_CONVERT_PHONETIC_NAME_STRINGS | FLAG_REFRAIN_QP_TO_NAME_PROPERTIES); 375 376 /* package */ static final String VCARD_TYPE_V21_JAPANESE_MOBILE_STR = "v21_japanese_mobile"; 377 378 /** 379 * <p> 380 * The vCard format used in DoCoMo, which is one of Japanese mobile phone careers. 381 * </p> 382 * <p> 383 * Base version is vCard 2.1, but the data has several DoCoMo-specific convensions. 384 * No Android-specific property nor defact property is included. The "Primary" properties 385 * are NOT encoded to Quoted-Printable. 386 * </p> 387 * @hide Should not be available world wide. 388 */ 389 public static final int VCARD_TYPE_DOCOMO = 390 (VCARD_TYPE_V21_JAPANESE_MOBILE | FLAG_DOCOMO); 391 392 /* package */ static final String VCARD_TYPE_DOCOMO_STR = "docomo"; 393 394 public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC; 395 396 private static final Map<String, Integer> sVCardTypeMap; 397 private static final Set<Integer> sJapaneseMobileTypeSet; 398 399 static { 400 sVCardTypeMap = new HashMap<String, Integer>(); 401 sVCardTypeMap.put(VCARD_TYPE_V21_GENERIC_STR, VCARD_TYPE_V21_GENERIC); 402 sVCardTypeMap.put(VCARD_TYPE_V30_GENERIC_STR, VCARD_TYPE_V30_GENERIC); 403 sVCardTypeMap.put(VCARD_TYPE_V21_EUROPE_STR, VCARD_TYPE_V21_EUROPE); 404 sVCardTypeMap.put(VCARD_TYPE_V30_EUROPE_STR, VCARD_TYPE_V30_EUROPE); 405 sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_STR, VCARD_TYPE_V21_JAPANESE); 406 sVCardTypeMap.put(VCARD_TYPE_V30_JAPANESE_STR, VCARD_TYPE_V30_JAPANESE); 407 sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_MOBILE_STR, VCARD_TYPE_V21_JAPANESE_MOBILE); 408 sVCardTypeMap.put(VCARD_TYPE_DOCOMO_STR, VCARD_TYPE_DOCOMO); 409 410 sJapaneseMobileTypeSet = new HashSet<Integer>(); 411 sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE); 412 sJapaneseMobileTypeSet.add(VCARD_TYPE_V30_JAPANESE); 413 sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_MOBILE); 414 sJapaneseMobileTypeSet.add(VCARD_TYPE_DOCOMO); 415 } 416 417 public static int getVCardTypeFromString(final String vcardTypeString) { 418 final String loweredKey = vcardTypeString.toLowerCase(); 419 if (sVCardTypeMap.containsKey(loweredKey)) { 420 return sVCardTypeMap.get(loweredKey); 421 } else if ("default".equalsIgnoreCase(vcardTypeString)) { 422 return VCARD_TYPE_DEFAULT; 423 } else { 424 Log.e(LOG_TAG, "Unknown vCard type String: \"" + vcardTypeString + "\""); 425 return VCARD_TYPE_DEFAULT; 426 } 427 } 428 429 public static boolean isVersion21(final int vcardType) { 430 return (vcardType & VERSION_MASK) == VERSION_21; 431 } 432 433 public static boolean isVersion30(final int vcardType) { 434 return (vcardType & VERSION_MASK) == VERSION_30; 435 } 436 437 public static boolean isVersion40(final int vcardType) { 438 return (vcardType & VERSION_MASK) == VERSION_40; 439 } 440 441 public static boolean shouldUseQuotedPrintable(final int vcardType) { 442 return !isVersion30(vcardType); 443 } 444 445 public static int getNameOrderType(final int vcardType) { 446 return vcardType & NAME_ORDER_MASK; 447 } 448 449 public static boolean usesAndroidSpecificProperty(final int vcardType) { 450 return ((vcardType & FLAG_USE_ANDROID_PROPERTY) != 0); 451 } 452 453 public static boolean usesDefactProperty(final int vcardType) { 454 return ((vcardType & FLAG_USE_DEFACT_PROPERTY) != 0); 455 } 456 457 public static boolean showPerformanceLog() { 458 return (VCardConfig.LOG_LEVEL & VCardConfig.LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0; 459 } 460 461 public static boolean shouldRefrainQPToNameProperties(final int vcardType) { 462 return (!shouldUseQuotedPrintable(vcardType) || 463 ((vcardType & FLAG_REFRAIN_QP_TO_NAME_PROPERTIES) != 0)); 464 } 465 466 public static boolean appendTypeParamName(final int vcardType) { 467 return (isVersion30(vcardType) || ((vcardType & FLAG_APPEND_TYPE_PARAM) != 0)); 468 } 469 470 /** 471 * @return true if the device is Japanese and some Japanese convension is 472 * applied to creating "formatted" something like FORMATTED_ADDRESS. 473 */ 474 public static boolean isJapaneseDevice(final int vcardType) { 475 // TODO: Some mask will be required so that this method wrongly interpret 476 // Japanese"-like" vCard type. 477 // e.g. VCARD_TYPE_V21_JAPANESE_SJIS | FLAG_APPEND_TYPE_PARAMS 478 return sJapaneseMobileTypeSet.contains(vcardType); 479 } 480 481 /* package */ static boolean refrainPhoneNumberFormatting(final int vcardType) { 482 return ((vcardType & FLAG_REFRAIN_PHONE_NUMBER_FORMATTING) != 0); 483 } 484 485 public static boolean needsToConvertPhoneticString(final int vcardType) { 486 return ((vcardType & FLAG_CONVERT_PHONETIC_NAME_STRINGS) != 0); 487 } 488 489 public static boolean onlyOneNoteFieldIsAvailable(final int vcardType) { 490 return vcardType == VCARD_TYPE_DOCOMO; 491 } 492 493 public static boolean isDoCoMo(final int vcardType) { 494 return ((vcardType & FLAG_DOCOMO) != 0); 495 } 496 497 private VCardConfig() { 498 } 499}