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