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