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
1574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final String[] sContactsProjection = new String[] {
1584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        Contacts._ID,
1594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    };
1604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(Context context) {
1624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, VCardConfig.VCARD_TYPE_DEFAULT, null, true);
1634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
1664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * The variant which sets charset to null and sets careHandlerErrors to true.
1674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
1684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(Context context, int vcardType) {
1694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, vcardType, null, true);
1704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(Context context, int vcardType, String charset) {
1734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, vcardType, charset, true);
1744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
1774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * The variant which sets charset to null.
1784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
1794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(final Context context, final int vcardType,
1804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final boolean careHandlerErrors) {
1814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, vcardType, null, careHandlerErrors);
1824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
1857e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Constructs for supporting call log entry vCard composing.
1864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     *
1874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param context Context to be used during the composition.
1884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param vcardType The type of vCard, typically available via {@link VCardConfig}.
1894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param charset The charset to be used. Use null when you don't need the charset.
1904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param careHandlerErrors If true, This object returns false everytime
1914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
1924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(final Context context, final int vcardType, String charset,
1934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final boolean careHandlerErrors) {
1947e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        this(context, context.getContentResolver(), vcardType, charset, careHandlerErrors);
1957e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
1967e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
1977e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    /**
1987e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Just for testing for now.
1997e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * @param resolver {@link ContentResolver} which used by this object.
2007e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * @hide
2017e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     */
2027e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    public VCardComposer(final Context context, ContentResolver resolver,
2037e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            final int vcardType, String charset, final boolean careHandlerErrors) {
20456174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa        // Not used right now
20556174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa        // mContext = context;
2064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mVCardType = vcardType;
2077e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mContentResolver = resolver;
2084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
2104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        charset = (TextUtils.isEmpty(charset) ? VCardConfig.DEFAULT_EXPORT_CHARSET : charset);
2124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final boolean shouldAppendCharsetParam = !(
213be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa                VCardConfig.isVersion30(vcardType) && UTF_8.equalsIgnoreCase(charset));
2144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mIsDoCoMo || shouldAppendCharsetParam) {
2169919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa            // TODO: clean up once we're sure CharsetUtils are really unnecessary any more.
2174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (SHIFT_JIS.equalsIgnoreCase(charset)) {
2189919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                /*if (mIsDoCoMo) {
2194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    try {
2204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
2214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    } catch (UnsupportedCharsetException e) {
2224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        Log.e(LOG_TAG,
2234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                "DoCoMo-specific SHIFT_JIS was not found. "
2244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                + "Use SHIFT_JIS as is.");
2254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        charset = SHIFT_JIS;
2264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    }
2274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } else {
2284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    try {
2294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
2304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    } catch (UnsupportedCharsetException e) {
2319919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                        // Log.e(LOG_TAG,
2329919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                        // "Career-specific SHIFT_JIS was not found. "
2339919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                        // + "Use SHIFT_JIS as is.");
2344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        charset = SHIFT_JIS;
2354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    }
2369919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                }*/
2374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCharset = charset;
2384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else {
239422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa                /* Log.w(LOG_TAG,
2404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        "The charset \"" + charset + "\" is used while "
241422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa                        + SHIFT_JIS + " is needed to be used."); */
2424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                if (TextUtils.isEmpty(charset)) {
2434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    mCharset = SHIFT_JIS;
2444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } else {
2459919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                    /*
2464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    try {
2474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        charset = CharsetUtils.charsetForVendor(charset).name();
2484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    } catch (UnsupportedCharsetException e) {
2494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        Log.i(LOG_TAG,
2504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                "Career-specific \"" + charset + "\" was not found (as usual). "
2514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                + "Use it as is.");
2529919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                    }*/
2534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    mCharset = charset;
2544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
2554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
2564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } else {
2574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (TextUtils.isEmpty(charset)) {
2584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCharset = UTF_8;
2594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else {
2609919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                /*try {
2614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    charset = CharsetUtils.charsetForVendor(charset).name();
2624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (UnsupportedCharsetException e) {
2634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    Log.i(LOG_TAG,
2644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            "Career-specific \"" + charset + "\" was not found (as usual). "
2654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            + "Use it as is.");
2669919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                }*/
2674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCharset = charset;
2684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
2694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
2704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        Log.d(LOG_TAG, "Use the charset \"" + mCharset + "\"");
2724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
2757e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Initializes this object using default {@link Contacts#CONTENT_URI}.
2767e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     *
2777e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * You can call this method or a variant of this method just once. In other words, you cannot
2787e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * reuse this object.
2797e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     *
2804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return Returns true when initialization is successful and all the other
2814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     *          methods are available. Returns false otherwise.
2824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
2834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean init() {
2844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return init(null, null);
2854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
287a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    /**
288a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * Special variant of init(), which accepts a Uri for obtaining {@link RawContactsEntity} from
289a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * {@link ContentResolver} with {@link Contacts#_ID}.
290a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * <code>
291a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * String selection = Data.CONTACT_ID + "=?";
292a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * String[] selectionArgs = new String[] {contactId};
293a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * Cursor cursor = mContentResolver.query(
294a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     *         contentUriForRawContactsEntity, null, selection, selectionArgs, null)
295a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * </code>
2967e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     *
2977e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * You can call this method or a variant of this method just once. In other words, you cannot
2987e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * reuse this object.
299677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
300677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @deprecated Use {@link #init(Uri, String[], String, String[], String, Uri)} if you really
301677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * need to change the default Uri.
302a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     */
303677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    @Deprecated
304a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    public boolean initWithRawContactsEntityUri(Uri contentUriForRawContactsEntity) {
305677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return init(Contacts.CONTENT_URI, sContactsProjection, null, null, null,
306677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                contentUriForRawContactsEntity);
307a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    }
308a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa
3097e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    /**
3107e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Initializes this object using default {@link Contacts#CONTENT_URI} and given selection
3117e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * arguments.
3127e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     */
3134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean init(final String selection, final String[] selectionArgs) {
314677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return init(Contacts.CONTENT_URI, sContactsProjection, selection, selectionArgs,
315677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                null, null);
3164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
3174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
3184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
3194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * Note that this is unstable interface, may be deleted in the future.
3204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
3214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean init(final Uri contentUri, final String selection,
3224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final String[] selectionArgs, final String sortOrder) {
323677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return init(contentUri, sContactsProjection, selection, selectionArgs, sortOrder, null);
3247e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
3257e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
326677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    /**
327846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * @param contentUri Uri for obtaining the list of contactId. Used with
328846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
329846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * @param selection selection used with
330846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
331846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * @param selectionArgs selectionArgs used with
332846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
333846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * @param sortOrder sortOrder used with
334846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
335846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * @param contentUriForRawContactsEntity Uri for obtaining entries relevant to each
336846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * contactId.
337846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     * Note that this is an unstable interface, may be deleted in the future.
338846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen     */
339846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen    public boolean init(final Uri contentUri, final String selection,
340846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen            final String[] selectionArgs, final String sortOrder,
341846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen            final Uri contentUriForRawContactsEntity) {
342846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen        return init(contentUri, sContactsProjection, selection, selectionArgs, sortOrder,
343846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen                contentUriForRawContactsEntity);
344846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen    }
345846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen
346846712bf3921bec5f0654f68e95df790b398acd5Martijn Coenen    /**
347677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * A variant of init(). Currently just for testing. Use other variants for init().
348677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
349677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * First we'll create {@link Cursor} for the list of contactId.
350677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
351677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * <code>
352677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * Cursor cursorForId = mContentResolver.query(
353677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *         contentUri, projection, selection, selectionArgs, sortOrder);
354677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * </code>
355677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
356677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * After that, we'll obtain data for each contactId in the list.
357677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
358677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * <code>
359677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * Cursor cursorForContent = mContentResolver.query(
360677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *         contentUriForRawContactsEntity, null,
361677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *         Data.CONTACT_ID + "=?", new String[] {contactId}, null)
362677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * </code>
363677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
364677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link #createOneEntry()} or its variants let the caller obtain each entry from
365677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * <code>cursorForContent</code> above.
366677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
367677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param contentUri Uri for obtaining the list of contactId. Used with
368677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
369677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param projection projection used with
370677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
371677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param selection selection used with
372677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
373677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param selectionArgs selectionArgs used with
374677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
375677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param sortOrder sortOrder used with
376677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
377677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param contentUriForRawContactsEntity Uri for obtaining entries relevant to each
378677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * contactId.
379677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @return true when successful
380677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
381677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @hide
382677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     */
383677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    public boolean init(final Uri contentUri, final String[] projection,
384677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            final String selection, final String[] selectionArgs,
385677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            final String sortOrder, Uri contentUriForRawContactsEntity) {
3865f0f9e9f2d3e8b73beaf49d542e10fdec6fa199bMartijn Coenen        if (!ContactsContract.AUTHORITY.equals(contentUri.getAuthority())) {
3877e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            if (DEBUG) Log.d(LOG_TAG, "Unexpected contentUri: " + contentUri);
3887e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            mErrorReason = FAILURE_REASON_UNSUPPORTED_URI;
3897e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
3907e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
3915f0f9e9f2d3e8b73beaf49d542e10fdec6fa199bMartijn Coenen
392677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        if (!initInterFirstPart(contentUriForRawContactsEntity)) {
3937e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
3947e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
3957e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!initInterCursorCreationPart(contentUri, projection, selection, selectionArgs,
3967e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                sortOrder)) {
3977e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
3987e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
3997e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!initInterMainPart()) {
4007e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
4017e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
4027e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return initInterLastPart();
4037e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4047e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
4057e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    /**
4067e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Just for testing for now. Do not use.
4077e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * @hide
4087e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     */
4097e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    public boolean init(Cursor cursor) {
410677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        if (!initInterFirstPart(null)) {
4117e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
4127e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
4137e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mCursorSuppliedFromOutside = true;
4147e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mCursor = cursor;
4157e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!initInterMainPart()) {
4167e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
4177e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
4187e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return initInterLastPart();
4197e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4207e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
421677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    private boolean initInterFirstPart(Uri contentUriForRawContactsEntity) {
422677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        mContentUriForRawContactsEntity =
423677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                (contentUriForRawContactsEntity != null ? contentUriForRawContactsEntity :
424677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                        RawContactsEntity.CONTENT_URI);
4257e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (mInitDone) {
4267e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            Log.e(LOG_TAG, "init() is already called");
4274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
4284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
4297e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return true;
4307e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4317e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
4327e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean initInterCursorCreationPart(
4337e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            final Uri contentUri, final String[] projection,
4347e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            final String selection, final String[] selectionArgs, final String sortOrder) {
4357e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mCursorSuppliedFromOutside = false;
4364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCursor = mContentResolver.query(
4374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                contentUri, projection, selection, selectionArgs, sortOrder);
4384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCursor == null) {
4397e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            Log.e(LOG_TAG, String.format("Cursor became null unexpectedly"));
4404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO;
4414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
4424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
4437e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return true;
4447e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
4467e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean initInterMainPart() {
4477e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (mCursor.getCount() == 0 || !mCursor.moveToFirst()) {
4487e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            if (DEBUG) {
4497e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                Log.d(LOG_TAG,
4507e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                    String.format("mCursor has an error (getCount: %d): ", mCursor.getCount()));
4514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
4527e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            closeCursorIfAppropriate();
4534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
4544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
4554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mIdColumn = mCursor.getColumnIndex(Contacts._ID);
456677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return mIdColumn >= 0;
4577e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
4597e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean initInterLastPart() {
4607e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mInitDone = true;
461a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa        mTerminateCalled = false;
4624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return true;
4634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
4644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
4658ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    /**
466677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @return a vCard string.
467677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     */
4688ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    public String createOneEntry() {
4698ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa        return createOneEntry(null);
470677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    }
471677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa
472677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    /**
473677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @hide
474677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     */
4758ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    public String createOneEntry(Method getEntityIteratorMethod) {
47656174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa        if (mIsDoCoMo && !mFirstVCardEmittedInDoCoMoCase) {
47756174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            mFirstVCardEmittedInDoCoMoCase = true;
47856174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            // Previously we needed to emit empty data for this specific case, but actually
47956174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            // this doesn't work now, as resolver doesn't return any data with "-1" contactId.
48056174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            // TODO: re-introduce or remove this logic. Needs to modify unit test when we
48156174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            // re-introduce the logic.
48256174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa            // return createOneEntryInternal("-1", getEntityIteratorMethod);
48356174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa        }
48456174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa
485677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        final String vcard = createOneEntryInternal(mCursor.getString(mIdColumn),
486677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                getEntityIteratorMethod);
487677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        if (!mCursor.moveToNext()) {
488677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            Log.e(LOG_TAG, "Cursor#moveToNext() returned false");
489677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        }
490677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return vcard;
491677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    }
492677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa
4934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private String createOneEntryInternal(final String contactId,
494677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            final Method getEntityIteratorMethod) {
4954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final Map<String, List<ContentValues>> contentValuesListMap =
4964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                new HashMap<String, List<ContentValues>>();
4974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // The resolver may return the entity iterator with no data. It is possible.
4984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // e.g. If all the data in the contact of the given contact id are not exportable ones,
4994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        //      they are hidden from the view of this method, though contact id itself exists.
5004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        EntityIterator entityIterator = null;
5014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        try {
502a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa            final Uri uri = mContentUriForRawContactsEntity;
5034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final String selection = Data.CONTACT_ID + "=?";
5044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final String[] selectionArgs = new String[] {contactId};
5054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (getEntityIteratorMethod != null) {
5064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                // Please note that this branch is executed by unit tests only
5074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                try {
5084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    entityIterator = (EntityIterator)getEntityIteratorMethod.invoke(null,
5094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            mContentResolver, uri, selection, selectionArgs, null);
5104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (IllegalArgumentException e) {
5114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    Log.e(LOG_TAG, "IllegalArgumentException has been thrown: " +
5124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            e.getMessage());
5134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (IllegalAccessException e) {
5144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    Log.e(LOG_TAG, "IllegalAccessException has been thrown: " +
5154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            e.getMessage());
5164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (InvocationTargetException e) {
51756174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa                    Log.e(LOG_TAG, "InvocationTargetException has been thrown: ", e);
51856174dfd0654acbe828e4db38537ec5a3a04d466Daisuke Miyakawa                    throw new RuntimeException("InvocationTargetException has been thrown");
5194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
5204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else {
5214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
5224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        uri, null, selection, selectionArgs, null));
5234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (entityIterator == null) {
5264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.e(LOG_TAG, "EntityIterator is null");
5274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return "";
5284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (!entityIterator.hasNext()) {
5314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.w(LOG_TAG, "Data does not exist. contactId: " + contactId);
5324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return "";
5334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            while (entityIterator.hasNext()) {
5364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Entity entity = entityIterator.next();
5374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                for (NamedContentValues namedContentValues : entity.getSubValues()) {
5384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    ContentValues contentValues = namedContentValues.values;
5394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    String key = contentValues.getAsString(Data.MIMETYPE);
5404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    if (key != null) {
5414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        List<ContentValues> contentValuesList =
5424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                contentValuesListMap.get(key);
5434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        if (contentValuesList == null) {
5444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            contentValuesList = new ArrayList<ContentValues>();
5454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            contentValuesListMap.put(key, contentValuesList);
5464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        }
5474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        contentValuesList.add(contentValues);
5484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    }
5494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
5504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } finally {
5524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (entityIterator != null) {
5534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                entityIterator.close();
5544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
5564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return buildVCard(contentValuesListMap);
5584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
5594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5605fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa    private VCardPhoneNumberTranslationCallback mPhoneTranslationCallback;
5615fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa    /**
5625fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * <p>
5635fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * Set a callback for phone number formatting. It will be called every time when this object
5645fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * receives a phone number for printing.
5655fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * </p>
5665fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * <p>
5675fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * When this is set {@link VCardConfig#FLAG_REFRAIN_PHONE_NUMBER_FORMATTING} will be ignored
5685fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * and the callback should be responsible for everything about phone number formatting.
5695fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * </p>
5705fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * <p>
5715fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * Caution: This interface will change. Please don't use without any strong reason.
5725fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     * </p>
5735fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa     */
5745fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa    public void setPhoneNumberTranslationCallback(VCardPhoneNumberTranslationCallback callback) {
5755fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa        mPhoneTranslationCallback = callback;
5765fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa    }
5775fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa
5784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
5794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * Builds and returns vCard using given map, whose key is CONTENT_ITEM_TYPE defined in
5804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * {ContactsContract}. Developers can override this method to customize the output.
5814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
5824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public String buildVCard(final Map<String, List<ContentValues>> contentValuesListMap) {
5834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (contentValuesListMap == null) {
5844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.e(LOG_TAG, "The given map is null. Ignore and return empty String");
5854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return "";
5864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } else {
5874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final VCardBuilder builder = new VCardBuilder(mVCardType, mCharset);
5884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
5894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
5905fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa                    .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE),
5915fffd2ba2d7fc22271251251f89043ab345acd74Daisuke Miyakawa                            mPhoneTranslationCallback)
5924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE))
5934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE))
5944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE))
5958c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa                    .appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE));
5968c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa            if ((mVCardType & VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT) == 0) {
5978c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa                builder.appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE));
5988c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa            }
5998c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa            builder.appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE))
6004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE))
6014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE))
602422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa                    .appendSipAddresses(contentValuesListMap.get(SipAddress.CONTENT_ITEM_TYPE))
6034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE));
6044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return builder.toString();
6054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void terminate() {
6097e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        closeCursorIfAppropriate();
6107e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mTerminateCalled = true;
6117e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
6127e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
6137e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private void closeCursorIfAppropriate() {
6147e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!mCursorSuppliedFromOutside && mCursor != null) {
6154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            try {
6164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCursor.close();
6174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } catch (SQLiteException e) {
6184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.e(LOG_TAG, "SQLiteException on Cursor#close(): " + e.getMessage());
6194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
6204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mCursor = null;
6214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    @Override
62591ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa    protected void finalize() throws Throwable {
62691ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa        try {
627a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa            if (!mTerminateCalled) {
628a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa                Log.e(LOG_TAG, "finalized() is called before terminate() being called");
629a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa            }
63091ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa        } finally {
63191ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa            super.finalize();
6324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
6364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return returns the number of available entities. The return value is undefined
6374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * when this object is not ready yet (typically when {{@link #init()} is not called
6384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * or when {@link #terminate()} is already called).
6394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
6404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public int getCount() {
6414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCursor == null) {
6424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.w(LOG_TAG, "This object is not ready yet.");
6434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return 0;
6444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return mCursor.getCount();
6464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
6494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return true when there's no entity to be built. The return value is undefined
6504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * when this object is not ready yet.
6514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
6524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean isAfterLast() {
6534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCursor == null) {
6544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.w(LOG_TAG, "This object is not ready yet.");
6554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
6564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return mCursor.isAfterLast();
6584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
6614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return Returns the error reason.
6624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
6634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public String getErrorReason() {
6644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return mErrorReason;
6654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa}
667