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"); you may not 54199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * use this file except in compliance with the License. You may obtain a copy of 64199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 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, WITHOUT 124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * License for the specific language governing permissions and limitations under 144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * the License. 154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawapackage com.android.vcard; 174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 189919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawaimport com.android.vcard.VCardUtils.PhoneNumberUtilsPort; 199919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa 204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.content.ContentValues; 214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Email; 224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Event; 234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Im; 244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Nickname; 254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Note; 264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Organization; 274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Phone; 284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Photo; 294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Relation; 30422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.SipAddress; 314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Website; 3495e66b00988bc16ecc17df31e47c873b2554b8ccinshikimport android.telephony.PhoneNumberUtils; 354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.text.TextUtils; 364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.util.Base64; 374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.util.Log; 384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.UnsupportedEncodingException; 404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.ArrayList; 414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Arrays; 424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Collections; 434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.HashMap; 444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.HashSet; 454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.List; 464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Map; 474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Set; 484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/** 504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * The class which lets users create their own vCard String. Typical usage is as follows: 524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <pre class="prettyprint">final VCardBuilder builder = new VCardBuilder(vcardType); 544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE)) 554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE)) 564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE)) 574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE)) 584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE)) 594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE)) 604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE)) 614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE)) 624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE)) 634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE)) 644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE)) 654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * .appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE)); 664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * return builder.toString();</pre> 674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawapublic class VCardBuilder { 6902117b3d19787ff65486b9f9db8abd338ae4c9f9Daisuke Miyakawa private static final String LOG_TAG = VCardConstants.LOG_TAG; 704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // If you add the other element, please check all the columns are able to be 724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // converted to String. 734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // e.g. BLOB is not what we can handle here now. 754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final Set<String> sAllowedAndroidPropertySet = 764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Collections.unmodifiableSet(new HashSet<String>(Arrays.asList( 774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Nickname.CONTENT_ITEM_TYPE, Event.CONTENT_ITEM_TYPE, 784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Relation.CONTENT_ITEM_TYPE))); 794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static final int DEFAULT_PHONE_TYPE = Phone.TYPE_HOME; 814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static final int DEFAULT_POSTAL_TYPE = StructuredPostal.TYPE_HOME; 824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static final int DEFAULT_EMAIL_TYPE = Email.TYPE_OTHER; 834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String VCARD_DATA_VCARD = "VCARD"; 854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String VCARD_DATA_PUBLIC = "PUBLIC"; 864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String VCARD_PARAM_SEPARATOR = ";"; 884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String VCARD_END_OF_LINE = "\r\n"; 894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String VCARD_DATA_SEPARATOR = ":"; 904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String VCARD_ITEM_SEPARATOR = ";"; 914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String VCARD_WS = " "; 924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String VCARD_PARAM_EQUAL = "="; 934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String VCARD_PARAM_ENCODING_QP = 954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "ENCODING=" + VCardConstants.PARAM_ENCODING_QP; 964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String VCARD_PARAM_ENCODING_BASE64_V21 = 974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "ENCODING=" + VCardConstants.PARAM_ENCODING_BASE64; 9836ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa private static final String VCARD_PARAM_ENCODING_BASE64_AS_B = 994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "ENCODING=" + VCardConstants.PARAM_ENCODING_B; 1004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String SHIFT_JIS = "SHIFT_JIS"; 1024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final int mVCardType; 1044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10536ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa private final boolean mIsV30OrV40; 1064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final boolean mIsJapaneseMobilePhone; 1074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final boolean mOnlyOneNoteFieldIsAvailable; 1084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final boolean mIsDoCoMo; 1094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final boolean mShouldUseQuotedPrintable; 1104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final boolean mUsesAndroidProperty; 1114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final boolean mUsesDefactProperty; 1124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final boolean mAppendTypeParamName; 1134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final boolean mRefrainsQPToNameProperties; 1144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final boolean mNeedsToConvertPhoneticString; 1154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final boolean mShouldAppendCharsetParam; 1174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final String mCharset; 1194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private final String mVCardCharsetParameter; 1204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private StringBuilder mBuilder; 1224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private boolean mEndAppended; 1234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder(final int vcardType) { 1254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Default charset should be used 1264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa this(vcardType, null); 1274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 1304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @param vcardType 1314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @param charset If null, we use default charset for export. 13236ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa * @hide 1334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder(final int vcardType, String charset) { 1354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mVCardType = vcardType; 1364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 137422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa if (VCardConfig.isVersion40(vcardType)) { 138422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa Log.w(LOG_TAG, "Should not use vCard 4.0 when building vCard. " + 139422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa "It is not officially published yet."); 140422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } 14136ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa 14236ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa mIsV30OrV40 = VCardConfig.isVersion30(vcardType) || VCardConfig.isVersion40(vcardType); 1434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mShouldUseQuotedPrintable = VCardConfig.shouldUseQuotedPrintable(vcardType); 1444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mIsDoCoMo = VCardConfig.isDoCoMo(vcardType); 1454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mIsJapaneseMobilePhone = VCardConfig.needsToConvertPhoneticString(vcardType); 1464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mOnlyOneNoteFieldIsAvailable = VCardConfig.onlyOneNoteFieldIsAvailable(vcardType); 1474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mUsesAndroidProperty = VCardConfig.usesAndroidSpecificProperty(vcardType); 1484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mUsesDefactProperty = VCardConfig.usesDefactProperty(vcardType); 1494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mRefrainsQPToNameProperties = VCardConfig.shouldRefrainQPToNameProperties(vcardType); 1504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mAppendTypeParamName = VCardConfig.appendTypeParamName(vcardType); 1514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mNeedsToConvertPhoneticString = VCardConfig.needsToConvertPhoneticString(vcardType); 1524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // vCard 2.1 requires charset. 1544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // vCard 3.0 does not allow it but we found some devices use it to determine 1554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // the exact charset. 1564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // We currently append it only when charset other than UTF_8 is used. 15736ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa mShouldAppendCharsetParam = 15836ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa !(VCardConfig.isVersion30(vcardType) && "UTF-8".equalsIgnoreCase(charset)); 1594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (VCardConfig.isDoCoMo(vcardType)) { 1614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!SHIFT_JIS.equalsIgnoreCase(charset)) { 162422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa /* Log.w(LOG_TAG, 1634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "The charset \"" + charset + "\" is used while " 164422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa + SHIFT_JIS + " is needed to be used."); */ 1654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(charset)) { 1664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mCharset = SHIFT_JIS; 1674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1689919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa /*try { 1694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa charset = CharsetUtils.charsetForVendor(charset).name(); 1704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (UnsupportedCharsetException e) { 1714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.i(LOG_TAG, 1724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "Career-specific \"" + charset + "\" was not found (as usual). " 1734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + "Use it as is."); 1749919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa }*/ 1754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mCharset = charset; 1764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1789919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa /*if (mIsDoCoMo) { 1794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 1804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name(); 1814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (UnsupportedCharsetException e) { 1824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.e(LOG_TAG, 1834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "DoCoMo-specific SHIFT_JIS was not found. " 1844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + "Use SHIFT_JIS as is."); 1854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa charset = SHIFT_JIS; 1864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 1894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name(); 1904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (UnsupportedCharsetException e) { 1914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.e(LOG_TAG, 1924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "Career-specific SHIFT_JIS was not found. " 1934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + "Use SHIFT_JIS as is."); 1944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa charset = SHIFT_JIS; 1954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1969919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa }*/ 1974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mCharset = charset; 1984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mVCardCharsetParameter = "CHARSET=" + SHIFT_JIS; 2004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(charset)) { 2024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.i(LOG_TAG, 2034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "Use the charset \"" + VCardConfig.DEFAULT_EXPORT_CHARSET 2044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + "\" for export."); 2054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mCharset = VCardConfig.DEFAULT_EXPORT_CHARSET; 2064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mVCardCharsetParameter = "CHARSET=" + VCardConfig.DEFAULT_EXPORT_CHARSET; 2074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2089919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa /* 2094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 2104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa charset = CharsetUtils.charsetForVendor(charset).name(); 2114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (UnsupportedCharsetException e) { 2124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.i(LOG_TAG, 2134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "Career-specific \"" + charset + "\" was not found (as usual). " 2144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + "Use it as is."); 2159919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa }*/ 2164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mCharset = charset; 2174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mVCardCharsetParameter = "CHARSET=" + charset; 2184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa clear(); 2214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void clear() { 2244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder = new StringBuilder(); 2254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mEndAppended = false; 2264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_BEGIN, VCARD_DATA_VCARD); 22736ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa if (VCardConfig.isVersion40(mVCardType)) { 22836ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_VERSION, VCardConstants.VERSION_V40); 22936ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa } else if (VCardConfig.isVersion30(mVCardType)) { 2304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_VERSION, VCardConstants.VERSION_V30); 2314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 23236ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa if (!VCardConfig.isVersion21(mVCardType)) { 23336ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa Log.w(LOG_TAG, "Unknown vCard version detected."); 23436ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa } 2354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_VERSION, VCardConstants.VERSION_V21); 2364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private boolean containsNonEmptyName(final ContentValues contentValues) { 2404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String familyName = contentValues.getAsString(StructuredName.FAMILY_NAME); 2414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String middleName = contentValues.getAsString(StructuredName.MIDDLE_NAME); 2424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String givenName = contentValues.getAsString(StructuredName.GIVEN_NAME); 2434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String prefix = contentValues.getAsString(StructuredName.PREFIX); 2444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String suffix = contentValues.getAsString(StructuredName.SUFFIX); 2454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String phoneticFamilyName = 2464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa contentValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME); 2474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String phoneticMiddleName = 2484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa contentValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME); 2494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String phoneticGivenName = 2504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa contentValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME); 2514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String displayName = contentValues.getAsString(StructuredName.DISPLAY_NAME); 2524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return !(TextUtils.isEmpty(familyName) && TextUtils.isEmpty(middleName) && 2534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa TextUtils.isEmpty(givenName) && TextUtils.isEmpty(prefix) && 2544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa TextUtils.isEmpty(suffix) && TextUtils.isEmpty(phoneticFamilyName) && 2554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa TextUtils.isEmpty(phoneticMiddleName) && TextUtils.isEmpty(phoneticGivenName) && 2564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa TextUtils.isEmpty(displayName)); 2574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2598bde974dac0ef49da5fda52da09952ebb4b5fd89Daisuke Miyakawa private ContentValues getPrimaryContentValueWithStructuredName( 2608bde974dac0ef49da5fda52da09952ebb4b5fd89Daisuke Miyakawa final List<ContentValues> contentValuesList) { 2614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa ContentValues primaryContentValues = null; 2624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa ContentValues subprimaryContentValues = null; 2634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (ContentValues contentValues : contentValuesList) { 2644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValues == null){ 2654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 2664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Integer isSuperPrimary = contentValues.getAsInteger(StructuredName.IS_SUPER_PRIMARY); 2684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (isSuperPrimary != null && isSuperPrimary > 0) { 2694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // We choose "super primary" ContentValues. 2704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa primaryContentValues = contentValues; 2714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 2724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (primaryContentValues == null) { 2734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // We choose the first "primary" ContentValues 2744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // if "super primary" ContentValues does not exist. 2754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer isPrimary = contentValues.getAsInteger(StructuredName.IS_PRIMARY); 2764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (isPrimary != null && isPrimary > 0 && 2774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa containsNonEmptyName(contentValues)) { 2784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa primaryContentValues = contentValues; 2794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Do not break, since there may be ContentValues with "super primary" 2804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // afterword. 2814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (subprimaryContentValues == null && 2824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa containsNonEmptyName(contentValues)) { 2834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa subprimaryContentValues = contentValues; 2844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (primaryContentValues == null) { 2894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (subprimaryContentValues != null) { 2904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // We choose the first ContentValues if any "primary" ContentValues does not exist. 2914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa primaryContentValues = subprimaryContentValues; 2924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2938bde974dac0ef49da5fda52da09952ebb4b5fd89Daisuke Miyakawa // There's no appropriate ContentValue with StructuredName. 2944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa primaryContentValues = new ContentValues(); 2954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return primaryContentValues; 2994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 3023d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa * To avoid unnecessary complication in logic, we use this method to construct N, FN 3033d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa * properties for vCard 4.0. 3043d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa */ 3053d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa private VCardBuilder appendNamePropertiesV40(final List<ContentValues> contentValuesList) { 3063d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa if (mIsDoCoMo || mNeedsToConvertPhoneticString) { 3073d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // Ignore all flags that look stale from the view of vCard 4.0 to 3083d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // simplify construction algorithm. Actually we don't have any vCard file 3093d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // available from real world yet, so we may need to re-enable some of these 3103d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // in the future. 3113d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa Log.w(LOG_TAG, "Invalid flag is used in vCard 4.0 construction. Ignored."); 3123d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } 3133d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 3143d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa if (contentValuesList == null || contentValuesList.isEmpty()) { 3153d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_FN, ""); 3163d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa return this; 3173d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } 3183d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 3193d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // We have difficulty here. How can we appropriately handle StructuredName with 3203d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // missing parts necessary for displaying while it has suppremental information. 3213d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // 3223d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // e.g. How to handle non-empty phonetic names with empty structured names? 3233d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 3248bde974dac0ef49da5fda52da09952ebb4b5fd89Daisuke Miyakawa final ContentValues contentValues = 3258bde974dac0ef49da5fda52da09952ebb4b5fd89Daisuke Miyakawa getPrimaryContentValueWithStructuredName(contentValuesList); 3263d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa String familyName = contentValues.getAsString(StructuredName.FAMILY_NAME); 3273d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String middleName = contentValues.getAsString(StructuredName.MIDDLE_NAME); 3283d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String givenName = contentValues.getAsString(StructuredName.GIVEN_NAME); 3293d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String prefix = contentValues.getAsString(StructuredName.PREFIX); 3303d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String suffix = contentValues.getAsString(StructuredName.SUFFIX); 3313d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String formattedName = contentValues.getAsString(StructuredName.DISPLAY_NAME); 3323d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa if (TextUtils.isEmpty(familyName) 3333d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa && TextUtils.isEmpty(givenName) 3343d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa && TextUtils.isEmpty(middleName) 3353d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa && TextUtils.isEmpty(prefix) 3363d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa && TextUtils.isEmpty(suffix)) { 3373d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa if (TextUtils.isEmpty(formattedName)) { 3383d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_FN, ""); 3393d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa return this; 3403d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } 3413d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa familyName = formattedName; 3423d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } 3433d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 3443d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String phoneticFamilyName = 3453d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa contentValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME); 3463d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String phoneticMiddleName = 3473d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa contentValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME); 3483d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String phoneticGivenName = 3493d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa contentValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME); 3503d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String escapedFamily = escapeCharacters(familyName); 3513d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String escapedGiven = escapeCharacters(givenName); 3523d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String escapedMiddle = escapeCharacters(middleName); 3533d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String escapedPrefix = escapeCharacters(prefix); 3543d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String escapedSuffix = escapeCharacters(suffix); 3553d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 3563d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_N); 3573d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 3583d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa if (!(TextUtils.isEmpty(phoneticFamilyName) && 3593d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa TextUtils.isEmpty(phoneticMiddleName) && 3603d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa TextUtils.isEmpty(phoneticGivenName))) { 3613d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 3623d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String sortAs = escapeCharacters(phoneticFamilyName) 3633d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa + ';' + escapeCharacters(phoneticGivenName) 3643d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa + ';' + escapeCharacters(phoneticMiddleName); 3653d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append("SORT-AS=").append( 3663d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa VCardUtils.toStringAsV40ParamValue(sortAs)); 3673d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } 3683d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 3693d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 3703d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(escapedFamily); 3713d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 3723d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(escapedGiven); 3733d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 3743d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(escapedMiddle); 3753d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 3763d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(escapedPrefix); 3773d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 3783d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(escapedSuffix); 3793d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 3803d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 3813d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa if (TextUtils.isEmpty(formattedName)) { 3823d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // Note: 3833d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // DISPLAY_NAME doesn't exist while some other elements do, which is usually 3843d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // weird in Android, as DISPLAY_NAME should (usually) be constructed 3853d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // from the others using locale information and its code points. 3863d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa Log.w(LOG_TAG, "DISPLAY_NAME is empty."); 3873d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 3883d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String escaped = escapeCharacters(VCardUtils.constructNameFromElements( 3893d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa VCardConfig.getNameOrderType(mVCardType), 3903d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa familyName, middleName, givenName, prefix, suffix)); 3913d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_FN, escaped); 3923d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } else { 3933d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa final String escapedFormatted = escapeCharacters(formattedName); 3943d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_FN); 3953d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 3963d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(escapedFormatted); 3973d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 3983d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } 3993d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 4003d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // We may need X- properties for phonetic names. 4013d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa appendPhoneticNameFields(contentValues); 4023d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa return this; 4033d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } 4043d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 4053d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa /** 4064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * For safety, we'll emit just one value around StructuredName, as external importers 4074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * may get confused with multiple "N", "FN", etc. properties, though it is valid in 4084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard spec. 4094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 4104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendNameProperties(final List<ContentValues> contentValuesList) { 4113d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa if (VCardConfig.isVersion40(mVCardType)) { 4123d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa return appendNamePropertiesV40(contentValuesList); 4133d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } 4143d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 4154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList == null || contentValuesList.isEmpty()) { 4163d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa if (VCardConfig.isVersion30(mVCardType)) { 4174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // vCard 3.0 requires "N" and "FN" properties. 41836ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa // vCard 4.0 does NOT require N, but we take care of possible backward 41936ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa // compatibility issues. 4204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_N, ""); 4214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_FN, ""); 42236ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa } else if (mIsDoCoMo) { 42336ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_N, ""); 4244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 4264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4288bde974dac0ef49da5fda52da09952ebb4b5fd89Daisuke Miyakawa final ContentValues contentValues = 4298bde974dac0ef49da5fda52da09952ebb4b5fd89Daisuke Miyakawa getPrimaryContentValueWithStructuredName(contentValuesList); 4304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String familyName = contentValues.getAsString(StructuredName.FAMILY_NAME); 4314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String middleName = contentValues.getAsString(StructuredName.MIDDLE_NAME); 4324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String givenName = contentValues.getAsString(StructuredName.GIVEN_NAME); 4334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String prefix = contentValues.getAsString(StructuredName.PREFIX); 4344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String suffix = contentValues.getAsString(StructuredName.SUFFIX); 4354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String displayName = contentValues.getAsString(StructuredName.DISPLAY_NAME); 4364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(familyName) || !TextUtils.isEmpty(givenName)) { 4384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyAppendCharsetParameterToName = 4394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa shouldAppendCharsetParam(familyName, givenName, middleName, prefix, suffix); 4404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintableToName = 4414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (!mRefrainsQPToNameProperties && 4424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !(VCardUtils.containsOnlyNonCrLfPrintableAscii(familyName) && 4434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa VCardUtils.containsOnlyNonCrLfPrintableAscii(givenName) && 4444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa VCardUtils.containsOnlyNonCrLfPrintableAscii(middleName) && 4454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa VCardUtils.containsOnlyNonCrLfPrintableAscii(prefix) && 4464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa VCardUtils.containsOnlyNonCrLfPrintableAscii(suffix))); 4474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String formattedName; 4494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(displayName)) { 4504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa formattedName = displayName; 4514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 4524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa formattedName = VCardUtils.constructNameFromElements( 4534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa VCardConfig.getNameOrderType(mVCardType), 4544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa familyName, middleName, givenName, prefix, suffix); 4554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyAppendCharsetParameterToFN = 4574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa shouldAppendCharsetParam(formattedName); 4584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintableToFN = 4594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !mRefrainsQPToNameProperties && 4604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(formattedName); 4614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedFamily; 4634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedGiven; 4644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedMiddle; 4654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedPrefix; 4664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedSuffix; 4674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintableToName) { 4684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedFamily = encodeQuotedPrintable(familyName); 4694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedGiven = encodeQuotedPrintable(givenName); 4704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedMiddle = encodeQuotedPrintable(middleName); 4714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPrefix = encodeQuotedPrintable(prefix); 4724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedSuffix = encodeQuotedPrintable(suffix); 4734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 4744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedFamily = escapeCharacters(familyName); 4754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedGiven = escapeCharacters(givenName); 4764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedMiddle = escapeCharacters(middleName); 4774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPrefix = escapeCharacters(prefix); 4784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedSuffix = escapeCharacters(suffix); 4794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedFormattedname = 4824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (reallyUseQuotedPrintableToFN ? 4834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodeQuotedPrintable(formattedName) : escapeCharacters(formattedName)); 4844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_N); 4864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mIsDoCoMo) { 4874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyAppendCharsetParameterToName) { 4884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 4894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 4904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintableToName) { 4924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 4934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 4944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 4964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // DoCoMo phones require that all the elements in the "family name" field. 4974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(formattedName); 4984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 4994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 5034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyAppendCharsetParameterToName) { 5044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 5054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 5064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintableToName) { 5084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 5094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 5104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 5124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedFamily); 5134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedGiven); 5154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedMiddle); 5174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedPrefix); 5194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedSuffix); 5214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 5234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // FN property 5254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_FN); 5264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyAppendCharsetParameterToFN) { 5274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 5284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 5294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintableToFN) { 5314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 5324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 5334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 5354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedFormattedname); 5364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 5374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (!TextUtils.isEmpty(displayName)) { 5384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintableToDisplayName = 5394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (!mRefrainsQPToNameProperties && 5404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(displayName)); 5414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedDisplayName = 5424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa reallyUseQuotedPrintableToDisplayName ? 5434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodeQuotedPrintable(displayName) : 5444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa escapeCharacters(displayName); 5454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5463d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // N 5474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_N); 5484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (shouldAppendCharsetParam(displayName)) { 5494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 5504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 5514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintableToDisplayName) { 5534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 5544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 5554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 5574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedDisplayName); 5584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 5624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 5633d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa 5643d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // FN 5654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_FN); 5664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Note: "CHARSET" param is not allowed in vCard 3.0, but we may add it 5684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // when it would be useful or necessary for external importers, 5694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // assuming the external importer allows this vioration of the spec. 5704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (shouldAppendCharsetParam(displayName)) { 5714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 5724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 5734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 5754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedDisplayName); 5764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 5773d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } else if (VCardConfig.isVersion30(mVCardType)) { 5784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_N, ""); 5794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_FN, ""); 5804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (mIsDoCoMo) { 5814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_N, ""); 5824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendPhoneticNameFields(contentValues); 5854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 5864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5883d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa /** 5893d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa * Emits SOUND;IRMC, SORT-STRING, and de-fact values for phonetic names like X-PHONETIC-FAMILY. 5903d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa */ 5914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private void appendPhoneticNameFields(final ContentValues contentValues) { 5924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String phoneticFamilyName; 5934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String phoneticMiddleName; 5944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String phoneticGivenName; 5954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa { 5964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String tmpPhoneticFamilyName = 5974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa contentValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME); 5984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String tmpPhoneticMiddleName = 5994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa contentValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME); 6004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String tmpPhoneticGivenName = 6014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa contentValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME); 6024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mNeedsToConvertPhoneticString) { 6034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneticFamilyName = VCardUtils.toHalfWidthString(tmpPhoneticFamilyName); 6044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneticMiddleName = VCardUtils.toHalfWidthString(tmpPhoneticMiddleName); 6054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneticGivenName = VCardUtils.toHalfWidthString(tmpPhoneticGivenName); 6064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 6074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneticFamilyName = tmpPhoneticFamilyName; 6084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneticMiddleName = tmpPhoneticMiddleName; 6094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneticGivenName = tmpPhoneticGivenName; 6104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(phoneticFamilyName) 6144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && TextUtils.isEmpty(phoneticMiddleName) 6154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && TextUtils.isEmpty(phoneticGivenName)) { 6164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mIsDoCoMo) { 6174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_SOUND); 6184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 6194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PARAM_TYPE_X_IRMC_N); 6204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 6214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 6224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 6234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 6244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 6254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 6264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return; 6284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6303d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa if (VCardConfig.isVersion40(mVCardType)) { 6313d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa // We don't want SORT-STRING anyway. 6323d77102a83d0e412046ca0ff9dfdef1a44050ca3Daisuke Miyakawa } else if (VCardConfig.isVersion30(mVCardType)) { 63336ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa final String sortString = 63436ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa VCardUtils.constructNameFromElements(mVCardType, 6354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneticFamilyName, phoneticMiddleName, phoneticGivenName); 6364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_SORT_STRING); 63736ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa if (VCardConfig.isVersion30(mVCardType) && shouldAppendCharsetParam(sortString)) { 63836ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa // vCard 3.0 does not force us to use UTF-8 and actually we see some 63936ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa // programs which emit this value. It is incorrect from the view of 64036ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa // specification, but actually necessary for parsing vCard with non-UTF-8 64136ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa // charsets, expecting other parsers not get confused with this value. 6424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 6434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 6444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 6464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(escapeCharacters(sortString)); 6474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 6484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (mIsJapaneseMobilePhone) { 6494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Note: There is no appropriate property for expressing 6504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // phonetic name (Yomigana in Japanese) in vCard 2.1, while there is in 6514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // vCard 3.0 (SORT-STRING). 6524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // We use DoCoMo's way when the device is Japanese one since it is already 6534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // supported by a lot of Japanese mobile phones. 6544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // This is "X-" property, so any parser hopefully would not get 6554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // confused with this. 6564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 6574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Also, DoCoMo's specification requires vCard composer to use just the first 6584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // column. 6594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // i.e. 6604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // good: SOUND;X-IRMC-N:Miyakawa Daisuke;;;; 6614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // bad : SOUND;X-IRMC-N:Miyakawa;Daisuke;;; 6624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_SOUND); 6634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 6644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PARAM_TYPE_X_IRMC_N); 6654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean reallyUseQuotedPrintable = 6674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (!mRefrainsQPToNameProperties 6684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && !(VCardUtils.containsOnlyNonCrLfPrintableAscii( 6694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneticFamilyName) 6704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && VCardUtils.containsOnlyNonCrLfPrintableAscii( 6714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneticMiddleName) 6724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && VCardUtils.containsOnlyNonCrLfPrintableAscii( 6734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneticGivenName))); 6744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedPhoneticFamilyName; 6764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedPhoneticMiddleName; 6774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedPhoneticGivenName; 6784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 6794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticFamilyName = encodeQuotedPrintable(phoneticFamilyName); 6804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticMiddleName = encodeQuotedPrintable(phoneticMiddleName); 6814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticGivenName = encodeQuotedPrintable(phoneticGivenName); 6824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 6834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticFamilyName = escapeCharacters(phoneticFamilyName); 6844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticMiddleName = escapeCharacters(phoneticMiddleName); 6854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticGivenName = escapeCharacters(phoneticGivenName); 6864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (shouldAppendCharsetParam(encodedPhoneticFamilyName, 6894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticMiddleName, encodedPhoneticGivenName)) { 6904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 6914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 6924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 6944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa { 6954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean first = true; 6964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(encodedPhoneticFamilyName)) { 6974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedPhoneticFamilyName); 6984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa first = false; 6994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(encodedPhoneticMiddleName)) { 7014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (first) { 7024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa first = false; 7034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 7044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(' '); 7054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedPhoneticMiddleName); 7074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(encodedPhoneticGivenName)) { 7094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!first) { 7104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(' '); 7114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedPhoneticGivenName); 7134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); // family;given 7164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); // given;middle 7174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); // middle;prefix 7184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); // prefix;suffix 7194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 7204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 7224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mUsesDefactProperty) { 7234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(phoneticGivenName)) { 7244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintable = 7254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 7264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticGivenName)); 7274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedPhoneticGivenName; 7284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 7294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticGivenName = encodeQuotedPrintable(phoneticGivenName); 7304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 7314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticGivenName = escapeCharacters(phoneticGivenName); 7324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_X_PHONETIC_FIRST_NAME); 7344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (shouldAppendCharsetParam(phoneticGivenName)) { 7354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 7364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 7374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 7394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 7404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 7414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 7434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedPhoneticGivenName); 7444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 7454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } // if (!TextUtils.isEmpty(phoneticGivenName)) 7464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(phoneticMiddleName)) { 7474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintable = 7484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 7494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticMiddleName)); 7504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedPhoneticMiddleName; 7514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 7524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticMiddleName = encodeQuotedPrintable(phoneticMiddleName); 7534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 7544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticMiddleName = escapeCharacters(phoneticMiddleName); 7554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_X_PHONETIC_MIDDLE_NAME); 7574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (shouldAppendCharsetParam(phoneticMiddleName)) { 7584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 7594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 7604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 7624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 7634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 7644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 7664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedPhoneticMiddleName); 7674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 7684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } // if (!TextUtils.isEmpty(phoneticGivenName)) 7694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(phoneticFamilyName)) { 7704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintable = 7714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 7724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticFamilyName)); 7734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedPhoneticFamilyName; 7744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 7754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticFamilyName = encodeQuotedPrintable(phoneticFamilyName); 7764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 7774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPhoneticFamilyName = escapeCharacters(phoneticFamilyName); 7784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_X_PHONETIC_LAST_NAME); 7804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (shouldAppendCharsetParam(phoneticFamilyName)) { 7814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 7824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 7834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 7854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 7864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 7874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 7894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedPhoneticFamilyName); 7904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 7914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } // if (!TextUtils.isEmpty(phoneticFamilyName)) 7924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 7954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendNickNames(final List<ContentValues> contentValuesList) { 7964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean useAndroidProperty; 79736ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa if (mIsV30OrV40) { // These specifications have NICKNAME property. 7984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa useAndroidProperty = false; 7994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (mUsesAndroidProperty) { 8004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa useAndroidProperty = true; 8014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 8024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // There's no way to add this field. 8034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 8044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList != null) { 8064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (ContentValues contentValues : contentValuesList) { 8074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String nickname = contentValues.getAsString(Nickname.NAME); 8084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(nickname)) { 8094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 8104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (useAndroidProperty) { 8124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendAndroidSpecificProperty(Nickname.CONTENT_ITEM_TYPE, contentValues); 8134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 8144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_NICKNAME, nickname); 8154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 8194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 8215fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa public VCardBuilder appendPhones(final List<ContentValues> contentValuesList, 8225fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa VCardPhoneNumberTranslationCallback translationCallback) { 8234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean phoneLineExists = false; 8244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList != null) { 8254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Set<String> phoneSet = new HashSet<String>(); 8264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (ContentValues contentValues : contentValuesList) { 8274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer typeAsObject = contentValues.getAsInteger(Phone.TYPE); 8284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String label = contentValues.getAsString(Phone.LABEL); 8294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer isPrimaryAsInteger = contentValues.getAsInteger(Phone.IS_PRIMARY); 8304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean isPrimary = (isPrimaryAsInteger != null ? 8314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (isPrimaryAsInteger > 0) : false); 8324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String phoneNumber = contentValues.getAsString(Phone.NUMBER); 8334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (phoneNumber != null) { 8344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneNumber = phoneNumber.trim(); 8354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(phoneNumber)) { 8374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 8384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 8404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int type = (typeAsObject != null ? typeAsObject : DEFAULT_PHONE_TYPE); 8415fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa // Note: We prioritize this callback over FLAG_REFRAIN_PHONE_NUMBER_FORMATTING 8425fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa // intentionally. In the future the flag will be replaced by callback 8435fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa // mechanism entirely. 8445fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa if (translationCallback != null) { 8455fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa phoneNumber = translationCallback.onValueReceived( 8465fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa phoneNumber, type, label, isPrimary); 8475fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa if (!phoneSet.contains(phoneNumber)) { 8485fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa phoneSet.add(phoneNumber); 8495fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa appendTelLine(type, label, phoneNumber, isPrimary); 8505fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa } 8515fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa } else if (type == Phone.TYPE_PAGER || 8524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa VCardConfig.refrainPhoneNumberFormatting(mVCardType)) { 8535fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa // Note: PAGER number needs unformatted "phone number". 8544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneLineExists = true; 8554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!phoneSet.contains(phoneNumber)) { 8564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneSet.add(phoneNumber); 8574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendTelLine(type, label, phoneNumber, isPrimary); 8584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 86095e66b00988bc16ecc17df31e47c873b2554b8ccinshik final List<String> phoneNumberList = splitPhoneNumbers(phoneNumber); 8614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (phoneNumberList.isEmpty()) { 8624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 8634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneLineExists = true; 8654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (String actualPhoneNumber : phoneNumberList) { 8664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!phoneSet.contains(actualPhoneNumber)) { 86795e66b00988bc16ecc17df31e47c873b2554b8ccinshik // 'p' and 'w' are the standard characters for pause and wait 86895e66b00988bc16ecc17df31e47c873b2554b8ccinshik // (see RFC 3601) 86995e66b00988bc16ecc17df31e47c873b2554b8ccinshik // so use those when exporting phone numbers via vCard. 87095e66b00988bc16ecc17df31e47c873b2554b8ccinshik String numberWithControlSequence = actualPhoneNumber 87195e66b00988bc16ecc17df31e47c873b2554b8ccinshik .replace(PhoneNumberUtils.PAUSE, 'p') 87295e66b00988bc16ecc17df31e47c873b2554b8ccinshik .replace(PhoneNumberUtils.WAIT, 'w'); 87395e66b00988bc16ecc17df31e47c873b2554b8ccinshik String formatted; 87495e66b00988bc16ecc17df31e47c873b2554b8ccinshik // TODO: remove this code and relevant test cases. vCard and any other 87595e66b00988bc16ecc17df31e47c873b2554b8ccinshik // codes using it shouldn't rely on the formatter here. 87695e66b00988bc16ecc17df31e47c873b2554b8ccinshik if (TextUtils.equals(numberWithControlSequence, actualPhoneNumber)) { 87795e66b00988bc16ecc17df31e47c873b2554b8ccinshik StringBuilder digitsOnlyBuilder = new StringBuilder(); 87895e66b00988bc16ecc17df31e47c873b2554b8ccinshik final int length = actualPhoneNumber.length(); 87995e66b00988bc16ecc17df31e47c873b2554b8ccinshik for (int i = 0; i < length; i++) { 88095e66b00988bc16ecc17df31e47c873b2554b8ccinshik final char ch = actualPhoneNumber.charAt(i); 88195e66b00988bc16ecc17df31e47c873b2554b8ccinshik if (Character.isDigit(ch) || ch == '+') { 88295e66b00988bc16ecc17df31e47c873b2554b8ccinshik digitsOnlyBuilder.append(ch); 88395e66b00988bc16ecc17df31e47c873b2554b8ccinshik } 88495e66b00988bc16ecc17df31e47c873b2554b8ccinshik } 88595e66b00988bc16ecc17df31e47c873b2554b8ccinshik final int phoneFormat = 88695e66b00988bc16ecc17df31e47c873b2554b8ccinshik VCardUtils.getPhoneNumberFormat(mVCardType); 88795e66b00988bc16ecc17df31e47c873b2554b8ccinshik formatted = PhoneNumberUtilsPort.formatNumber( 88895e66b00988bc16ecc17df31e47c873b2554b8ccinshik digitsOnlyBuilder.toString(), phoneFormat); 88995e66b00988bc16ecc17df31e47c873b2554b8ccinshik } else { 89095e66b00988bc16ecc17df31e47c873b2554b8ccinshik // Be conservative. 89195e66b00988bc16ecc17df31e47c873b2554b8ccinshik formatted = numberWithControlSequence; 89295e66b00988bc16ecc17df31e47c873b2554b8ccinshik } 893465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa 894465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa // In vCard 4.0, value type must be "a single URI value", 895465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa // not just a phone number. (Based on vCard 4.0 rev.13) 896465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa if (VCardConfig.isVersion40(mVCardType) 897465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa && !TextUtils.isEmpty(formatted) 898465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa && !formatted.startsWith("tel:")) { 899465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa formatted = "tel:" + formatted; 900465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa } 901465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa 902465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa // Pre-formatted string should be stored. 9034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneSet.add(actualPhoneNumber); 904465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa appendTelLine(type, label, formatted, isPrimary); 9054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } // for (String actualPhoneNumber : phoneNumberList) { 907465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa 908465aa5d5706ba56c74c1249a17a6df80b0f42972Daisuke Miyakawa // TODO: TEL with SIP URI? 9094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!phoneLineExists && mIsDoCoMo) { 9144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendTelLine(Phone.TYPE_HOME, "", "", false); 9154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 9184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 9214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 9224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Splits a given string expressing phone numbers into several strings, and remove 9234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * unnecessary characters inside them. The size of a returned list becomes 1 when 9244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * no split is needed. 9254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 9264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 9274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * The given number "may" have several phone numbers when the contact entry is corrupted 9284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * because of its original source. 9294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * e.g. "111-222-3333 (Miami)\n444-555-6666 (Broward; 305-653-6796 (Miami)" 9304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 9314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 9324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * This kind of "phone numbers" will not be created with Android vCard implementation, 9334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * but we may encounter them if the source of the input data has already corrupted 9344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * implementation. 9354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 9364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 9374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * To handle this case, this method first splits its input into multiple parts 9384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * (e.g. "111-222-3333 (Miami)", "444-555-6666 (Broward", and 305653-6796 (Miami)") and 9394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * removes unnecessary strings like "(Miami)". 9404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 9414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 9424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Do not call this method when trimming is inappropriate for its receivers. 9434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 9444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 94595e66b00988bc16ecc17df31e47c873b2554b8ccinshik private List<String> splitPhoneNumbers(final String phoneNumber) { 9464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final List<String> phoneList = new ArrayList<String>(); 9474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa StringBuilder builder = new StringBuilder(); 9494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = phoneNumber.length(); 9504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 9514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final char ch = phoneNumber.charAt(i); 95295e66b00988bc16ecc17df31e47c873b2554b8ccinshik if (ch == '\n' && builder.length() > 0) { 9534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneList.add(builder.toString()); 9544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder = new StringBuilder(); 95595e66b00988bc16ecc17df31e47c873b2554b8ccinshik } else { 95695e66b00988bc16ecc17df31e47c873b2554b8ccinshik builder.append(ch); 9574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (builder.length() > 0) { 9604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa phoneList.add(builder.toString()); 9614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return phoneList; 9634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendEmails(final List<ContentValues> contentValuesList) { 9664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean emailAddressExists = false; 9674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList != null) { 9684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Set<String> addressSet = new HashSet<String>(); 9694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (ContentValues contentValues : contentValuesList) { 9704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String emailAddress = contentValues.getAsString(Email.DATA); 9714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (emailAddress != null) { 9724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa emailAddress = emailAddress.trim(); 9734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(emailAddress)) { 9754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 9764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Integer typeAsObject = contentValues.getAsInteger(Email.TYPE); 9784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int type = (typeAsObject != null ? 9794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsObject : DEFAULT_EMAIL_TYPE); 9804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String label = contentValues.getAsString(Email.LABEL); 9814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Integer isPrimaryAsInteger = contentValues.getAsInteger(Email.IS_PRIMARY); 9824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean isPrimary = (isPrimaryAsInteger != null ? 9834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (isPrimaryAsInteger > 0) : false); 9844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa emailAddressExists = true; 9854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!addressSet.contains(emailAddress)) { 9864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressSet.add(emailAddress); 9874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendEmailLine(type, label, emailAddress, isPrimary); 9884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!emailAddressExists && mIsDoCoMo) { 9934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendEmailLine(Email.TYPE_HOME, "", "", false); 9944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 9974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendPostals(final List<ContentValues> contentValuesList) { 10004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList == null || contentValuesList.isEmpty()) { 10014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mIsDoCoMo) { 10024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_ADR); 10034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 10044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PARAM_TYPE_HOME); 10054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 10064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 10074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 10094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mIsDoCoMo) { 10104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendPostalsForDoCoMo(contentValuesList); 10114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 10124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendPostalsForGeneric(contentValuesList); 10134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 10174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final Map<Integer, Integer> sPostalTypePriorityMap; 10204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa static { 10224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sPostalTypePriorityMap = new HashMap<Integer, Integer>(); 10234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sPostalTypePriorityMap.put(StructuredPostal.TYPE_HOME, 0); 10244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sPostalTypePriorityMap.put(StructuredPostal.TYPE_WORK, 1); 10254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sPostalTypePriorityMap.put(StructuredPostal.TYPE_OTHER, 2); 10264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa sPostalTypePriorityMap.put(StructuredPostal.TYPE_CUSTOM, 3); 10274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 10304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Tries to append just one line. If there's no appropriate address 10314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * information, append an empty line. 10324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 10334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private void appendPostalsForDoCoMo(final List<ContentValues> contentValuesList) { 10344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int currentPriority = Integer.MAX_VALUE; 10354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int currentType = Integer.MAX_VALUE; 10364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa ContentValues currentContentValues = null; 10374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final ContentValues contentValues : contentValuesList) { 10384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValues == null) { 10394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 10404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer typeAsInteger = contentValues.getAsInteger(StructuredPostal.TYPE); 10424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer priorityAsInteger = sPostalTypePriorityMap.get(typeAsInteger); 10434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int priority = 10444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (priorityAsInteger != null ? priorityAsInteger : Integer.MAX_VALUE); 10454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (priority < currentPriority) { 10464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa currentPriority = priority; 10474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa currentType = typeAsInteger; 10484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa currentContentValues = contentValues; 10494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (priority == 0) { 10504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 10514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (currentContentValues == null) { 10564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, "Should not come here. Must have at least one postal data."); 10574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return; 10584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String label = currentContentValues.getAsString(StructuredPostal.LABEL); 10614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendPostalLine(currentType, label, currentContentValues, false, true); 10624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private void appendPostalsForGeneric(final List<ContentValues> contentValuesList) { 10654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final ContentValues contentValues : contentValuesList) { 10664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValues == null) { 10674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 10684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer typeAsInteger = contentValues.getAsInteger(StructuredPostal.TYPE); 10704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int type = (typeAsInteger != null ? 10714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsInteger : DEFAULT_POSTAL_TYPE); 10724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String label = contentValues.getAsString(StructuredPostal.LABEL); 10734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer isPrimaryAsInteger = 10744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa contentValues.getAsInteger(StructuredPostal.IS_PRIMARY); 10754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean isPrimary = (isPrimaryAsInteger != null ? 10764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (isPrimaryAsInteger > 0) : false); 10774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendPostalLine(type, label, contentValues, isPrimary, false); 10784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static class PostalStruct { 10824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintable; 10834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean appendCharset; 10844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String addressData; 10854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public PostalStruct(final boolean reallyUseQuotedPrintable, 10864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean appendCharset, final String addressData) { 10874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa this.reallyUseQuotedPrintable = reallyUseQuotedPrintable; 10884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa this.appendCharset = appendCharset; 10894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa this.addressData = addressData; 10904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 10944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @return null when there's no information available to construct the data. 10954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 10964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private PostalStruct tryConstructPostalStruct(ContentValues contentValues) { 10974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // adr-value = 0*6(text-value ";") text-value 10984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // ; PO Box, Extended Address, Street, Locality, Region, Postal 10994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // ; Code, Country Name 11004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawPoBox = contentValues.getAsString(StructuredPostal.POBOX); 11014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawNeighborhood = contentValues.getAsString(StructuredPostal.NEIGHBORHOOD); 11024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawStreet = contentValues.getAsString(StructuredPostal.STREET); 11034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawLocality = contentValues.getAsString(StructuredPostal.CITY); 11044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawRegion = contentValues.getAsString(StructuredPostal.REGION); 11054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawPostalCode = contentValues.getAsString(StructuredPostal.POSTCODE); 11064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawCountry = contentValues.getAsString(StructuredPostal.COUNTRY); 11074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String[] rawAddressArray = new String[]{ 11084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawPoBox, rawNeighborhood, rawStreet, rawLocality, 11094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawRegion, rawPostalCode, rawCountry}; 11104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!VCardUtils.areAllEmpty(rawAddressArray)) { 11114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintable = 11124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 11134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawAddressArray)); 11144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean appendCharset = 11154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyPrintableAscii(rawAddressArray); 11164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedPoBox; 11174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedStreet; 11184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedLocality; 11194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedRegion; 11204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedPostalCode; 11214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedCountry; 11224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedNeighborhood; 11234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 11244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawLocality2; 11254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // This looks inefficient since we encode rawLocality and rawNeighborhood twice, 11264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // but this is intentional. 11274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 11284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // QP encoding may add line feeds when needed and the result of 11294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // - encodeQuotedPrintable(rawLocality + " " + rawNeighborhood) 11304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // may be different from 11314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // - encodedLocality + " " + encodedNeighborhood. 11324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 11334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // We use safer way. 11344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(rawLocality)) { 11354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(rawNeighborhood)) { 11364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawLocality2 = ""; 11374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 11384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawLocality2 = rawNeighborhood; 11394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 11404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 11414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(rawNeighborhood)) { 11424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawLocality2 = rawLocality; 11434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 11444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawLocality2 = rawLocality + " " + rawNeighborhood; 11454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 11464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 11474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 11484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPoBox = encodeQuotedPrintable(rawPoBox); 11494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedStreet = encodeQuotedPrintable(rawStreet); 11504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedLocality = encodeQuotedPrintable(rawLocality2); 11514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedRegion = encodeQuotedPrintable(rawRegion); 11524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPostalCode = encodeQuotedPrintable(rawPostalCode); 11534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedCountry = encodeQuotedPrintable(rawCountry); 11544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 11554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPoBox = escapeCharacters(rawPoBox); 11564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedStreet = escapeCharacters(rawStreet); 11574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedLocality = escapeCharacters(rawLocality2); 11584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedRegion = escapeCharacters(rawRegion); 11594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedPostalCode = escapeCharacters(rawPostalCode); 11604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedCountry = escapeCharacters(rawCountry); 11614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedNeighborhood = escapeCharacters(rawNeighborhood); 11624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 11634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final StringBuilder addressBuilder = new StringBuilder(); 11644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(encodedPoBox); 11654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // PO BOX ; Extended Address 11664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // Extended Address : Street 11674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(encodedStreet); 11684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // Street : Locality 11694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(encodedLocality); 11704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // Locality : Region 11714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(encodedRegion); 11724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // Region : Postal Code 11734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(encodedPostalCode); 11744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // Postal Code : Country 11754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(encodedCountry); 11764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return new PostalStruct( 11774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa reallyUseQuotedPrintable, appendCharset, addressBuilder.toString()); 11784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { // VCardUtils.areAllEmpty(rawAddressArray) == true 11794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Try to use FORMATTED_ADDRESS instead. 11804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawFormattedAddress = 11814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa contentValues.getAsString(StructuredPostal.FORMATTED_ADDRESS); 11824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(rawFormattedAddress)) { 11834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return null; 11844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 11854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintable = 11864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 11874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawFormattedAddress)); 11884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean appendCharset = 11894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyPrintableAscii(rawFormattedAddress); 11904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedFormattedAddress; 11914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 11924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedFormattedAddress = encodeQuotedPrintable(rawFormattedAddress); 11934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 11944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedFormattedAddress = escapeCharacters(rawFormattedAddress); 11954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 11964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 11974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // We use the second value ("Extended Address") just because Japanese mobile phones 11984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // do so. If the other importer expects the value be in the other field, some flag may 11994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // be needed. 12004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final StringBuilder addressBuilder = new StringBuilder(); 12014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // PO BOX ; Extended Address 12024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(encodedFormattedAddress); 12034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // Extended Address : Street 12044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // Street : Locality 12054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // Locality : Region 12064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // Region : Postal Code 12074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressBuilder.append(VCARD_ITEM_SEPARATOR); // Postal Code : Country 12084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return new PostalStruct( 12094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa reallyUseQuotedPrintable, appendCharset, addressBuilder.toString()); 12104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 12134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendIms(final List<ContentValues> contentValuesList) { 12144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList != null) { 12154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (ContentValues contentValues : contentValuesList) { 12164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer protocolAsObject = contentValues.getAsInteger(Im.PROTOCOL); 12174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (protocolAsObject == null) { 12184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 12194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String propertyName = VCardUtils.getPropertyNameForIm(protocolAsObject); 12214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (propertyName == null) { 12224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 12234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String data = contentValues.getAsString(Im.DATA); 12254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (data != null) { 12264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa data = data.trim(); 12274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(data)) { 12294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 12304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String typeAsString; 12324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa { 12334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer typeAsInteger = contentValues.getAsInteger(Im.TYPE); 12344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa switch (typeAsInteger != null ? typeAsInteger : Im.TYPE_OTHER) { 12354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Im.TYPE_HOME: { 12364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = VCardConstants.PARAM_TYPE_HOME; 12374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 12384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Im.TYPE_WORK: { 12404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = VCardConstants.PARAM_TYPE_WORK; 12414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 12424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Im.TYPE_CUSTOM: { 12444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String label = contentValues.getAsString(Im.LABEL); 12454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = (label != null ? "X-" + label : null); 12464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 12474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Im.TYPE_OTHER: // Ignore 12494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa default: { 12504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = null; 12514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 12524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 12564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final List<String> parameterList = new ArrayList<String>(); 12574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(typeAsString)) { 12584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(typeAsString); 12594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer isPrimaryAsInteger = contentValues.getAsInteger(Im.IS_PRIMARY); 12614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean isPrimary = (isPrimaryAsInteger != null ? 12624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (isPrimaryAsInteger > 0) : false); 12634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (isPrimary) { 12644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_PREF); 12654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 12674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLineWithCharsetAndQPDetection(propertyName, parameterList, data); 12684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 12714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 12734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendWebsites(final List<ContentValues> contentValuesList) { 12744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList != null) { 12754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (ContentValues contentValues : contentValuesList) { 12764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String website = contentValues.getAsString(Website.URL); 12774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (website != null) { 12784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa website = website.trim(); 12794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 12814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Note: vCard 3.0 does not allow any parameter addition toward "URL" 12824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // property, while there's no document in vCard 2.1. 12834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(website)) { 12844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_URL, website); 12854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 12894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 12914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendOrganizations(final List<ContentValues> contentValuesList) { 12924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList != null) { 12934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (ContentValues contentValues : contentValuesList) { 12944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String company = contentValues.getAsString(Organization.COMPANY); 12954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (company != null) { 12964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa company = company.trim(); 12974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 12984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String department = contentValues.getAsString(Organization.DEPARTMENT); 12994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (department != null) { 13004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa department = department.trim(); 13014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String title = contentValues.getAsString(Organization.TITLE); 13034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (title != null) { 13044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa title = title.trim(); 13054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 13074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa StringBuilder orgBuilder = new StringBuilder(); 13084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(company)) { 13094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa orgBuilder.append(company); 13104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(department)) { 13124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (orgBuilder.length() > 0) { 13134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa orgBuilder.append(';'); 13144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa orgBuilder.append(department); 13164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String orgline = orgBuilder.toString(); 13184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_ORG, orgline, 13194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyPrintableAscii(orgline), 13204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 13214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(orgline))); 13224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 13234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(title)) { 13244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_TITLE, title, 13254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyPrintableAscii(title), 13264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 13274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(title))); 13284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 13324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 13344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendPhotos(final List<ContentValues> contentValuesList) { 13354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList != null) { 13364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (ContentValues contentValues : contentValuesList) { 13374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValues == null) { 13384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 13394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa byte[] data = contentValues.getAsByteArray(Photo.PHOTO); 13414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (data == null) { 13424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 13434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String photoType = VCardUtils.guessImageType(data); 13454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (photoType == null) { 13464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.d(LOG_TAG, "Unknown photo type. Ignored."); 13474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 13484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TODO: check this works fine. 13504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String photoString = new String(Base64.encode(data, Base64.NO_WRAP)); 13514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(photoString)) { 13524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendPhotoLine(photoString, photoType); 13534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 13574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 13594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendNotes(final List<ContentValues> contentValuesList) { 13604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList != null) { 13614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mOnlyOneNoteFieldIsAvailable) { 13624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final StringBuilder noteBuilder = new StringBuilder(); 13634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean first = true; 13644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final ContentValues contentValues : contentValuesList) { 13654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String note = contentValues.getAsString(Note.NOTE); 13664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (note == null) { 13674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa note = ""; 13684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (note.length() > 0) { 13704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (first) { 13714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa first = false; 13724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 13734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa noteBuilder.append('\n'); 13744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa noteBuilder.append(note); 13764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 13784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String noteStr = noteBuilder.toString(); 13794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // This means we scan noteStr completely twice, which is redundant. 13804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // But for now, we assume this is not so time-consuming.. 13814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean shouldAppendCharsetInfo = 13824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyPrintableAscii(noteStr); 13834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintable = 13844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 13854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr)); 13864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_NOTE, noteStr, 13874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa shouldAppendCharsetInfo, reallyUseQuotedPrintable); 13884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 13894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (ContentValues contentValues : contentValuesList) { 13904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String noteStr = contentValues.getAsString(Note.NOTE); 13914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(noteStr)) { 13924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean shouldAppendCharsetInfo = 13934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyPrintableAscii(noteStr); 13944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintable = 13954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 13964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr)); 13974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_NOTE, noteStr, 13984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa shouldAppendCharsetInfo, reallyUseQuotedPrintable); 13994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 14044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 14064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendEvents(final List<ContentValues> contentValuesList) { 14074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // There's possibility where a given object may have more than one birthday, which 14084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // is inappropriate. We just build one birthday. 14094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValuesList != null) { 14104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String primaryBirthday = null; 14114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String secondaryBirthday = null; 14124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final ContentValues contentValues : contentValuesList) { 14134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValues == null) { 14144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 14154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer eventTypeAsInteger = contentValues.getAsInteger(Event.TYPE); 14174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int eventType; 14184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (eventTypeAsInteger != null) { 14194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa eventType = eventTypeAsInteger; 14204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 14214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa eventType = Event.TYPE_OTHER; 14224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (eventType == Event.TYPE_BIRTHDAY) { 14244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String birthdayCandidate = contentValues.getAsString(Event.START_DATE); 14254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (birthdayCandidate == null) { 14264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 14274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer isSuperPrimaryAsInteger = 14294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa contentValues.getAsInteger(Event.IS_SUPER_PRIMARY); 14304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean isSuperPrimary = (isSuperPrimaryAsInteger != null ? 14314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (isSuperPrimaryAsInteger > 0) : false); 14324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (isSuperPrimary) { 14334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // "super primary" birthday should the prefered one. 14344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa primaryBirthday = birthdayCandidate; 14354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 14364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final Integer isPrimaryAsInteger = 14384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa contentValues.getAsInteger(Event.IS_PRIMARY); 14394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean isPrimary = (isPrimaryAsInteger != null ? 14404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (isPrimaryAsInteger > 0) : false); 14414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (isPrimary) { 14424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // We don't break here since "super primary" birthday may exist later. 14434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa primaryBirthday = birthdayCandidate; 14444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (secondaryBirthday == null) { 14454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // First entry is set to the "secondary" candidate. 14464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa secondaryBirthday = birthdayCandidate; 14474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (mUsesAndroidProperty) { 14494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Event types other than Birthday is not supported by vCard. 14504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendAndroidSpecificProperty(Event.CONTENT_ITEM_TYPE, contentValues); 14514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (primaryBirthday != null) { 14544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_BDAY, 14554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa primaryBirthday.trim()); 14564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (secondaryBirthday != null){ 14574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_BDAY, 14584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa secondaryBirthday.trim()); 14594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 14624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 14644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardBuilder appendRelation(final List<ContentValues> contentValuesList) { 14654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mUsesAndroidProperty && contentValuesList != null) { 14664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final ContentValues contentValues : contentValuesList) { 14674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (contentValues == null) { 14684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa continue; 14694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendAndroidSpecificProperty(Relation.CONTENT_ITEM_TYPE, contentValues); 14714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return this; 14744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 14764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 14774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @param emitEveryTime If true, builder builds the line even when there's no entry. 14784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 14794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendPostalLine(final int type, final String label, 14804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final ContentValues contentValues, 14814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean isPrimary, final boolean emitEveryTime) { 14824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintable; 14834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean appendCharset; 14844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String addressValue; 14854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa { 14864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa PostalStruct postalStruct = tryConstructPostalStruct(contentValues); 14874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (postalStruct == null) { 14884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (emitEveryTime) { 14894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa reallyUseQuotedPrintable = false; 14904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendCharset = false; 14914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressValue = ""; 14924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 14934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return; 14944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 14954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 14964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa reallyUseQuotedPrintable = postalStruct.reallyUseQuotedPrintable; 14974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendCharset = postalStruct.appendCharset; 14984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa addressValue = postalStruct.addressData; 14994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 15024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa List<String> parameterList = new ArrayList<String>(); 15034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (isPrimary) { 15044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_PREF); 15054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa switch (type) { 15074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case StructuredPostal.TYPE_HOME: { 15084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_HOME); 15094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case StructuredPostal.TYPE_WORK: { 15124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_WORK); 15134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case StructuredPostal.TYPE_CUSTOM: { 15164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(label) 15174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && VCardUtils.containsOnlyAlphaDigitHyphen(label)) { 15184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // We're not sure whether the label is valid in the spec 15194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // ("IANA-token" in the vCard 3.0 is unclear...) 15204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Just for safety, we add "X-" at the beggining of each label. 15214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Also checks the label obeys with vCard 3.0 spec. 15224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add("X-" + label); 15234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case StructuredPostal.TYPE_OTHER: { 15274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa default: { 15304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.e(LOG_TAG, "Unknown StructuredPostal type: " + type); 15314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 15354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_ADR); 15364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!parameterList.isEmpty()) { 15374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 15384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendTypeParameters(parameterList); 15394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (appendCharset) { 15414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Strictly, vCard 3.0 does not allow exporters to emit charset information, 15424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // but we will add it since the information should be useful for importers, 15434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 15444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Assume no parser does not emit error with this parameter in vCard 3.0. 15454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 15464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 15474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 15494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 15504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 15514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 15534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(addressValue); 15544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 15554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 15574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendEmailLine(final int type, final String label, 15584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawValue, final boolean isPrimary) { 15594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String typeAsString; 15604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa switch (type) { 15614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Email.TYPE_CUSTOM: { 15624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (VCardUtils.isMobilePhoneLabel(label)) { 15634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = VCardConstants.PARAM_TYPE_CELL; 15644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (!TextUtils.isEmpty(label) 15654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && VCardUtils.containsOnlyAlphaDigitHyphen(label)) { 15664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = "X-" + label; 15674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 15684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = null; 15694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Email.TYPE_HOME: { 15734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = VCardConstants.PARAM_TYPE_HOME; 15744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Email.TYPE_WORK: { 15774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = VCardConstants.PARAM_TYPE_WORK; 15784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Email.TYPE_OTHER: { 15814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = null; 15824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Email.TYPE_MOBILE: { 15854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = VCardConstants.PARAM_TYPE_CELL; 15864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa default: { 15894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.e(LOG_TAG, "Unknown Email type: " + type); 15904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa typeAsString = null; 15914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 15924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 15954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final List<String> parameterList = new ArrayList<String>(); 15964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (isPrimary) { 15974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_PREF); 15984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 15994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!TextUtils.isEmpty(typeAsString)) { 16004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(typeAsString); 16014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 16034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_EMAIL, parameterList, 16044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawValue); 16054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 16074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendTelLine(final Integer typeAsInteger, final String label, 16084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedValue, boolean isPrimary) { 16094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_TEL); 16104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 16114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 16124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int type; 16134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (typeAsInteger == null) { 16144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa type = Phone.TYPE_OTHER; 16154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 16164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa type = typeAsInteger; 16174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 16194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa ArrayList<String> parameterList = new ArrayList<String>(); 16204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa switch (type) { 16214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_HOME: { 16224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.addAll( 16234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Arrays.asList(VCardConstants.PARAM_TYPE_HOME)); 16244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_WORK: { 16274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.addAll( 16284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Arrays.asList(VCardConstants.PARAM_TYPE_WORK)); 16294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_FAX_HOME: { 16324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.addAll( 16334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Arrays.asList(VCardConstants.PARAM_TYPE_HOME, VCardConstants.PARAM_TYPE_FAX)); 16344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_FAX_WORK: { 16374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.addAll( 16384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Arrays.asList(VCardConstants.PARAM_TYPE_WORK, VCardConstants.PARAM_TYPE_FAX)); 16394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_MOBILE: { 16424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_CELL); 16434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_PAGER: { 16464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mIsDoCoMo) { 16474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Not sure about the reason, but previous implementation had 16484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // used "VOICE" instead of "PAGER" 16494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_VOICE); 16504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 16514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_PAGER); 16524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_OTHER: { 16564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_VOICE); 16574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_CAR: { 16604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_CAR); 16614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_COMPANY_MAIN: { 16644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // There's no relevant field in vCard (at least 2.1). 16654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_WORK); 16664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa isPrimary = true; 16674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_ISDN: { 16704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_ISDN); 16714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_MAIN: { 16744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa isPrimary = true; 16754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_OTHER_FAX: { 16784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_FAX); 16794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_TELEX: { 16824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_TLX); 16834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_WORK_MOBILE: { 16864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.addAll( 16874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Arrays.asList(VCardConstants.PARAM_TYPE_WORK, VCardConstants.PARAM_TYPE_CELL)); 16884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_WORK_PAGER: { 16914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_WORK); 16924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // See above. 16934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mIsDoCoMo) { 16944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_VOICE); 16954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 16964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_PAGER); 16974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 16984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 16994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_MMS: { 17014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_MSG); 17024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 17034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_CUSTOM: { 17054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(label)) { 17064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Just ignore the custom type. 17074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_VOICE); 17084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (VCardUtils.isMobilePhoneLabel(label)) { 17094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_CELL); 171036ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa } else if (mIsV30OrV40) { 17112bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa // This label is appropriately encoded in appendTypeParameters. 17122bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa parameterList.add(label); 17134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 17144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String upperLabel = label.toUpperCase(); 17154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (VCardUtils.isValidInV21ButUnknownToContactsPhoteType(upperLabel)) { 17164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(upperLabel); 17174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (VCardUtils.containsOnlyAlphaDigitHyphen(label)) { 17184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Note: Strictly, vCard 2.1 does not allow "X-" parameter without 17194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // "TYPE=" string. 17204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add("X-" + label); 17214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 17244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_RADIO: 17264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case Phone.TYPE_TTY_TDD: 17274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa default: { 17284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 17294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 17324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (isPrimary) { 17334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parameterList.add(VCardConstants.PARAM_TYPE_PREF); 17344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 17364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (parameterList.isEmpty()) { 17374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendUncommonPhoneType(mBuilder, type); 17384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 17394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendTypeParameters(parameterList); 17404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 17424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 17434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedValue); 17444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 17454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 17474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 17484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Appends phone type string which may not be available in some devices. 17494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 17504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private void appendUncommonPhoneType(final StringBuilder builder, final Integer type) { 17514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mIsDoCoMo) { 17524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // The previous implementation for DoCoMo had been conservative 17534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // about miscellaneous types. 17544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(VCardConstants.PARAM_TYPE_VOICE); 17554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 17564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String phoneType = VCardUtils.getPhoneTypeString(type); 17574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (phoneType != null) { 17584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendTypeParameter(phoneType); 17594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 17604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.e(LOG_TAG, "Unknown or unsupported (by vCard) Phone type: " + type); 17614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 17654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 176602117b3d19787ff65486b9f9db8abd338ae4c9f9Daisuke Miyakawa * @param encodedValue Must be encoded by BASE64 17674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @param photoType 17684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 17694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendPhotoLine(final String encodedValue, final String photoType) { 17704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa StringBuilder tmpBuilder = new StringBuilder(); 17714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(VCardConstants.PROPERTY_PHOTO); 17724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(VCARD_PARAM_SEPARATOR); 177336ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa if (mIsV30OrV40) { 177436ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa tmpBuilder.append(VCARD_PARAM_ENCODING_BASE64_AS_B); 17754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 17764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(VCARD_PARAM_ENCODING_BASE64_V21); 17774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 17784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(VCARD_PARAM_SEPARATOR); 17794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendTypeParameter(tmpBuilder, photoType); 17804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(VCARD_DATA_SEPARATOR); 17814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(encodedValue); 17824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 17834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String tmpStr = tmpBuilder.toString(); 17844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder = new StringBuilder(); 17854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int lineCount = 0; 17864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = tmpStr.length(); 17874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int maxNumForFirstLine = VCardConstants.MAX_CHARACTER_NUMS_BASE64_V30 17884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa - VCARD_END_OF_LINE.length(); 17894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int maxNumInGeneral = maxNumForFirstLine - VCARD_WS.length(); 17904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int maxNum = maxNumForFirstLine; 17914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 17924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(tmpStr.charAt(i)); 17934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa lineCount++; 17944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (lineCount > maxNum) { 17954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(VCARD_END_OF_LINE); 17964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(VCARD_WS); 17974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa maxNum = maxNumInGeneral; 17984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa lineCount = 0; 17994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 18004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 18014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(tmpBuilder.toString()); 18024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 18034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 18044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 18054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1806422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa /** 1807422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa * SIP (Session Initiation Protocol) is first supported in RFC 4770 as part of IMPP 1808422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa * support. vCard 2.1 and old vCard 3.0 may not able to parse it, or expect X-SIP 1809422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa * instead of "IMPP;sip:...". 1810422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa * 1811422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa * We honor RFC 4770 and don't allow vCard 3.0 to emit X-SIP at all. 1812422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa */ 1813422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa public VCardBuilder appendSipAddresses(final List<ContentValues> contentValuesList) { 1814422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa final boolean useXProperty; 1815422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa if (mIsV30OrV40) { 1816422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa useXProperty = false; 1817422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } else if (mUsesDefactProperty){ 1818422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa useXProperty = true; 1819422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } else { 1820422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa return this; 1821422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } 1822422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa 1823422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa if (contentValuesList != null) { 1824422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa for (ContentValues contentValues : contentValuesList) { 1825422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa String sipAddress = contentValues.getAsString(SipAddress.SIP_ADDRESS); 1826422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa if (TextUtils.isEmpty(sipAddress)) { 1827422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa continue; 1828422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } 1829422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa if (useXProperty) { 1830422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa // X-SIP does not contain "sip:" prefix. 1831422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa if (sipAddress.startsWith("sip:")) { 1832422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa if (sipAddress.length() == 4) { 1833422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa continue; 1834422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } 1835422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa sipAddress = sipAddress.substring(4); 1836422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } 1837422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa // No type is available yet. 1838422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_X_SIP, sipAddress); 1839422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } else { 1840422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa if (!sipAddress.startsWith("sip:")) { 1841422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa sipAddress = "sip:" + sipAddress; 1842422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } 184337634a0179f74431317f50d2ce493e3fad36f5a9Daisuke Miyakawa final String propertyName; 184437634a0179f74431317f50d2ce493e3fad36f5a9Daisuke Miyakawa if (VCardConfig.isVersion40(mVCardType)) { 184537634a0179f74431317f50d2ce493e3fad36f5a9Daisuke Miyakawa // We have two ways to emit sip address: TEL and IMPP. Currently (rev.13) 184637634a0179f74431317f50d2ce493e3fad36f5a9Daisuke Miyakawa // TEL seems appropriate but may change in the future. 184737634a0179f74431317f50d2ce493e3fad36f5a9Daisuke Miyakawa propertyName = VCardConstants.PROPERTY_TEL; 184837634a0179f74431317f50d2ce493e3fad36f5a9Daisuke Miyakawa } else { 184937634a0179f74431317f50d2ce493e3fad36f5a9Daisuke Miyakawa // RFC 4770 (for vCard 3.0) 185037634a0179f74431317f50d2ce493e3fad36f5a9Daisuke Miyakawa propertyName = VCardConstants.PROPERTY_IMPP; 185137634a0179f74431317f50d2ce493e3fad36f5a9Daisuke Miyakawa } 185237634a0179f74431317f50d2ce493e3fad36f5a9Daisuke Miyakawa appendLineWithCharsetAndQPDetection(propertyName, sipAddress); 1853422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } 1854422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } 1855422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } 1856422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa return this; 1857422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa } 1858422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa 18594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendAndroidSpecificProperty( 18604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String mimeType, ContentValues contentValues) { 18614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!sAllowedAndroidPropertySet.contains(mimeType)) { 18624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return; 18634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 18644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final List<String> rawValueList = new ArrayList<String>(); 18654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 1; i <= VCardConstants.MAX_DATA_COLUMN; i++) { 18664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String value = contentValues.getAsString("data" + i); 18674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (value == null) { 18684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa value = ""; 18694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 18704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawValueList.add(value); 18714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 18724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 18734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean needCharset = 18744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldAppendCharsetParam && 18754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); 18764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean reallyUseQuotedPrintable = 18774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 18784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); 18794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCardConstants.PROPERTY_X_ANDROID_CUSTOM); 18804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (needCharset) { 18814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 18824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 18834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 18844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 18854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 18864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 18874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 18884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 18894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mimeType); // Should not be encoded. 18904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (String rawValue : rawValueList) { 18914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedValue; 18924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 18934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedValue = encodeQuotedPrintable(rawValue); 18944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 18954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TODO: one line may be too huge, which may be invalid in vCard 3.0 18964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // (which says "When generating a content line, lines longer than 18974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 75 characters SHOULD be folded"), though several 18984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // (even well-known) applications do not care this. 18994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedValue = escapeCharacters(rawValue); 19004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 19024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedValue); 19034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 19054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLineWithCharsetAndQPDetection(final String propertyName, 19084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawValue) { 19094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLineWithCharsetAndQPDetection(propertyName, null, rawValue); 19104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLineWithCharsetAndQPDetection( 19134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String propertyName, final List<String> rawValueList) { 19144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLineWithCharsetAndQPDetection(propertyName, null, rawValueList); 19154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLineWithCharsetAndQPDetection(final String propertyName, 19184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final List<String> parameterList, final String rawValue) { 19194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean needCharset = 19204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyPrintableAscii(rawValue); 19214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean reallyUseQuotedPrintable = 19224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 19234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValue)); 19244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(propertyName, parameterList, 19254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa rawValue, needCharset, reallyUseQuotedPrintable); 19264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLineWithCharsetAndQPDetection(final String propertyName, 19294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final List<String> parameterList, final List<String> rawValueList) { 19304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean needCharset = 19314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldAppendCharsetParam && 19324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); 19334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean reallyUseQuotedPrintable = 19344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa (mShouldUseQuotedPrintable && 19354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); 19364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(propertyName, parameterList, rawValueList, 19374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa needCharset, reallyUseQuotedPrintable); 19384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 194102117b3d19787ff65486b9f9db8abd338ae4c9f9Daisuke Miyakawa * Appends one line with a given property name and value. 19424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 19434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLine(final String propertyName, final String rawValue) { 19444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(propertyName, rawValue, false, false); 19454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLine(final String propertyName, final List<String> rawValueList) { 19484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(propertyName, rawValueList, false, false); 19494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLine(final String propertyName, 19524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawValue, final boolean needCharset, 19534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean reallyUseQuotedPrintable) { 19544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(propertyName, null, rawValue, needCharset, reallyUseQuotedPrintable); 19554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLine(final String propertyName, final List<String> parameterList, 19584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawValue) { 19594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(propertyName, parameterList, rawValue, false, false); 19604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLine(final String propertyName, final List<String> parameterList, 19634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String rawValue, final boolean needCharset, 19644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean reallyUseQuotedPrintable) { 19654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(propertyName); 19664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (parameterList != null && parameterList.size() > 0) { 19674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 19684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendTypeParameters(parameterList); 19694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (needCharset) { 19714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 19724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 19734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedValue; 19764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (reallyUseQuotedPrintable) { 19774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 19784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 19794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedValue = encodeQuotedPrintable(rawValue); 19804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 19814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TODO: one line may be too huge, which may be invalid in vCard spec, though 19824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // several (even well-known) applications do not care that violation. 19834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedValue = escapeCharacters(rawValue); 19844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 19874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedValue); 19884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 19894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLine(final String propertyName, final List<String> rawValueList, 19924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean needCharset, boolean needQuotedPrintable) { 19934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(propertyName, null, rawValueList, needCharset, needQuotedPrintable); 19944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 19954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 19964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void appendLine(final String propertyName, final List<String> parameterList, 19974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final List<String> rawValueList, final boolean needCharset, 19984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final boolean needQuotedPrintable) { 19994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(propertyName); 20004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (parameterList != null && parameterList.size() > 0) { 20014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 20024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendTypeParameters(parameterList); 20034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (needCharset) { 20054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 20064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(mVCardCharsetParameter); 20074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (needQuotedPrintable) { 20094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 20104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_PARAM_ENCODING_QP); 20114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 20134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_DATA_SEPARATOR); 20144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean first = true; 20154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (String rawValue : rawValueList) { 20164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String encodedValue; 20174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (needQuotedPrintable) { 20184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedValue = encodeQuotedPrintable(rawValue); 20194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 20204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TODO: one line may be too huge, which may be invalid in vCard 3.0 20214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // (which says "When generating a content line, lines longer than 20224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 75 characters SHOULD be folded"), though several 20234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // (even well-known) applications do not care this. 20244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa encodedValue = escapeCharacters(rawValue); 20254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 20274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (first) { 20284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa first = false; 20294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 20304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_ITEM_SEPARATOR); 20314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(encodedValue); 20334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mBuilder.append(VCARD_END_OF_LINE); 20354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 20374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 20384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * VCARD_PARAM_SEPARATOR must be appended before this method being called. 20394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 20404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private void appendTypeParameters(final List<String> types) { 20414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // We may have to make this comma separated form like "TYPE=DOM,WORK" in the future, 20424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // which would be recommended way in vcard 3.0 though not valid in vCard 2.1. 20434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean first = true; 20444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (final String typeValue : types) { 2045422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa if (VCardConfig.isVersion30(mVCardType) || VCardConfig.isVersion40(mVCardType)) { 2046422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa final String encoded = (VCardConfig.isVersion40(mVCardType) ? 2047422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa VCardUtils.toStringAsV40ParamValue(typeValue) : 2048422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa VCardUtils.toStringAsV30ParamValue(typeValue)); 20492bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa if (TextUtils.isEmpty(encoded)) { 20502bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa continue; 20512bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa } 20522bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa 20532bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa if (first) { 20542bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa first = false; 20552bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa } else { 20562bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 20572bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa } 20582bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa appendTypeParameter(encoded); 20592bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa } else { // vCard 2.1 20602bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa if (!VCardUtils.isV21Word(typeValue)) { 20612bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa continue; 20622bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa } 20632bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa if (first) { 20642bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa first = false; 20652bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa } else { 20662bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa mBuilder.append(VCARD_PARAM_SEPARATOR); 20672bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa } 20682bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa appendTypeParameter(typeValue); 20694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 20734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 20744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * VCARD_PARAM_SEPARATOR must be appended before this method being called. 20754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 20764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private void appendTypeParameter(final String type) { 20774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendTypeParameter(mBuilder, type); 20784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 20804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private void appendTypeParameter(final StringBuilder builder, final String type) { 20814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Refrain from using appendType() so that "TYPE=" is not be appended when the 20824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // device is DoCoMo's (just for safety). 20834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 20844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Note: In vCard 3.0, Type strings also can be like this: "TYPE=HOME,PREF" 208536ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa if (VCardConfig.isVersion40(mVCardType) || 208636ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa ((VCardConfig.isVersion30(mVCardType) || mAppendTypeParamName) && !mIsDoCoMo)) { 20874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(VCardConstants.PARAM_TYPE).append(VCARD_PARAM_EQUAL); 20884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(type); 20904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 20914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 20924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 20934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Returns true when the property line should contain charset parameter 20944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * information. This method may return true even when vCard version is 3.0. 20954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 20964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Strictly, adding charset information is invalid in VCard 3.0. 20974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * However we'll add the info only when charset we use is not UTF-8 20984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * in vCard 3.0 format, since parser side may be able to use the charset 20994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * via this field, though we may encounter another problem by adding it. 21004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 21014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * e.g. Japanese mobile phones use Shift_Jis while RFC 2426 21024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * recommends UTF-8. By adding this field, parsers may be able 21034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * to know this text is NOT UTF-8 but Shift_Jis. 21044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 21054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private boolean shouldAppendCharsetParam(String...propertyValueList) { 21064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!mShouldAppendCharsetParam) { 21074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 21084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (String propertyValue : propertyValueList) { 21104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!VCardUtils.containsOnlyPrintableAscii(propertyValue)) { 21114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 21124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 21154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 21174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private String encodeQuotedPrintable(final String str) { 21184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(str)) { 21194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return ""; 21204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 21224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final StringBuilder builder = new StringBuilder(); 21234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int index = 0; 21244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int lineCount = 0; 21254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa byte[] strArray = null; 21264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 21274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 21284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa strArray = str.getBytes(mCharset); 21294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (UnsupportedEncodingException e) { 21304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.e(LOG_TAG, "Charset " + mCharset + " cannot be used. " 21314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + "Try default charset"); 21324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa strArray = str.getBytes(); 21334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (index < strArray.length) { 21354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(String.format("=%02X", strArray[index])); 21364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa index += 1; 21374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa lineCount += 3; 21384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 21394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (lineCount >= 67) { 21404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Specification requires CRLF must be inserted before the 21414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // length of the line 21424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // becomes more than 76. 21434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Assuming that the next character is a multi-byte character, 21444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // it will become 21454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 6 bytes. 21464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 76 - 6 - 3 = 67 21474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append("=\r\n"); 21484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa lineCount = 0; 21494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 21524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 21534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 21554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 21564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Append '\' to the characters which should be escaped. The character set is different 21574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * not only between vCard 2.1 and vCard 3.0 but also among each device. 21584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 21594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Note that Quoted-Printable string must not be input here. 21604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 21614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @SuppressWarnings("fallthrough") 21624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private String escapeCharacters(final String unescaped) { 21634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (TextUtils.isEmpty(unescaped)) { 21644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return ""; 21654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 21674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final StringBuilder tmpBuilder = new StringBuilder(); 21684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = unescaped.length(); 21694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 21704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final char ch = unescaped.charAt(i); 21714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa switch (ch) { 21724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case ';': { 21734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append('\\'); 21744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(';'); 21754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 21764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case '\r': { 21784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (i + 1 < length) { 21794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa char nextChar = unescaped.charAt(i); 21804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (nextChar == '\n') { 21814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 21824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 21834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // fall through 21844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 21864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // fall through 21874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case '\n': { 21904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // In vCard 2.1, there's no specification about this, while 21914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // vCard 3.0 explicitly requires this should be encoded to "\n". 21924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append("\\n"); 21934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 21944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 21954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case '\\': { 219636ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa if (mIsV30OrV40) { 21974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append("\\\\"); 21984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 21994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 22004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // fall through 22014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case '<': 22044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case '>': { 22054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mIsDoCoMo) { 22064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append('\\'); 22074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(ch); 22084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 22094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(ch); 22104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 22124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case ',': { 221436ba003879c5583609af3afcec8df22f51d94cd3Daisuke Miyakawa if (mIsV30OrV40) { 22154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append("\\,"); 22164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 22174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(ch); 22184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 22204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa default: { 22224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmpBuilder.append(ch); 22234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 22244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return tmpBuilder.toString(); 22284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 22304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 22314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public String toString() { 22324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!mEndAppended) { 22334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mIsDoCoMo) { 22344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_X_CLASS, VCARD_DATA_PUBLIC); 22354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_X_REDUCTION, ""); 22364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_X_NO, ""); 22374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_X_DCM_HMN_MODE, ""); 22384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa appendLine(VCardConstants.PROPERTY_END, VCARD_DATA_VCARD); 22404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mEndAppended = true; 22414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return mBuilder.toString(); 22434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 22444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa} 2245