VCardComposer.java revision 8ed6de732dfb8bf8257152e5c5faf7e0ee760464
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;
444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.text.TextUtils;
454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.util.Log;
464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.BufferedWriter;
484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.IOException;
494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.OutputStream;
504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.OutputStreamWriter;
514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.UnsupportedEncodingException;
524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.Writer;
534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.lang.reflect.InvocationTargetException;
544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.lang.reflect.Method;
554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.ArrayList;
564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.HashMap;
574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.List;
584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Map;
594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/**
614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * The class for composing vCard from Contacts information.
634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Usually, this class should be used like this.
664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <pre class="prettyprint">VCardComposer composer = null;
684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * try {
694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     composer = new VCardComposer(context);
704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     composer.addHandler(
714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *             composer.new HandlerForOutputStream(outputStream));
724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     if (!composer.init()) {
734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         // Do something handling the situation.
744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         return;
754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     }
764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     while (!composer.isAfterLast()) {
774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         if (mCanceled) {
784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *             // Assume a user may cancel this operation during the export.
794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *             return;
804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         }
814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         if (!composer.createOneEntry()) {
824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *             // Do something handling the error situation.
834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *             return;
844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         }
854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     }
864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * } finally {
874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     if (composer != null) {
884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *         composer.terminate();
894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *     }
904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * }</pre>
914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Users have to manually take care of memory efficiency. Even one vCard may contain
934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * image of non-trivial size for mobile devices.
944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * {@link VCardBuilder} is used to build each vCard.
974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */
994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawapublic class VCardComposer {
1004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final String LOG_TAG = "VCardComposer";
1017e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private static final boolean DEBUG = false;
1024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO =
1044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        "Failed to get database information";
1054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static final String FAILURE_REASON_NO_ENTRY =
1074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        "There's no exportable in the database";
1084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static final String FAILURE_REASON_NOT_INITIALIZED =
1104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        "The vCard composer object is not correctly initialized";
1114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /** Should be visible only from developers... (no need to translate, hopefully) */
1134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static final String FAILURE_REASON_UNSUPPORTED_URI =
1144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        "The Uri vCard composer received is not supported by the composer.";
1154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static final String NO_ERROR = "No error";
1174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    // Strictly speaking, "Shift_JIS" is the most appropriate, but we use upper version here,
1194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    // since usual vCard devices for Japanese devices already use it.
1204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final String SHIFT_JIS = "SHIFT_JIS";
1214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final String UTF_8 = "UTF-8";
1224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final Map<Integer, String> sImMap;
1244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    static {
1264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap = new HashMap<Integer, String>();
1274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM);
1284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN);
1294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_YAHOO, VCardConstants.PROPERTY_X_YAHOO);
1304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ);
1314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
1324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        sImMap.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
1334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // We don't add Google talk here since it has to be handled separately.
1344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public static interface OneEntryHandler {
1374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        public boolean onInit(Context context);
1384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        public boolean onEntryCreated(String vcard);
1394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        public void onTerminate();
1404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
1434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * <p>
1444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * An useful handler for emitting vCard String to an OutputStream object one by one.
1454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * </p>
1464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * <p>
1474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * The input OutputStream object is closed() on {@link #onTerminate()}.
1484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * Must not close the stream outside this class.
1494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * </p>
1504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
1514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public final class HandlerForOutputStream implements OneEntryHandler {
1524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        private final OutputStream mOutputStream; // mWriter will close this.
1534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        private Writer mWriter;
1544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        /**
1564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa         * Input stream will be closed on the detruction of this object.
1574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa         */
1584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        public HandlerForOutputStream(final OutputStream outputStream) {
1594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mOutputStream = outputStream;
1604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
1614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
162da2f6ef422b360827f2c5231552d8c9fad0ed8b1Daisuke Miyakawa        @Override
1634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        public boolean onInit(final Context context) {
1644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            try {
1654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mWriter = new BufferedWriter(new OutputStreamWriter(
1664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        mOutputStream, mCharset));
1674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } catch (UnsupportedEncodingException e1) {
1684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.e(LOG_TAG, "Unsupported charset: " + mCharset);
1694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mErrorReason = "Encoding is not supported (usually this does not happen!): "
1704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        + mCharset;
1714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return false;
1724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
1734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (mIsDoCoMo) {
1754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                try {
1764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    // Create one empty entry.
1774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    mWriter.write(createOneEntryInternal("-1", null));
1784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (IOException e) {
1794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    Log.e(LOG_TAG,
1804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            "IOException occurred during exportOneContactData: "
1814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                    + e.getMessage());
1824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    mErrorReason = "IOException occurred: " + e.getMessage();
1834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    return false;
1844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
1854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
1864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return true;
1874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
1884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
189da2f6ef422b360827f2c5231552d8c9fad0ed8b1Daisuke Miyakawa        @Override
1904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        public boolean onEntryCreated(String vcard) {
1914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            try {
1924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mWriter.write(vcard);
1934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } catch (IOException e) {
1944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.e(LOG_TAG,
1954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        "IOException occurred during exportOneContactData: "
1964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                + e.getMessage());
1974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mErrorReason = "IOException occurred: " + e.getMessage();
1984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return false;
1994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
2004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return true;
2014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
2024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
203da2f6ef422b360827f2c5231552d8c9fad0ed8b1Daisuke Miyakawa        @Override
2044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        public void onTerminate() {
2054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (mWriter != null) {
2064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                try {
20791ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa                    mWriter.close();
2084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (IOException e) {
20991ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa                    Log.w(LOG_TAG, "IOException is thrown during close(). Ignored.", e);
2104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
2114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
2124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
2134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final Context mContext;
2164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final int mVCardType;
2174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final boolean mCareHandlerErrors;
2184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final ContentResolver mContentResolver;
2194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final boolean mIsDoCoMo;
2214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private Cursor mCursor;
2227e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean mCursorSuppliedFromOutside;
2234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private int mIdColumn;
224677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    private Uri mContentUriForRawContactsEntity;
2254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final String mCharset;
2274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final List<OneEntryHandler> mHandlerList;
2284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2297e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean mInitDone;
2304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private String mErrorReason = NO_ERROR;
2314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
232a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    /**
233a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * Set to false when one of {@link #init()} variants is called, and set to true when
234a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * {@link #terminate()} is called. Initially set to true.
235a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     */
236a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    private boolean mTerminateCalled = true;
23791ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa
2384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static final String[] sContactsProjection = new String[] {
2394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        Contacts._ID,
2404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    };
2414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(Context context) {
2434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, VCardConfig.VCARD_TYPE_DEFAULT, null, true);
2444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
2474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * The variant which sets charset to null and sets careHandlerErrors to true.
2484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
2494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(Context context, int vcardType) {
2504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, vcardType, null, true);
2514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(Context context, int vcardType, String charset) {
2544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, vcardType, charset, true);
2554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
2584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * The variant which sets charset to null.
2594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
2604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(final Context context, final int vcardType,
2614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final boolean careHandlerErrors) {
2624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(context, vcardType, null, careHandlerErrors);
2634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
2667e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Constructs for supporting call log entry vCard composing.
2674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     *
2684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param context Context to be used during the composition.
2694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param vcardType The type of vCard, typically available via {@link VCardConfig}.
2704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param charset The charset to be used. Use null when you don't need the charset.
2714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param careHandlerErrors If true, This object returns false everytime
2724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * a Handler object given via {{@link #addHandler(OneEntryHandler)} returns false.
2734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * If false, this ignores those errors.
2744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
2754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardComposer(final Context context, final int vcardType, String charset,
2764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final boolean careHandlerErrors) {
2777e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        this(context, context.getContentResolver(), vcardType, charset, careHandlerErrors);
2787e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
2797e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
2807e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    /**
2817e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Just for testing for now.
2827e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * @param resolver {@link ContentResolver} which used by this object.
2837e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * @hide
2847e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     */
2857e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    public VCardComposer(final Context context, ContentResolver resolver,
2867e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            final int vcardType, String charset, final boolean careHandlerErrors) {
2874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mContext = context;
2884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mVCardType = vcardType;
2894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCareHandlerErrors = careHandlerErrors;
2907e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mContentResolver = resolver;
2914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
2934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mHandlerList = new ArrayList<OneEntryHandler>();
2944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        charset = (TextUtils.isEmpty(charset) ? VCardConfig.DEFAULT_EXPORT_CHARSET : charset);
2964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final boolean shouldAppendCharsetParam = !(
297be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa                VCardConfig.isVersion30(vcardType) && UTF_8.equalsIgnoreCase(charset));
2984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mIsDoCoMo || shouldAppendCharsetParam) {
3009919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa            // TODO: clean up once we're sure CharsetUtils are really unnecessary any more.
3014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (SHIFT_JIS.equalsIgnoreCase(charset)) {
3029919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                /*if (mIsDoCoMo) {
3034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    try {
3044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
3054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    } catch (UnsupportedCharsetException e) {
3064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        Log.e(LOG_TAG,
3074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                "DoCoMo-specific SHIFT_JIS was not found. "
3084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                + "Use SHIFT_JIS as is.");
3094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        charset = SHIFT_JIS;
3104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    }
3114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } else {
3124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    try {
3134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
3144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    } catch (UnsupportedCharsetException e) {
3159919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                        // Log.e(LOG_TAG,
3169919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                        // "Career-specific SHIFT_JIS was not found. "
3179919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                        // + "Use SHIFT_JIS as is.");
3184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        charset = SHIFT_JIS;
3194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    }
3209919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                }*/
3214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCharset = charset;
3224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else {
323422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa                /* Log.w(LOG_TAG,
3244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        "The charset \"" + charset + "\" is used while "
325422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa                        + SHIFT_JIS + " is needed to be used."); */
3264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                if (TextUtils.isEmpty(charset)) {
3274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    mCharset = SHIFT_JIS;
3284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } else {
3299919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                    /*
3304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    try {
3314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        charset = CharsetUtils.charsetForVendor(charset).name();
3324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    } catch (UnsupportedCharsetException e) {
3334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        Log.i(LOG_TAG,
3344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                "Career-specific \"" + charset + "\" was not found (as usual). "
3354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                + "Use it as is.");
3369919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                    }*/
3374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    mCharset = charset;
3384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
3394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
3404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } else {
3414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (TextUtils.isEmpty(charset)) {
3424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCharset = UTF_8;
3434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else {
3449919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                /*try {
3454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    charset = CharsetUtils.charsetForVendor(charset).name();
3464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (UnsupportedCharsetException e) {
3474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    Log.i(LOG_TAG,
3484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            "Career-specific \"" + charset + "\" was not found (as usual). "
3494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            + "Use it as is.");
3509919ad2126c06dbf2eb54a11e6158f87f316bc22Daisuke Miyakawa                }*/
3514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCharset = charset;
3524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
3534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
3544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
3554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        Log.d(LOG_TAG, "Use the charset \"" + mCharset + "\"");
3564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
3574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
3584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
3594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * Must be called before {@link #init()}.
3604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
3614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void addHandler(OneEntryHandler handler) {
3624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (handler != null) {
3634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mHandlerList.add(handler);
3644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
3654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
3664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
3674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
3687e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Initializes this object using default {@link Contacts#CONTENT_URI}.
3697e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     *
3707e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * You can call this method or a variant of this method just once. In other words, you cannot
3717e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * reuse this object.
3727e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     *
3734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return Returns true when initialization is successful and all the other
3744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     *          methods are available. Returns false otherwise.
3754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
3764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean init() {
3774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return init(null, null);
3784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
3794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
380a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    /**
381a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * Special variant of init(), which accepts a Uri for obtaining {@link RawContactsEntity} from
382a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * {@link ContentResolver} with {@link Contacts#_ID}.
383a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * <code>
384a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * String selection = Data.CONTACT_ID + "=?";
385a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * String[] selectionArgs = new String[] {contactId};
386a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * Cursor cursor = mContentResolver.query(
387a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     *         contentUriForRawContactsEntity, null, selection, selectionArgs, null)
388a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     * </code>
3897e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     *
3907e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * You can call this method or a variant of this method just once. In other words, you cannot
3917e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * reuse this object.
392677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
393677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @deprecated Use {@link #init(Uri, String[], String, String[], String, Uri)} if you really
394677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * need to change the default Uri.
395a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa     */
396677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    @Deprecated
397a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    public boolean initWithRawContactsEntityUri(Uri contentUriForRawContactsEntity) {
398677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return init(Contacts.CONTENT_URI, sContactsProjection, null, null, null,
399677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                contentUriForRawContactsEntity);
400a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa    }
401a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa
4027e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    /**
4037e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Initializes this object using default {@link Contacts#CONTENT_URI} and given selection
4047e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * arguments.
4057e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     */
4064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean init(final String selection, final String[] selectionArgs) {
407677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return init(Contacts.CONTENT_URI, sContactsProjection, selection, selectionArgs,
408677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                null, null);
4094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
4104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
4114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
4124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * Note that this is unstable interface, may be deleted in the future.
4134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
4144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean init(final Uri contentUri, final String selection,
4154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final String[] selectionArgs, final String sortOrder) {
416677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return init(contentUri, sContactsProjection, selection, selectionArgs, sortOrder, null);
4177e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4187e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
419677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    /**
420677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * A variant of init(). Currently just for testing. Use other variants for init().
421677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
422677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * First we'll create {@link Cursor} for the list of contactId.
423677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
424677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * <code>
425677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * Cursor cursorForId = mContentResolver.query(
426677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *         contentUri, projection, selection, selectionArgs, sortOrder);
427677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * </code>
428677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
429677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * After that, we'll obtain data for each contactId in the list.
430677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
431677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * <code>
432677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * Cursor cursorForContent = mContentResolver.query(
433677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *         contentUriForRawContactsEntity, null,
434677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *         Data.CONTACT_ID + "=?", new String[] {contactId}, null)
435677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * </code>
436677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
437677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link #createOneEntry()} or its variants let the caller obtain each entry from
438677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * <code>cursorForContent</code> above.
439677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
440677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param contentUri Uri for obtaining the list of contactId. Used with
441677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
442677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param projection projection used with
443677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
444677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param selection selection used with
445677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
446677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param selectionArgs selectionArgs used with
447677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
448677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param sortOrder sortOrder used with
449677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * {@link ContentResolver#query(Uri, String[], String, String[], String)}
450677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @param contentUriForRawContactsEntity Uri for obtaining entries relevant to each
451677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * contactId.
452677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @return true when successful
453677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     *
454677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @hide
455677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     */
456677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    public boolean init(final Uri contentUri, final String[] projection,
457677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            final String selection, final String[] selectionArgs,
458677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            final String sortOrder, Uri contentUriForRawContactsEntity) {
4597e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!Contacts.CONTENT_URI.equals(contentUri)) {
4607e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            if (DEBUG) Log.d(LOG_TAG, "Unexpected contentUri: " + contentUri);
4617e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            mErrorReason = FAILURE_REASON_UNSUPPORTED_URI;
4627e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
4637e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
464677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        if (!initInterFirstPart(contentUriForRawContactsEntity)) {
4657e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
4667e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
4677e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!initInterCursorCreationPart(contentUri, projection, selection, selectionArgs,
4687e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                sortOrder)) {
4697e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
4707e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
4717e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!initInterMainPart()) {
4727e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
4737e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
4747e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return initInterLastPart();
4757e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4767e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
4777e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    /**
4787e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * Just for testing for now. Do not use.
4797e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     * @hide
4807e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa     */
4817e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    public boolean init(Cursor cursor) {
482677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        if (!initInterFirstPart(null)) {
4837e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
4847e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
4857e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mCursorSuppliedFromOutside = true;
4867e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mCursor = cursor;
4877e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!initInterMainPart()) {
4887e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            return false;
4897e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        }
4907e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return initInterLastPart();
4917e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
4927e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
493677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    private boolean initInterFirstPart(Uri contentUriForRawContactsEntity) {
494677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        mContentUriForRawContactsEntity =
495677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                (contentUriForRawContactsEntity != null ? contentUriForRawContactsEntity :
496677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                        RawContactsEntity.CONTENT_URI);
4977e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (mInitDone) {
4987e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            Log.e(LOG_TAG, "init() is already called");
4994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
5004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
5014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCareHandlerErrors) {
5034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
5044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    mHandlerList.size());
5054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            for (OneEntryHandler handler : mHandlerList) {
5064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                if (!handler.onInit(mContext)) {
5077e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                    if (DEBUG) {
5087e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                        Log.d(LOG_TAG,
5097e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                                String.format("One of OneEntryHandler (%s) return false on init.",
5107e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                                        handler.toString()));
5117e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                    }
5124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    for (OneEntryHandler finished : finishedList) {
5134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        finished.onTerminate();
5144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    }
5154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    return false;
5164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
5174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } else {
5194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            // Just ignore the false returned from onInit().
5204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            for (OneEntryHandler handler : mHandlerList) {
5214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                handler.onInit(mContext);
5224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
5244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5257e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return true;
5267e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
5277e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
5287e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean initInterCursorCreationPart(
5297e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            final Uri contentUri, final String[] projection,
5307e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            final String selection, final String[] selectionArgs, final String sortOrder) {
5317e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mCursorSuppliedFromOutside = false;
5324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCursor = mContentResolver.query(
5334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                contentUri, projection, selection, selectionArgs, sortOrder);
5344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCursor == null) {
5367e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            Log.e(LOG_TAG, String.format("Cursor became null unexpectedly"));
5374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO;
5384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
5394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
5407e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        return true;
5417e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
5424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5437e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean initInterMainPart() {
5447e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (mCursor.getCount() == 0 || !mCursor.moveToFirst()) {
5457e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            if (DEBUG) {
5467e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                Log.d(LOG_TAG,
5477e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa                    String.format("mCursor has an error (getCount: %d): ", mCursor.getCount()));
5484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
5497e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa            closeCursorIfAppropriate();
5504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
5514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
5524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mIdColumn = mCursor.getColumnIndex(Contacts._ID);
553677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return mIdColumn >= 0;
5547e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
5554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5567e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private boolean initInterLastPart() {
5577e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mInitDone = true;
558a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa        mTerminateCalled = false;
5594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return true;
5604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
5614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5628ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    /**
5638ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa     * @deprecated use {@link #createOneEntry()} instead.
5648ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa     */
5658ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    public boolean createOneEntryLegacy() {
5668ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa        return createOneEntryLegacy(null);
5674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
5684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
5694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
570677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @return a vCard string.
571677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     */
5728ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    public String createOneEntry() {
5738ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa        return createOneEntry(null);
574677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    }
575677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa
576677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    /**
577677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     * @hide
578677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa     */
5798ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    public String createOneEntry(Method getEntityIteratorMethod) {
580677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        final String vcard = createOneEntryInternal(mCursor.getString(mIdColumn),
581677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                getEntityIteratorMethod);
582677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        if (!mCursor.moveToNext()) {
583677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            Log.e(LOG_TAG, "Cursor#moveToNext() returned false");
584677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        }
585677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa        return vcard;
586677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    }
587677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa
588677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa    /**
5894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @param getEntityIteratorMethod For Dependency Injection.
5904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @hide just for testing.
5914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
5928ed6de732dfb8bf8257152e5c5faf7e0ee760464Daisuke Miyakawa    public boolean createOneEntryLegacy(Method getEntityIteratorMethod) {
5937e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!mInitDone) {
5944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mErrorReason = FAILURE_REASON_NOT_INITIALIZED;
5954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
5964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
5974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final String vcard;
5984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        try {
5994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (mIdColumn >= 0) {
6004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                vcard = createOneEntryInternal(mCursor.getString(mIdColumn),
6014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        getEntityIteratorMethod);
6024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else {
6034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.e(LOG_TAG, "Incorrect mIdColumn: " + mIdColumn);
6044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return true;
6054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
6064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } catch (OutOfMemoryError error) {
6074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            // Maybe some data (e.g. photo) is too big to have in memory. But it
6084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            // should be rare.
6094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.e(LOG_TAG, "OutOfMemoryError occured. Ignore the entry.");
6104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            System.gc();
6114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            // TODO: should tell users what happened?
6124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return true;
6134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } finally {
614677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            if (!mCursor.moveToNext()) {
615677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                Log.e(LOG_TAG, "Cursor#moveToNext() returned false");
616677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            }
6174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // This function does not care the OutOfMemoryError on the handler side :-P
6204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCareHandlerErrors) {
6214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
6224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    mHandlerList.size());
6234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            for (OneEntryHandler handler : mHandlerList) {
6244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                if (!handler.onEntryCreated(vcard)) {
6254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    return false;
6264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
6274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
6284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } else {
6294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            for (OneEntryHandler handler : mHandlerList) {
6304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                handler.onEntryCreated(vcard);
6314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
6324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
6334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return true;
6354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
6364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private String createOneEntryInternal(final String contactId,
638677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa            final Method getEntityIteratorMethod) {
6394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final Map<String, List<ContentValues>> contentValuesListMap =
6404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                new HashMap<String, List<ContentValues>>();
6414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // The resolver may return the entity iterator with no data. It is possible.
6424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // e.g. If all the data in the contact of the given contact id are not exportable ones,
6434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        //      they are hidden from the view of this method, though contact id itself exists.
6444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        EntityIterator entityIterator = null;
6454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        try {
646a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa            final Uri uri = mContentUriForRawContactsEntity;
6474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final String selection = Data.CONTACT_ID + "=?";
6484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final String[] selectionArgs = new String[] {contactId};
6494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (getEntityIteratorMethod != null) {
6504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                // Please note that this branch is executed by unit tests only
6514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                try {
6524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    entityIterator = (EntityIterator)getEntityIteratorMethod.invoke(null,
6534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            mContentResolver, uri, selection, selectionArgs, null);
6544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (IllegalArgumentException e) {
6554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    Log.e(LOG_TAG, "IllegalArgumentException has been thrown: " +
6564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            e.getMessage());
6574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (IllegalAccessException e) {
6584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    Log.e(LOG_TAG, "IllegalAccessException has been thrown: " +
6594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            e.getMessage());
6604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                } catch (InvocationTargetException e) {
6614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    Log.e(LOG_TAG, "InvocationTargetException has been thrown: ");
6624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    StackTraceElement[] stackTraceElements = e.getCause().getStackTrace();
6634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    for (StackTraceElement element : stackTraceElements) {
6644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        Log.e(LOG_TAG, "    at " + element.toString());
6654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    }
666677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa                    throw new RuntimeException("InvocationTargetException has been thrown: " +
6674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            e.getCause().getMessage());
6684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
6694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else {
6704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
6714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        uri, null, selection, selectionArgs, null));
6724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
6734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (entityIterator == null) {
6754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.e(LOG_TAG, "EntityIterator is null");
6764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return "";
6774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
6784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (!entityIterator.hasNext()) {
6804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.w(LOG_TAG, "Data does not exist. contactId: " + contactId);
6814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return "";
6824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
6834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
6844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            while (entityIterator.hasNext()) {
6854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Entity entity = entityIterator.next();
6864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                for (NamedContentValues namedContentValues : entity.getSubValues()) {
6874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    ContentValues contentValues = namedContentValues.values;
6884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    String key = contentValues.getAsString(Data.MIMETYPE);
6894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    if (key != null) {
6904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        List<ContentValues> contentValuesList =
6914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                                contentValuesListMap.get(key);
6924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        if (contentValuesList == null) {
6934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            contentValuesList = new ArrayList<ContentValues>();
6944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                            contentValuesListMap.put(key, contentValuesList);
6954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        }
6964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        contentValuesList.add(contentValues);
6974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    }
6984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                }
6994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
7004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } finally {
7014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (entityIterator != null) {
7024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                entityIterator.close();
7034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
7044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
7054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
7064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return buildVCard(contentValuesListMap);
7074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
7084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
7094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
7104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * Builds and returns vCard using given map, whose key is CONTENT_ITEM_TYPE defined in
7114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * {ContactsContract}. Developers can override this method to customize the output.
7124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
7134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public String buildVCard(final Map<String, List<ContentValues>> contentValuesListMap) {
7144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (contentValuesListMap == null) {
7154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.e(LOG_TAG, "The given map is null. Ignore and return empty String");
7164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return "";
7174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } else {
7184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final VCardBuilder builder = new VCardBuilder(mVCardType, mCharset);
7194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
7204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
7214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE))
7224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE))
7234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE))
7244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE))
7258c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa                    .appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE));
7268c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa            if ((mVCardType & VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT) == 0) {
7278c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa                builder.appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE));
7288c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa            }
7298c1cdbbccd5169122c183f6fbfd4436faacf2a1dDaisuke Miyakawa            builder.appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE))
7304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE))
7314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE))
732422643669a44d08ca8b22a73286fae988a288b0eDaisuke Miyakawa                    .appendSipAddresses(contentValuesListMap.get(SipAddress.CONTENT_ITEM_TYPE))
7334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    .appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE));
7344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return builder.toString();
7354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
7364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
7374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
7384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void terminate() {
7394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        for (OneEntryHandler handler : mHandlerList) {
7404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            handler.onTerminate();
7414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
7424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
7437e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        closeCursorIfAppropriate();
7447e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        mTerminateCalled = true;
7457e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    }
7467e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa
7477e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa    private void closeCursorIfAppropriate() {
7487e4e86eb5ad2c8a68ca7005ef4dee64a82ce0198Daisuke Miyakawa        if (!mCursorSuppliedFromOutside && mCursor != null) {
7494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            try {
7504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCursor.close();
7514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } catch (SQLiteException e) {
7524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                Log.e(LOG_TAG, "SQLiteException on Cursor#close(): " + e.getMessage());
7534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
7544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mCursor = null;
7554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
7564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
7574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
7584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    @Override
75991ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa    protected void finalize() throws Throwable {
76091ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa        try {
761a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa            if (!mTerminateCalled) {
762a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa                Log.e(LOG_TAG, "finalized() is called before terminate() being called");
763a11303ccb430ca40210900823807027cc842bf6cDaisuke Miyakawa            }
76491ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa        } finally {
76591ff68b93f7a623f168697ebdb895daea3542579Daisuke Miyakawa            super.finalize();
7664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
7674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
7684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
7694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
7704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return returns the number of available entities. The return value is undefined
7714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * when this object is not ready yet (typically when {{@link #init()} is not called
7724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * or when {@link #terminate()} is already called).
7734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
7744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public int getCount() {
7754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCursor == null) {
7764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.w(LOG_TAG, "This object is not ready yet.");
7774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return 0;
7784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
7794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return mCursor.getCount();
7804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
7814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
7824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
7834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return true when there's no entity to be built. The return value is undefined
7844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * when this object is not ready yet.
7854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
7864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public boolean isAfterLast() {
7874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCursor == null) {
7884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.w(LOG_TAG, "This object is not ready yet.");
7894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return false;
7904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
7914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return mCursor.isAfterLast();
7924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
7934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
7944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
7954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @return Returns the error reason.
7964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
7974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public String getErrorReason() {
7984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return mErrorReason;
7994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
8004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa}
801