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
184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.content.ContentResolver;
194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.content.ContentValues;
204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.content.Context;
214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.content.Entity;
224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.content.Entity.NamedContentValues;
23422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawaimport android.content.EntityIterator;
244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.database.Cursor;
254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.database.sqlite.SQLiteException;
264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.net.Uri;
274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Email;
284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Event;
294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Im;
304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Nickname;
314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Note;
324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Organization;
334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Phone;
344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Photo;
354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Relation;
36422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.SipAddress;
374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Website;
40422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawaimport android.provider.ContactsContract.Contacts;
41422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawaimport android.provider.ContactsContract.Data;
42422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawaimport android.provider.ContactsContract.RawContacts;
43422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawaimport android.provider.ContactsContract.RawContactsEntity;
445f0f9e9f2d3e8b73beaf49d542e10fdec6fa199bMartijn Coenenimport android.provider.ContactsContract;
454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.text.TextUtils;
464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.util.Log;
474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.lang.reflect.InvocationTargetException;
494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.lang.reflect.Method;
504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.ArrayList;
514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.HashMap;
524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.List;
534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Map;
544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/**
564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * The class for composing vCard from Contacts information.
584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Usually, this class should be used like this.
614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <pre class="prettyprint">VCardComposer composer = null;
634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * try {
644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     composer = new VCardComposer(context);
654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     composer.addHandler(
664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *             composer.new HandlerForOutputStream(outputStream));
674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     if (!composer.init()) {
684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         // Do something handling the situation.
694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         return;
704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     }
714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     while (!composer.isAfterLast()) {
724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         if (mCanceled) {
734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *             // Assume a user may cancel this operation during the export.
744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *             return;
754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         }
764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         if (!composer.createOneEntry()) {
774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *             // Do something handling the error situation.
784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *             return;
794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         }
804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     }
814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * } finally {
824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     if (composer != null) {
834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         composer.terminate();
844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     }
854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * }</pre>
864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Users have to manually take care of memory efficiency. Even one vCard may contain
884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * image of non-trivial size for mobile devices.
894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * {@link VCardBuilder} is used to build each vCard.
924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */
944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawapublic class VCardComposer {
954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final String LOG_TAG = "VCardComposer";
967e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private static final boolean DEBUG = false;
974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO =
994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        "Failed to get database information";
1004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static final String FAILURE_REASON_NO_ENTRY =
1024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        "There's no exportable in the database";
1034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static final String FAILURE_REASON_NOT_INITIALIZED =
1054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        "The vCard composer object is not correctly initialized";
1064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /** Should be visible only from developers... (no need to translate, hopefully) */
1084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static final String FAILURE_REASON_UNSUPPORTED_URI =
1094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        "The Uri vCard composer received is not supported by the composer.";
1104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static final String NO_ERROR = "No error";
1124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    // Strictly speaking, "Shift_JIS" is the most appropriate, but we use upper version here,
1144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    // since usual vCard devices for Japanese devices already use it.
1154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final String SHIFT_JIS = "SHIFT_JIS";
1164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final String UTF_8 = "UTF-8";
1174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final Map<Integer, String> sImMap;
1194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    static {
1214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap = new HashMap<Integer, String>();
1224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM);
1234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN);
1244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_YAHOO, VCardConstants.PROPERTY_X_YAHOO);
1254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ);
1264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
1274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
1284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // We don't add Google talk here since it has to be handled separately.
1294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final int mVCardType;
1324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final ContentResolver mContentResolver;
1334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final boolean mIsDoCoMo;
13556174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa    /**
13656174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa     * Used only when {@link #mIsDoCoMo} is true. Set to true when the first vCard for DoCoMo
13756174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa     * vCard is emitted.
13856174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa     */
13956174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa    private boolean mFirstVCardEmittedInDoCoMoCase;
14056174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa
1414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private Cursor mCursor;
1427e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean mCursorSuppliedFromOutside;
1434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private int mIdColumn;
144677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    private Uri mContentUriForRawContactsEntity;
1454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final String mCharset;
1474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1487e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean mInitDone;
1494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private String mErrorReason = NO_ERROR;
1504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
151a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    /**
152a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * Set to false when one of {@link #init()} variants is called, and set to true when
153a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * {@link #terminate()} is called. Initially set to true.
154a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     */
155a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    private boolean mTerminateCalled = true;
15691ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa
157753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    private RawContactEntitlesInfoCallback mRawContactEntitlesInfoCallback;
158753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai
1594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final String[] sContactsProjection = new String[] {
1604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        Contacts._ID,
1614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    };
1624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(Context context) {
1644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, VCardConfig.VCARD_TYPE_DEFAULT, null, true);
1654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
1684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * The variant which sets charset to null and sets careHandlerErrors to true.
1694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
1704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(Context context, int vcardType) {
1714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, vcardType, null, true);
1724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(Context context, int vcardType, String charset) {
1754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, vcardType, charset, true);
1764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
1794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * The variant which sets charset to null.
1804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
1814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(final Context context, final int vcardType,
1824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final boolean careHandlerErrors) {
1834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, vcardType, null, careHandlerErrors);
1844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
1877e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Constructs for supporting call log entry vCard composing.
1884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     *
1894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param context Context to be used during the composition.
1904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param vcardType The type of vCard, typically available via {@link VCardConfig}.
1914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param charset The charset to be used. Use null when you don't need the charset.
1924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param careHandlerErrors If true, This object returns false everytime
1934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
1944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(final Context context, final int vcardType, String charset,
1954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final boolean careHandlerErrors) {
1967e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        this(context, context.getContentResolver(), vcardType, charset, careHandlerErrors);
1977e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
1987e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
1997e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    /**
2007e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Just for testing for now.
2017e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * @param resolver {@link ContentResolver} which used by this object.
2027e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * @hide
2037e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     */
2047e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    public VCardComposer(final Context context, ContentResolver resolver,
2057e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            final int vcardType, String charset, final boolean careHandlerErrors) {
20656174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa        // Not used right now
20756174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa        // mContext = context;
2084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mVCardType = vcardType;
2097e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mContentResolver = resolver;
2104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
2124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        charset = (TextUtils.isEmpty(charset) ? VCardConfig.DEFAULT_EXPORT_CHARSET : charset);
2144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final boolean shouldAppendCharsetParam = !(
215be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa                VCardConfig.isVersion30(vcardType) && UTF_8.equalsIgnoreCase(charset));
2164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mIsDoCoMo || shouldAppendCharsetParam) {
2184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (SHIFT_JIS.equalsIgnoreCase(charset)) {
2194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCharset = charset;
2204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else {
221422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa                /* Log.w(LOG_TAG,
2224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        "The charset \"" + charset + "\" is used while "
223422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa                        + SHIFT_JIS + " is needed to be used."); */
2244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                if (TextUtils.isEmpty(charset)) {
2254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    mCharset = SHIFT_JIS;
2264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } else {
2274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    mCharset = charset;
2284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
2294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
2304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } else {
2314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (TextUtils.isEmpty(charset)) {
2324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCharset = UTF_8;
2334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else {
2344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCharset = charset;
2354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
2364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
2374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        Log.d(LOG_TAG, "Use the charset \"" + mCharset + "\"");
2394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
2427e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Initializes this object using default {@link Contacts#CONTENT_URI}.
2437e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     *
2447e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * You can call this method or a variant of this method just once. In other words, you cannot
2457e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * reuse this object.
2467e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     *
2474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return Returns true when initialization is successful and all the other
2484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     *          methods are available. Returns false otherwise.
2494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
2504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean init() {
2514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return init(null, null);
2524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
254a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    /**
255a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * Special variant of init(), which accepts a Uri for obtaining {@link RawContactsEntity} from
256a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * {@link ContentResolver} with {@link Contacts#_ID}.
257a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * <code>
258a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * String selection = Data.CONTACT_ID + "=?";
259a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * String[] selectionArgs = new String[] {contactId};
260a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * Cursor cursor = mContentResolver.query(
261a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     *         contentUriForRawContactsEntity, null, selection, selectionArgs, null)
262a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * </code>
2637e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     *
2647e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * You can call this method or a variant of this method just once. In other words, you cannot
2657e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * reuse this object.
266677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
267677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @deprecated Use {@link #init(Uri, String[], String, String[], String, Uri)} if you really
268677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * need to change the default Uri.
269a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     */
270677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    @Deprecated
271a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    public boolean initWithRawContactsEntityUri(Uri contentUriForRawContactsEntity) {
272677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return init(Contacts.CONTENT_URI, sContactsProjection, null, null, null,
273677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                contentUriForRawContactsEntity);
274a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    }
275a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa
2767e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    /**
2777e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Initializes this object using default {@link Contacts#CONTENT_URI} and given selection
2787e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * arguments.
2797e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     */
2804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean init(final String selection, final String[] selectionArgs) {
281677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return init(Contacts.CONTENT_URI, sContactsProjection, selection, selectionArgs,
282677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                null, null);
2834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
2864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * Note that this is unstable interface, may be deleted in the future.
2874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
2884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean init(final Uri contentUri, final String selection,
2894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final String[] selectionArgs, final String sortOrder) {
290677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return init(contentUri, sContactsProjection, selection, selectionArgs, sortOrder, null);
2917e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
2927e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
293677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    /**
294846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * @param contentUri Uri for obtaining the list of contactId. Used with
295846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
296846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * @param selection selection used with
297846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
298846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * @param selectionArgs selectionArgs used with
299846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
300846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * @param sortOrder sortOrder used with
301846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
302846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * @param contentUriForRawContactsEntity Uri for obtaining entries relevant to each
303846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * contactId.
304846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * Note that this is an unstable interface, may be deleted in the future.
305846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     */
306846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen    public boolean init(final Uri contentUri, final String selection,
307846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen            final String[] selectionArgs, final String sortOrder,
308846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen            final Uri contentUriForRawContactsEntity) {
309846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen        return init(contentUri, sContactsProjection, selection, selectionArgs, sortOrder,
310846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen                contentUriForRawContactsEntity);
311846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen    }
312846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen
313846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen    /**
314677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * A variant of init(). Currently just for testing. Use other variants for init().
315677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
316677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * First we'll create {@link Cursor} for the list of contactId.
317677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
318677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * <code>
319677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * Cursor cursorForId = mContentResolver.query(
320677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *         contentUri, projection, selection, selectionArgs, sortOrder);
321677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * </code>
322677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
323677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * After that, we'll obtain data for each contactId in the list.
324677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
325677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * <code>
326677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * Cursor cursorForContent = mContentResolver.query(
327677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *         contentUriForRawContactsEntity, null,
328677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *         Data.CONTACT_ID + "=?", new String[] {contactId}, null)
329677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * </code>
330677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
331677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link #createOneEntry()} or its variants let the caller obtain each entry from
332677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * <code>cursorForContent</code> above.
333677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
334677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param contentUri Uri for obtaining the list of contactId. Used with
335677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
336677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param projection projection used with
337677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
338677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param selection selection used with
339677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
340677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param selectionArgs selectionArgs used with
341677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
342677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param sortOrder sortOrder used with
343677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
344677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param contentUriForRawContactsEntity Uri for obtaining entries relevant to each
345677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * contactId.
346677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @return true when successful
347677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
348677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @hide
349677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     */
350677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    public boolean init(final Uri contentUri, final String[] projection,
351677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            final String selection, final String[] selectionArgs,
352677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            final String sortOrder, Uri contentUriForRawContactsEntity) {
3535f0f9e9f2d3e8b73beaf49d542e10fdec6fa199bMartijn Coenen        if (!ContactsContract.AUTHORITY.equals(contentUri.getAuthority())) {
3547e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            if (DEBUG) Log.d(LOG_TAG, "Unexpected contentUri: " + contentUri);
3557e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            mErrorReason = FAILURE_REASON_UNSUPPORTED_URI;
3567e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
3577e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
3585f0f9e9f2d3e8b73beaf49d542e10fdec6fa199bMartijn Coenen
359677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        if (!initInterFirstPart(contentUriForRawContactsEntity)) {
3607e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
3617e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
3627e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!initInterCursorCreationPart(contentUri, projection, selection, selectionArgs,
3637e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                sortOrder)) {
3647e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
3657e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
3667e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!initInterMainPart()) {
3677e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
3687e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
3697e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return initInterLastPart();
3707e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
3717e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
3727e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    /**
3737e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Just for testing for now. Do not use.
3747e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * @hide
3757e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     */
3767e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    public boolean init(Cursor cursor) {
377753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        return initWithCallback(cursor, null);
378753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    }
379753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai
380753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    /**
381753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    * @param cursor Cursor that used to get contact id
382753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    * @param rawContactEntitlesInfoCallback Callback that return RawContactEntitlesInfo
383753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    * Note that this is an unstable interface, may be deleted in the future.
384753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    *
385753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    * @return true when successful
386753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    */
387753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    public boolean initWithCallback(Cursor cursor,
388753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai            RawContactEntitlesInfoCallback rawContactEntitlesInfoCallback) {
389677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        if (!initInterFirstPart(null)) {
3907e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
3917e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
3927e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mCursorSuppliedFromOutside = true;
3937e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mCursor = cursor;
394753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        mRawContactEntitlesInfoCallback = rawContactEntitlesInfoCallback;
3957e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!initInterMainPart()) {
3967e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
3977e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
3987e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return initInterLastPart();
3997e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4007e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
401677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    private boolean initInterFirstPart(Uri contentUriForRawContactsEntity) {
402677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        mContentUriForRawContactsEntity =
403677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                (contentUriForRawContactsEntity != null ? contentUriForRawContactsEntity :
404677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                        RawContactsEntity.CONTENT_URI);
4057e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (mInitDone) {
4067e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            Log.e(LOG_TAG, "init() is already called");
4074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
4084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
4097e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return true;
4107e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4117e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
4127e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean initInterCursorCreationPart(
4137e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            final Uri contentUri, final String[] projection,
4147e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            final String selection, final String[] selectionArgs, final String sortOrder) {
4157e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mCursorSuppliedFromOutside = false;
4164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCursor = mContentResolver.query(
4174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                contentUri, projection, selection, selectionArgs, sortOrder);
4184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCursor == null) {
4197e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            Log.e(LOG_TAG, String.format("Cursor became null unexpectedly"));
4204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO;
4214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
4224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
4237e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return true;
4247e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
4267e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean initInterMainPart() {
4277e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (mCursor.getCount() == 0 || !mCursor.moveToFirst()) {
4287e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            if (DEBUG) {
4297e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                Log.d(LOG_TAG,
4307e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                    String.format("mCursor has an error (getCount: %d): ", mCursor.getCount()));
4314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
4327e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            closeCursorIfAppropriate();
4334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
4344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
435753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        mIdColumn = mCursor.getColumnIndex(Data.CONTACT_ID);
436753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        if (mIdColumn < 0) {
437753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai            mIdColumn = mCursor.getColumnIndex(Contacts._ID);
438753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        }
439677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return mIdColumn >= 0;
4407e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
4427e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean initInterLastPart() {
4437e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mInitDone = true;
444a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa        mTerminateCalled = false;
4454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return true;
4464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
4474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
4488ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    /**
449677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @return a vCard string.
450677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     */
4518ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    public String createOneEntry() {
4528ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa        return createOneEntry(null);
453677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    }
454677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa
455677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    /**
456677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @hide
457677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     */
4588ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    public String createOneEntry(Method getEntityIteratorMethod) {
45956174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa        if (mIsDoCoMo && !mFirstVCardEmittedInDoCoMoCase) {
46056174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            mFirstVCardEmittedInDoCoMoCase = true;
46156174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            // Previously we needed to emit empty data for this specific case, but actually
46256174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            // this doesn't work now, as resolver doesn't return any data with "-1" contactId.
46356174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            // TODO: re-introduce or remove this logic. Needs to modify unit test when we
46456174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            // re-introduce the logic.
46556174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            // return createOneEntryInternal("-1", getEntityIteratorMethod);
46656174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa        }
46756174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa
468753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        final String vcard = createOneEntryInternal(mCursor.getLong(mIdColumn),
469677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                getEntityIteratorMethod);
470677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        if (!mCursor.moveToNext()) {
471677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            Log.e(LOG_TAG, "Cursor#moveToNext() returned false");
472677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        }
473677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return vcard;
474677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    }
475677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa
476753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    /**
477753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai     *  Class that store rawContactEntitlesUri and contactId
478753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai     */
479753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    public static class RawContactEntitlesInfo {
480753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        public final Uri rawContactEntitlesUri;
481753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        public final long contactId;
482753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        public RawContactEntitlesInfo(Uri rawContactEntitlesUri, long contactId) {
483753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai            this.rawContactEntitlesUri = rawContactEntitlesUri;
484753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai            this.contactId = contactId;
485753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        }
486753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    }
487753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai
488753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    /**
489753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    * Listener for getting raw contact entitles info
490753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    */
491753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    public interface RawContactEntitlesInfoCallback {
492753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        /**
493753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        * Callback to get RawContactEntitlesInfo from contact id
494753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        *
495753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        * @param contactId Contact id that you want to process.
496753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        * @return RawContactEntitlesInfo that ready to process.
497753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        */
498753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai        RawContactEntitlesInfo getRawContactEntitlesInfo(long contactId);
499753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    }
500753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai
501753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai    private String createOneEntryInternal(long contactId,
502677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            final Method getEntityIteratorMethod) {
5034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final Map<String, List<ContentValues>> contentValuesListMap =
5044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                new HashMap<String, List<ContentValues>>();
5054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // The resolver may return the entity iterator with no data. It is possible.
5064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // e.g. If all the data in the contact of the given contact id are not exportable ones,
5074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        //      they are hidden from the view of this method, though contact id itself exists.
5084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        EntityIterator entityIterator = null;
5094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        try {
510753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai            Uri uri = mContentUriForRawContactsEntity;
511753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai            if (mRawContactEntitlesInfoCallback != null) {
512753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai                RawContactEntitlesInfo rawContactEntitlesInfo =
513753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai                        mRawContactEntitlesInfoCallback.getRawContactEntitlesInfo(contactId);
514753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai                uri = rawContactEntitlesInfo.rawContactEntitlesUri;
515753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai                contactId = rawContactEntitlesInfo.contactId;
516753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai            }
5174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final String selection = Data.CONTACT_ID + "=?";
518753058fffd5cead5e6ebe7e81a9810cc4ca9ceeaRicky Wai            final String[] selectionArgs = new String[] {String.valueOf(contactId)};
5194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (getEntityIteratorMethod != null) {
5204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                // Please note that this branch is executed by unit tests only
5214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                try {
5224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    entityIterator = (EntityIterator)getEntityIteratorMethod.invoke(null,
5234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            mContentResolver, uri, selection, selectionArgs, null);
5244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (IllegalArgumentException e) {
5254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    Log.e(LOG_TAG, "IllegalArgumentException has been thrown: " +
5264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            e.getMessage());
5274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (IllegalAccessException e) {
5284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    Log.e(LOG_TAG, "IllegalAccessException has been thrown: " +
5294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            e.getMessage());
5304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (InvocationTargetException e) {
53156174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa                    Log.e(LOG_TAG, "InvocationTargetException has been thrown: ", e);
53256174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa                    throw new RuntimeException("InvocationTargetException has been thrown");
5334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
5344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else {
5354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
5364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        uri, null, selection, selectionArgs, null));
5374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (entityIterator == null) {
5404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.e(LOG_TAG, "EntityIterator is null");
5414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return "";
5424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (!entityIterator.hasNext()) {
5454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.w(LOG_TAG, "Data does not exist. contactId: " + contactId);
5464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return "";
5474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            while (entityIterator.hasNext()) {
5504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Entity entity = entityIterator.next();
5514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                for (NamedContentValues namedContentValues : entity.getSubValues()) {
5524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    ContentValues contentValues = namedContentValues.values;
5534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    String key = contentValues.getAsString(Data.MIMETYPE);
5544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    if (key != null) {
5554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        List<ContentValues> contentValuesList =
5564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                contentValuesListMap.get(key);
5574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        if (contentValuesList == null) {
5584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            contentValuesList = new ArrayList<ContentValues>();
5594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            contentValuesListMap.put(key, contentValuesList);
5604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        }
5614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        contentValuesList.add(contentValues);
5624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    }
5634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
5644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } finally {
5664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (entityIterator != null) {
5674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                entityIterator.close();
5684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
5704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return buildVCard(contentValuesListMap);
5724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
5734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5745fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa    private VCardPhoneNumberTranslationCallback mPhoneTranslationCallback;
5755fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa    /**
5765fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * <p>
5775fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * Set a callback for phone number formatting. It will be called every time when this object
5785fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * receives a phone number for printing.
5795fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * </p>
5805fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * <p>
5815fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * When this is set {@link VCardConfig#FLAG_REFRAIN_PHONE_NUMBER_FORMATTING} will be ignored
5825fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * and the callback should be responsible for everything about phone number formatting.
5835fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * </p>
5845fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * <p>
5855fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * Caution: This interface will change. Please don't use without any strong reason.
5865fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * </p>
5875fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     */
5885fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa    public void setPhoneNumberTranslationCallback(VCardPhoneNumberTranslationCallback callback) {
5895fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa        mPhoneTranslationCallback = callback;
5905fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa    }
5915fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa
5924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
5934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * Builds and returns vCard using given map, whose key is CONTENT_ITEM_TYPE defined in
5944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * {ContactsContract}. Developers can override this method to customize the output.
5954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
5964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public String buildVCard(final Map<String, List<ContentValues>> contentValuesListMap) {
5974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (contentValuesListMap == null) {
5984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.e(LOG_TAG, "The given map is null. Ignore and return empty String");
5994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return "";
6004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } else {
6014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final VCardBuilder builder = new VCardBuilder(mVCardType, mCharset);
6024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
6034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
6045fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa                    .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE),
6055fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa                            mPhoneTranslationCallback)
6064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE))
6074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE))
6084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE))
6098c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa                    .appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE));
6108c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa            if ((mVCardType & VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT) == 0) {
6118c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa                builder.appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE));
6128c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa            }
6138c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa            builder.appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE))
6144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE))
6154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE))
616422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa                    .appendSipAddresses(contentValuesListMap.get(SipAddress.CONTENT_ITEM_TYPE))
6174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE));
6184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return builder.toString();
6194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void terminate() {
6237e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        closeCursorIfAppropriate();
6247e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mTerminateCalled = true;
6257e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
6267e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
6277e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private void closeCursorIfAppropriate() {
6287e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!mCursorSuppliedFromOutside && mCursor != null) {
6294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            try {
6304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCursor.close();
6314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } catch (SQLiteException e) {
6324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.e(LOG_TAG, "SQLiteException on Cursor#close(): " + e.getMessage());
6334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
6344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mCursor = null;
6354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    @Override
63991ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa    protected void finalize() throws Throwable {
64091ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa        try {
641a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa            if (!mTerminateCalled) {
642a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa                Log.e(LOG_TAG, "finalized() is called before terminate() being called");
643a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa            }
64491ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa        } finally {
64591ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa            super.finalize();
6464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
6504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return returns the number of available entities. The return value is undefined
6514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * when this object is not ready yet (typically when {{@link #init()} is not called
6524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * or when {@link #terminate()} is already called).
6534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
6544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public int getCount() {
6554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCursor == null) {
6564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.w(LOG_TAG, "This object is not ready yet.");
6574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return 0;
6584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return mCursor.getCount();
6604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
6634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return true when there's no entity to be built. The return value is undefined
6644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * when this object is not ready yet.
6654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
6664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean isAfterLast() {
6674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCursor == null) {
6684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.w(LOG_TAG, "This object is not ready yet.");
6694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
6704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return mCursor.isAfterLast();
6724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
6754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return Returns the error reason.
6764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
6774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public String getErrorReason() {
6784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return mErrorReason;
6794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa}
681