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}