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