VCardUtils.java revision be378d5b188f51cf717e5309e3c39180e85833a8
14199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/* 24199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Copyright (C) 2009 The Android Open Source Project 34199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 44199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Licensed under the Apache License, Version 2.0 (the "License"); 54199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * you may not use this file except in compliance with the License. 64199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * You may obtain a copy of the License at 74199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 84199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * http://www.apache.org/licenses/LICENSE-2.0 94199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Unless required by applicable law or agreed to in writing, software 114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * distributed under the License is distributed on an "AS IS" BASIS, 124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * See the License for the specific language governing permissions and 144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * limitations under the License. 154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawapackage com.android.vcard; 174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 18be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawaimport com.android.vcard.exception.VCardException; 19be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa 204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport org.apache.commons.codec.DecoderException; 214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport org.apache.commons.codec.net.QuotedPrintableCodec; 224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.content.ContentProviderOperation; 244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.Data; 254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Im; 264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Phone; 274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.telephony.PhoneNumberUtils; 294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.text.TextUtils; 304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.util.Log; 314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.UnsupportedEncodingException; 334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.ArrayList; 344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Arrays; 354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Collection; 364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.HashMap; 374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.HashSet; 384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.List; 394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Map; 404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Set; 414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/** 434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Utilities for VCard handling codes. 444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawapublic class VCardUtils { 464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String LOG_TAG = "VCardUtils"; 474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Note that not all types are included in this map/set, since, for example, TYPE_HOME_FAX is 494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // converted to two parameter Strings. These only contain some minor fields valid in both 504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // vCard and current (as of 2009-08-07) Contacts structure. 514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final Map<Integer, String> sKnownPhoneTypesMap_ItoS; 524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final Set<String> sPhoneTypesUnknownToContactsSet; 534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final Map<String, Integer> sKnownPhoneTypeMap_StoI; 544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final Map<Integer, String> sKnownImPropNameMap_ItoS; 554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final Set<String> sMobilePhoneLabelSet; 564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa static { 584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>(); 594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI = new HashMap<String, Integer>(); 604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_CAR, VCardConstants.PARAM_TYPE_CAR); 624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_CAR, Phone.TYPE_CAR); 634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_PAGER, VCardConstants.PARAM_TYPE_PAGER); 644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_PAGER, Phone.TYPE_PAGER); 654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_ISDN, VCardConstants.PARAM_TYPE_ISDN); 664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_ISDN, Phone.TYPE_ISDN); 674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_HOME, Phone.TYPE_HOME); 694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_WORK, Phone.TYPE_WORK); 704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_CELL, Phone.TYPE_MOBILE); 714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_OTHER, Phone.TYPE_OTHER); 734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_CALLBACK, 744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Phone.TYPE_CALLBACK); 754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put( 764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa VCardConstants.PARAM_PHONE_EXTRA_TYPE_COMPANY_MAIN, Phone.TYPE_COMPANY_MAIN); 774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_RADIO, Phone.TYPE_RADIO); 784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_TTY_TDD, 794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Phone.TYPE_TTY_TDD); 804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_ASSISTANT, 814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Phone.TYPE_ASSISTANT); 824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sPhoneTypesUnknownToContactsSet = new HashSet<String>(); 844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MODEM); 854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MSG); 864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_BBS); 874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_VIDEO); 884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownImPropNameMap_ItoS = new HashMap<Integer, String>(); 904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM); 914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN); 924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_YAHOO, VCardConstants.PROPERTY_X_YAHOO); 934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME); 944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_GOOGLE_TALK, 954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa VCardConstants.PROPERTY_X_GOOGLE_TALK); 964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ); 974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER); 984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_QQ, VCardConstants.PROPERTY_X_QQ); 994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_NETMEETING, VCardConstants.PROPERTY_X_NETMEETING); 1004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // \u643A\u5E2F\u96FB\u8A71 = Full-width Hiragana "Keitai-Denwa" (mobile phone) 1024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // \u643A\u5E2F = Full-width Hiragana "Keitai" (mobile phone) 1034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // \u30B1\u30A4\u30BF\u30A4 = Full-width Katakana "Keitai" (mobile phone) 1044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // \uFF79\uFF72\uFF80\uFF72 = Half-width Katakana "Keitai" (mobile phone) 1054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sMobilePhoneLabelSet = new HashSet<String>(Arrays.asList( 1064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "MOBILE", "\u643A\u5E2F\u96FB\u8A71", "\u643A\u5E2F", "\u30B1\u30A4\u30BF\u30A4", 1074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "\uFF79\uFF72\uFF80\uFF72")); 1084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static String getPhoneTypeString(Integer type) { 1114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return sKnownPhoneTypesMap_ItoS.get(type); 1124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 1154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Returns Interger when the given types can be parsed as known type. Returns String object 1164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * when not, which should be set to label. 1174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static Object getPhoneTypeFromStrings(Collection<String> types, 1194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String number) { 1204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (number == null) { 1214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa number = ""; 1224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int type = -1; 1244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String label = null; 1254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean isFax = false; 1264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean hasPref = false; 1274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (types != null) { 1294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (String typeString : types) { 1304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (typeString == null) { 1314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 1324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeString = typeString.toUpperCase(); 1344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (typeString.equals(VCardConstants.PARAM_TYPE_PREF)) { 1354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa hasPref = true; 1364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (typeString.equals(VCardConstants.PARAM_TYPE_FAX)) { 1374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa isFax = true; 1384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (typeString.startsWith("X-") && type < 0) { 1404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeString = typeString.substring(2); 1414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (typeString.length() == 0) { 1434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 1444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer tmp = sKnownPhoneTypeMap_StoI.get(typeString); 1464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (tmp != null) { 1474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int typeCandidate = tmp; 1484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TYPE_PAGER is prefered when the number contains @ surronded by 1494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // a pager number and a domain name. 1504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // e.g. 1514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // o 1111@domain.com 1524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // x @domain.com 1534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // x 1111@ 1544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int indexOfAt = number.indexOf("@"); 1554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if ((typeCandidate == Phone.TYPE_PAGER 1564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && 0 < indexOfAt && indexOfAt < number.length() - 1) 1574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa || type < 0 1584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa || type == Phone.TYPE_CUSTOM) { 1594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa type = tmp; 1604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (type < 0) { 1624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa type = Phone.TYPE_CUSTOM; 1634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa label = typeString; 1644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (type < 0) { 1694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (hasPref) { 1704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa type = Phone.TYPE_MAIN; 1714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // default to TYPE_HOME 1734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa type = Phone.TYPE_HOME; 1744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (isFax) { 1774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (type == Phone.TYPE_HOME) { 1784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa type = Phone.TYPE_FAX_HOME; 1794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (type == Phone.TYPE_WORK) { 1804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa type = Phone.TYPE_FAX_WORK; 1814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (type == Phone.TYPE_OTHER) { 1824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa type = Phone.TYPE_OTHER_FAX; 1834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (type == Phone.TYPE_CUSTOM) { 1864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return label; 1874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return type; 1894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @SuppressWarnings("deprecation") 1934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static boolean isMobilePhoneLabel(final String label) { 1944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // For backward compatibility. 1954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Detail: Until Donut, there isn't TYPE_MOBILE for email while there is now. 1964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // To support mobile type at that time, this custom label had been used. 1974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return ("_AUTO_CELL".equals(label) || sMobilePhoneLabelSet.contains(label)); 1984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static boolean isValidInV21ButUnknownToContactsPhoteType(final String label) { 2014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return sPhoneTypesUnknownToContactsSet.contains(label); 2024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static String getPropertyNameForIm(final int protocol) { 2054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return sKnownImPropNameMap_ItoS.get(protocol); 2064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static String[] sortNameElements(final int vcardType, 2094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String familyName, final String middleName, final String givenName) { 2104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String[] list = new String[3]; 2114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int nameOrderType = VCardConfig.getNameOrderType(vcardType); 2124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa switch (nameOrderType) { 2134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case VCardConfig.NAME_ORDER_JAPANESE: { 2144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (containsOnlyPrintableAscii(familyName) && 2154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa containsOnlyPrintableAscii(givenName)) { 2164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[0] = givenName; 2174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[1] = middleName; 2184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[2] = familyName; 2194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[0] = familyName; 2214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[1] = middleName; 2224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[2] = givenName; 2234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 2254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case VCardConfig.NAME_ORDER_EUROPE: { 2274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[0] = middleName; 2284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[1] = givenName; 2294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[2] = familyName; 2304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 2314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa default: { 2334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[0] = givenName; 2344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[1] = middleName; 2354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list[2] = familyName; 2364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 2374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return list; 2404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static int getPhoneNumberFormat(final int vcardType) { 2434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (VCardConfig.isJapaneseDevice(vcardType)) { 2444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return PhoneNumberUtils.FORMAT_JAPAN; 2454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return PhoneNumberUtils.FORMAT_NANP; 2474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 2514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 2524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Inserts postal data into the builder object. 2534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 2544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 2554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Note that the data structure of ContactsContract is different from that defined in vCard. 2564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * So some conversion may be performed in this method. 2574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 2584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 2594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static void insertStructuredPostalDataUsingContactsStruct(int vcardType, 2604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final ContentProviderOperation.Builder builder, 2614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final VCardEntry.PostalData postalData) { 2624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValueBackReference(StructuredPostal.RAW_CONTACT_ID, 0); 2634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE); 2644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(StructuredPostal.TYPE, postalData.type); 2664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (postalData.type == StructuredPostal.TYPE_CUSTOM) { 2674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(StructuredPostal.LABEL, postalData.label); 2684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String streetString; 2714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(postalData.street)) { 2724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(postalData.extendedAddress)) { 2734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa streetString = null; 2744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa streetString = postalData.extendedAddress; 2764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(postalData.extendedAddress)) { 2794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa streetString = postalData.street; 2804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa streetString = postalData.street + " " + postalData.extendedAddress; 2824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(StructuredPostal.POBOX, postalData.pobox); 2854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(StructuredPostal.STREET, streetString); 2864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(StructuredPostal.CITY, postalData.localty); 2874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(StructuredPostal.REGION, postalData.region); 2884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(StructuredPostal.POSTCODE, postalData.postalCode); 2894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(StructuredPostal.COUNTRY, postalData.country); 2904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(StructuredPostal.FORMATTED_ADDRESS, 2924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa postalData.getFormattedAddress(vcardType)); 2934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (postalData.isPrimary) { 2944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.withValue(Data.IS_PRIMARY, 1); 2954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static String constructNameFromElements(final int vcardType, 2994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String familyName, final String middleName, final String givenName) { 3004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return constructNameFromElements(vcardType, familyName, middleName, givenName, 3014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa null, null); 3024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static String constructNameFromElements(final int vcardType, 3054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String familyName, final String middleName, final String givenName, 3064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String prefix, final String suffix) { 3074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final StringBuilder builder = new StringBuilder(); 3084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String[] nameList = sortNameElements(vcardType, familyName, middleName, givenName); 3094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean first = true; 3104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(prefix)) { 3114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa first = false; 3124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(prefix); 3134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final String namePart : nameList) { 3154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(namePart)) { 3164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (first) { 3174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa first = false; 3184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 3194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(' '); 3204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(namePart); 3224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(suffix)) { 3254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!first) { 3264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(' '); 3274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(suffix); 3294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 3314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static List<String> constructListFromValue(final String value, 3344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean isV30) { 3354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final List<String> list = new ArrayList<String>(); 3364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa StringBuilder builder = new StringBuilder(); 3374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int length = value.length(); 3384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 3394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa char ch = value.charAt(i); 3404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == '\\' && i < length - 1) { 3414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa char nextCh = value.charAt(i + 1); 3424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String unescapedString = 343be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa (isV30 ? VCardParserImpl_V30.escapeCharacter(nextCh) : 3444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa VCardParserImpl_V21.unescapeCharacter(nextCh)); 3454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (unescapedString != null) { 3464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(unescapedString); 3474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa i++; 3484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 3494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(ch); 3504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (ch == ';') { 3524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list.add(builder.toString()); 3534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder = new StringBuilder(); 3544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 3554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(ch); 3564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list.add(builder.toString()); 3594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return list; 3604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static boolean containsOnlyPrintableAscii(final String...values) { 3634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (values == null) { 3644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 3654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return containsOnlyPrintableAscii(Arrays.asList(values)); 3674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static boolean containsOnlyPrintableAscii(final Collection<String> values) { 3704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (values == null) { 3714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 3724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final String value : values) { 3744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(value)) { 3754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 3764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isPrintableAsciiOnly(value)) { 3784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 3794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 3824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 3854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 3864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * This is useful when checking the string should be encoded into quoted-printable 3874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * or not, which is required by vCard 2.1. 3884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 3894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 3904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * See the definition of "7bit" in vCard 2.1 spec for more information. 3914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 3924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 3934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static boolean containsOnlyNonCrLfPrintableAscii(final String...values) { 3944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (values == null) { 3954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 3964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return containsOnlyNonCrLfPrintableAscii(Arrays.asList(values)); 3984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static boolean containsOnlyNonCrLfPrintableAscii(final Collection<String> values) { 4014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (values == null) { 4024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 4034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int asciiFirst = 0x20; 4054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int asciiLast = 0x7E; // included 4064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final String value : values) { 4074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(value)) { 4084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 4094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = value.length(); 4114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) { 4124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int c = value.codePointAt(i); 4134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!(asciiFirst <= c && c <= asciiLast)) { 4144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 4154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 4194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final Set<Character> sUnAcceptableAsciiInV21WordSet = 4224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa new HashSet<Character>(Arrays.asList('[', ']', '=', ':', '.', ',', ' ')); 4234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 4254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 4264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * This is useful since vCard 3.0 often requires the ("X-") properties and groups 4274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * should contain only alphabets, digits, and hyphen. 4284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 4294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 4304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Note: It is already known some devices (wrongly) outputs properties with characters 4314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * which should not be in the field. One example is "X-GOOGLE TALK". We accept 4324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * such kind of input but must never output it unless the target is very specific 4334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * to the device which is able to parse the malformed input. 4344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 4354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 4364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static boolean containsOnlyAlphaDigitHyphen(final String...values) { 4374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (values == null) { 4384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 4394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return containsOnlyAlphaDigitHyphen(Arrays.asList(values)); 4414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static boolean containsOnlyAlphaDigitHyphen(final Collection<String> values) { 4444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (values == null) { 4454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 4464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int upperAlphabetFirst = 0x41; // A 4484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int upperAlphabetAfterLast = 0x5b; // [ 4494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int lowerAlphabetFirst = 0x61; // a 4504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int lowerAlphabetAfterLast = 0x7b; // { 4514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int digitFirst = 0x30; // 0 4524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int digitAfterLast = 0x3A; // : 4534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int hyphen = '-'; 4544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final String str : values) { 4554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(str)) { 4564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 4574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = str.length(); 4594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) { 4604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int codepoint = str.codePointAt(i); 4614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetAfterLast) || 4624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (upperAlphabetFirst <= codepoint && codepoint < upperAlphabetAfterLast) || 4634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (digitFirst <= codepoint && codepoint < digitAfterLast) || 4644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (codepoint == hyphen))) { 4654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 4664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 4704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 4734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 4744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Returns true when the given String is categorized as "word" specified in vCard spec 2.1. 4754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 4764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 4774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard 2.1 specifies:<br /> 4784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * word = <any printable 7bit us-ascii except []=:., > 4794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 4804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 4814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static boolean isV21Word(final String value) { 4824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(value)) { 4834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 4844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int asciiFirst = 0x20; 4864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int asciiLast = 0x7E; // included 4874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = value.length(); 4884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) { 4894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int c = value.codePointAt(i); 4904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!(asciiFirst <= c && c <= asciiLast) || 4914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sUnAcceptableAsciiInV21WordSet.contains((char)c)) { 4924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 4934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 4964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static String toHalfWidthString(final String orgString) { 4994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(orgString)) { 5004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return null; 5014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final StringBuilder builder = new StringBuilder(); 5034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = orgString.length(); 5044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i = orgString.offsetByCodePoints(i, 1)) { 5054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // All Japanese character is able to be expressed by char. 5064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Do not need to use String#codepPointAt(). 5074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final char ch = orgString.charAt(i); 5084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch); 5094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (halfWidthText != null) { 5104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(halfWidthText); 5114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 5124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(ch); 5134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 5164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 5194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Guesses the format of input image. Currently just the first few bytes are used. 5204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * The type "GIF", "PNG", or "JPEG" is returned when possible. Returns null when 5214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * the guess failed. 5224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @param input Image as byte array. 5234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @return The image type or null when the type cannot be determined. 5244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 5254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static String guessImageType(final byte[] input) { 5264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (input == null) { 5274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return null; 5284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (input.length >= 3 && input[0] == 'G' && input[1] == 'I' && input[2] == 'F') { 5304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return "GIF"; 5314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (input.length >= 4 && input[0] == (byte) 0x89 5324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && input[1] == 'P' && input[2] == 'N' && input[3] == 'G') { 5334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Note: vCard 2.1 officially does not support PNG, but we may have it and 5344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // using X- word like "X-PNG" may not let importers know it is PNG. 5354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // So we use the String "PNG" as is... 5364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return "PNG"; 5374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (input.length >= 2 && input[0] == (byte) 0xff 5384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && input[1] == (byte) 0xd8) { 5394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return "JPEG"; 5404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 5414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return null; 5424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 5464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @return True when all the given values are null or empty Strings. 5474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 5484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static boolean areAllEmpty(final String...values) { 5494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (values == null) { 5504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 5514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final String value : values) { 5544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(value)) { 5554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 5564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 5594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa //// The methods bellow may be used by unit test. 5624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 56458610106ce61adad9b1caa1fe9f7925c3e938babDaisuke Miyakawa * Unquotes given Quoted-Printable value. value must not be null. 5654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 56658610106ce61adad9b1caa1fe9f7925c3e938babDaisuke Miyakawa public static String parseQuotedPrintable( 56758610106ce61adad9b1caa1fe9f7925c3e938babDaisuke Miyakawa final String value, boolean strictLineBreaking, 5684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String sourceCharset, String targetCharset) { 5694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // "= " -> " ", "=\t" -> "\t". 5704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Previous code had done this replacement. Keep on the safe side. 5714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String quotedPrintable; 5724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa { 5734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final StringBuilder builder = new StringBuilder(); 5744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = value.length(); 5754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 5764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa char ch = value.charAt(i); 5774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == '=' && i < length - 1) { 5784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa char nextCh = value.charAt(i + 1); 5794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (nextCh == ' ' || nextCh == '\t') { 5804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(nextCh); 5814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa i++; 5824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 5834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(ch); 5864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa quotedPrintable = builder.toString(); 5884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String[] lines; 5914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (strictLineBreaking) { 5924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa lines = quotedPrintable.split("\r\n"); 5934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 5944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa StringBuilder builder = new StringBuilder(); 5954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = quotedPrintable.length(); 5964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa ArrayList<String> list = new ArrayList<String>(); 5974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 5984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa char ch = quotedPrintable.charAt(i); 5994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == '\n') { 6004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list.add(builder.toString()); 6014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder = new StringBuilder(); 6024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (ch == '\r') { 6034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list.add(builder.toString()); 6044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder = new StringBuilder(); 6054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (i < length - 1) { 6064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa char nextCh = quotedPrintable.charAt(i + 1); 6074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (nextCh == '\n') { 6084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa i++; 6094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 6124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(ch); 6134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String lastLine = builder.toString(); 6164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (lastLine.length() > 0) { 6174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa list.add(lastLine); 6184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa lines = list.toArray(new String[0]); 6204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final StringBuilder builder = new StringBuilder(); 6234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (String line : lines) { 6244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line.endsWith("=")) { 6254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa line = line.substring(0, line.length() - 1); 6264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(line); 6284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawString = builder.toString(); 6314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(rawString)) { 6324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, "Given raw string is empty."); 6334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa byte[] rawBytes = null; 6364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 6374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawBytes = rawString.getBytes(sourceCharset); 6384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (UnsupportedEncodingException e) { 6394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, "Failed to decode: " + sourceCharset); 6404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawBytes = rawString.getBytes(); 6414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa byte[] decodedBytes = null; 6444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 6454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa decodedBytes = QuotedPrintableCodec.decodeQuotedPrintable(rawBytes); 6464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (DecoderException e) { 6474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.e(LOG_TAG, "DecoderException is thrown."); 6484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa decodedBytes = rawBytes; 6494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 6524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return new String(decodedBytes, targetCharset); 6534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (UnsupportedEncodingException e) { 6544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset); 6554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return new String(decodedBytes); 6564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 659be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa public static final VCardParser getAppropriateParser(int vcardType) 660be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa throws VCardException { 661be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa if (VCardConfig.isVersion21(vcardType)) { 662be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa return new VCardParser_V21(); 663be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa } else if (VCardConfig.isVersion30(vcardType)) { 664be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa return new VCardParser_V30(); 665be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa } else if (VCardConfig.isVersion40(vcardType)) { 666be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa return new VCardParser_V40(); 667be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa } else { 668be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa throw new VCardException("Version is not specified"); 669be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa } 670be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa } 671be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa 672be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa // TODO: utilities for vCard 4.0: datetime, timestamp, integer, float, and boolean 673be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa 6744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private VCardUtils() { 6754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa} 677