BluetoothPbapVcardManager.java revision c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1
1b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh/*
2b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * Copyright (c) 2008-2009, Motorola, Inc.
3c7a57f31515107366589bd6875c3cc4af1fc806efredc * Copyright (C) 2009-2012, Broadcom Corporation
4b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh *
5b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * All rights reserved.
6b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh *
7b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * Redistribution and use in source and binary forms, with or without
8b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * modification, are permitted provided that the following conditions are met:
9b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh *
10b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * - Redistributions of source code must retain the above copyright notice,
11b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * this list of conditions and the following disclaimer.
12b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh *
13b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * - Redistributions in binary form must reproduce the above copyright notice,
14b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * this list of conditions and the following disclaimer in the documentation
15b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * and/or other materials provided with the distribution.
16b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh *
17b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * - Neither the name of the Motorola, Inc. nor the names of its contributors
18b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * may be used to endorse or promote products derived from this software
19b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * without specific prior written permission.
20b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh *
21b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh * POSSIBILITY OF SUCH DAMAGE.
32b9cd7fee03a41e56a0cea9aa2e1af3b28c5be590Jaikumar Ganesh */
332c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
342c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fanpackage com.android.bluetooth.pbap;
352c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
362f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yueimport android.content.ContentResolver;
372f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yueimport android.content.Context;
38c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Guptaimport android.database.CursorWindowAllocationException;
39198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawaimport android.database.Cursor;
40198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawaimport android.net.Uri;
41198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawaimport android.provider.CallLog;
42198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawaimport android.provider.CallLog.Calls;
432f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yueimport android.provider.ContactsContract.CommonDataKinds;
442f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yueimport android.provider.ContactsContract.Contacts;
452f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yueimport android.provider.ContactsContract.Data;
462f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yueimport android.provider.ContactsContract.CommonDataKinds.Phone;
470dcd2262d853c2011e11617a8efba6758370c41fLiejun Taoimport android.provider.ContactsContract.PhoneLookup;
48d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawaimport android.telephony.PhoneNumberUtils;
49198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawaimport android.text.TextUtils;
50198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawaimport android.util.Log;
51198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa
52198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawaimport com.android.bluetooth.R;
5312cb33f6d9fd269944a5618661e3880beea58b6eDaisuke Miyakawaimport com.android.vcard.VCardComposer;
5412cb33f6d9fd269944a5618661e3880beea58b6eDaisuke Miyakawaimport com.android.vcard.VCardConfig;
55d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawaimport com.android.vcard.VCardPhoneNumberTranslationCallback;
562f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue
572f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yueimport java.io.IOException;
582f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yueimport java.io.OutputStream;
592c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fanimport java.util.ArrayList;
602c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
610b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yueimport javax.obex.ServerOperation;
62198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawaimport javax.obex.Operation;
63198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawaimport javax.obex.ResponseCodes;
64198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa
65c7a57f31515107366589bd6875c3cc4af1fc806efredcimport com.android.bluetooth.Utils;
66c7a57f31515107366589bd6875c3cc4af1fc806efredc
672c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fanpublic class BluetoothPbapVcardManager {
682f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue    private static final String TAG = "BluetoothPbapVcardManager";
692c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
704446eaa935994bc91d6d308303e8d27526b4590dLixin Yue    private static final boolean V = BluetoothPbapService.VERBOSE;
714446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
722c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    private ContentResolver mResolver;
732c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
742c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    private Context mContext;
752c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
762f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue    static final String[] PHONES_PROJECTION = new String[] {
772f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            Data._ID, // 0
782f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            CommonDataKinds.Phone.TYPE, // 1
792f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            CommonDataKinds.Phone.LABEL, // 2
802f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            CommonDataKinds.Phone.NUMBER, // 3
812f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            Contacts.DISPLAY_NAME, // 4
822c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    };
832c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
84e10881ae39eb4affb7a78827f2060964e8534515Daisuke Miyakawa    private static final int PHONE_NUMBER_COLUMN_INDEX = 3;
852c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
862f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue    static final String SORT_ORDER_PHONE_NUMBER = CommonDataKinds.Phone.NUMBER + " ASC";
874446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
882b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    static final String[] CONTACTS_PROJECTION = new String[] {
892b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            Contacts._ID, // 0
902b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            Contacts.DISPLAY_NAME, // 1
912b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    };
922b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh
932b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    static final int CONTACTS_ID_COLUMN_INDEX = 0;
942b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh
952b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    static final int CONTACTS_NAME_COLUMN_INDEX = 1;
962b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh
972b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    // call histories use dynamic handles, and handles should order by date; the
982b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    // most recently one should be the first handle. In table "calls", _id and
992b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    // date are consistent in ordering, to implement simply, we sort by _id
1002b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    // here.
1012b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    static final String CALLLOG_SORT_ORDER = Calls._ID + " DESC";
1022b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh
103cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue    private static final String CLAUSE_ONLY_VISIBLE = Contacts.IN_VISIBLE_GROUP + "=1";
104cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue
1052c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    public BluetoothPbapVcardManager(final Context context) {
1062c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan        mContext = context;
1072c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan        mResolver = mContext.getContentResolver();
1082c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    }
1092c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
110c7a57f31515107366589bd6875c3cc4af1fc806efredc    /**
111c7a57f31515107366589bd6875c3cc4af1fc806efredc     * Create an owner vcard from the configured profile
112c7a57f31515107366589bd6875c3cc4af1fc806efredc     * @param vcardType21
113c7a57f31515107366589bd6875c3cc4af1fc806efredc     * @return
114c7a57f31515107366589bd6875c3cc4af1fc806efredc     */
115c7a57f31515107366589bd6875c3cc4af1fc806efredc    private final String getOwnerPhoneNumberVcardFromProfile(final boolean vcardType21, final byte[] filter) {
116c7a57f31515107366589bd6875c3cc4af1fc806efredc        // Currently only support Generic Vcard 2.1 and 3.0
117c7a57f31515107366589bd6875c3cc4af1fc806efredc        int vcardType;
118c7a57f31515107366589bd6875c3cc4af1fc806efredc        if (vcardType21) {
119c7a57f31515107366589bd6875c3cc4af1fc806efredc            vcardType = VCardConfig.VCARD_TYPE_V21_GENERIC;
120c7a57f31515107366589bd6875c3cc4af1fc806efredc        } else {
121c7a57f31515107366589bd6875c3cc4af1fc806efredc            vcardType = VCardConfig.VCARD_TYPE_V30_GENERIC;
122c7a57f31515107366589bd6875c3cc4af1fc806efredc        }
1234a53a55dc10d3a26c94e5844f7d4a2565a67142cfredc
1244a53a55dc10d3a26c94e5844f7d4a2565a67142cfredc        if (!BluetoothPbapConfig.includePhotosInVcard()) {
1254a53a55dc10d3a26c94e5844f7d4a2565a67142cfredc            vcardType |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT;
1264a53a55dc10d3a26c94e5844f7d4a2565a67142cfredc        }
1274a53a55dc10d3a26c94e5844f7d4a2565a67142cfredc
128c7a57f31515107366589bd6875c3cc4af1fc806efredc        return BluetoothPbapUtils.createProfileVCard(mContext, vcardType,filter);
129c7a57f31515107366589bd6875c3cc4af1fc806efredc    }
130c7a57f31515107366589bd6875c3cc4af1fc806efredc
131c7a57f31515107366589bd6875c3cc4af1fc806efredc    public final String getOwnerPhoneNumberVcard(final boolean vcardType21, final byte[] filter) {
132c7a57f31515107366589bd6875c3cc4af1fc806efredc        //Owner vCard enhancement: Use "ME" profile if configured
133c7a57f31515107366589bd6875c3cc4af1fc806efredc        if (BluetoothPbapConfig.useProfileForOwnerVcard()) {
134c7a57f31515107366589bd6875c3cc4af1fc806efredc            String vcard = getOwnerPhoneNumberVcardFromProfile(vcardType21, filter);
135c7a57f31515107366589bd6875c3cc4af1fc806efredc            if (vcard != null && vcard.length() != 0) {
136c7a57f31515107366589bd6875c3cc4af1fc806efredc                return vcard;
137c7a57f31515107366589bd6875c3cc4af1fc806efredc            }
138c7a57f31515107366589bd6875c3cc4af1fc806efredc        }
139c7a57f31515107366589bd6875c3cc4af1fc806efredc        //End enhancement
140c7a57f31515107366589bd6875c3cc4af1fc806efredc
1413c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa        BluetoothPbapCallLogComposer composer = new BluetoothPbapCallLogComposer(mContext);
1422f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        String name = BluetoothPbapService.getLocalPhoneName();
1432f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        String number = BluetoothPbapService.getLocalPhoneNum();
1442f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        String vcard = composer.composeVCardForPhoneOwnNumber(Phone.TYPE_MOBILE, name, number,
1452f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                vcardType21);
1462f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        return vcard;
1472c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    }
1482c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
1492f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue    public final int getPhonebookSize(final int type) {
1502f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        int size;
1512f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        switch (type) {
1522f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            case BluetoothPbapObexServer.ContentType.PHONEBOOK:
1532f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                size = getContactsSize();
1542f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                break;
1552f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            default:
1562f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                size = getCallHistorySize(type);
1572f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                break;
1582c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan        }
159c7a57f31515107366589bd6875c3cc4af1fc806efredc        if (V) Log.v(TAG, "getPhonebookSize size = " + size + " type = " + type);
1602f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        return size;
1612c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    }
1622c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
1632f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue    public final int getContactsSize() {
1642b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        final Uri myUri = Contacts.CONTENT_URI;
1652f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        int size = 0;
1662f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        Cursor contactCursor = null;
1672f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        try {
168cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue            contactCursor = mResolver.query(myUri, null, CLAUSE_ONLY_VISIBLE, null, null);
1692f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            if (contactCursor != null) {
1702f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                size = contactCursor.getCount() + 1; // always has the 0.vcf
1712f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            }
172c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta        } catch (CursorWindowAllocationException e) {
173c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta            Log.e(TAG, "CursorWindowAllocationException while getting Contacts size");
1742f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        } finally {
1752f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            if (contactCursor != null) {
1762f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                contactCursor.close();
177c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                contactCursor = null;
1782f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            }
1792c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan        }
1802f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        return size;
1812c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    }
1822c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
1832f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue    public final int getCallHistorySize(final int type) {
1842b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        final Uri myUri = CallLog.Calls.CONTENT_URI;
1852f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        String selection = BluetoothPbapObexServer.createSelectionPara(type);
1862f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        int size = 0;
1872f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        Cursor callCursor = null;
1882f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        try {
1892f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            callCursor = mResolver.query(myUri, null, selection, null,
1902f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                    CallLog.Calls.DEFAULT_SORT_ORDER);
1912f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            if (callCursor != null) {
1922f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                size = callCursor.getCount();
1934446eaa935994bc91d6d308303e8d27526b4590dLixin Yue            }
194c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta        } catch (CursorWindowAllocationException e) {
195c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta            Log.e(TAG, "CursorWindowAllocationException while getting CallHistory size");
1962f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        } finally {
1972f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            if (callCursor != null) {
1982f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                callCursor.close();
199c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                callCursor = null;
2004446eaa935994bc91d6d308303e8d27526b4590dLixin Yue            }
2012f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        }
2022f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        return size;
2032f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue    }
2044446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
2052f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue    public final ArrayList<String> loadCallHistoryList(final int type) {
2062b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        final Uri myUri = CallLog.Calls.CONTENT_URI;
2072f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        String selection = BluetoothPbapObexServer.createSelectionPara(type);
2082f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        String[] projection = new String[] {
2099674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                Calls.NUMBER, Calls.CACHED_NAME, Calls.NUMBER_PRESENTATION
2102f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        };
2112f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        final int CALLS_NUMBER_COLUMN_INDEX = 0;
2122f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        final int CALLS_NAME_COLUMN_INDEX = 1;
2139674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner        final int CALLS_NUMBER_PRESENTATION_COLUMN_INDEX = 2;
2142f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue
2152f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        Cursor callCursor = null;
2162f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        ArrayList<String> list = new ArrayList<String>();
2172f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        try {
2182f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            callCursor = mResolver.query(myUri, projection, selection, null,
2192b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    CALLLOG_SORT_ORDER);
2202f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            if (callCursor != null) {
2212f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                for (callCursor.moveToFirst(); !callCursor.isAfterLast();
2222f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                        callCursor.moveToNext()) {
2232f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                    String name = callCursor.getString(CALLS_NAME_COLUMN_INDEX);
2242f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                    if (TextUtils.isEmpty(name)) {
22577ba5f6684f4dd7e4b7fc37982271da5654aec07Staffan Lindvall                        // name not found, use number instead
2269674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                        final int numberPresentation = callCursor.getInt(
2279674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                                CALLS_NUMBER_PRESENTATION_COLUMN_INDEX);
2289674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                        if (numberPresentation != Calls.PRESENTATION_ALLOWED) {
22977ba5f6684f4dd7e4b7fc37982271da5654aec07Staffan Lindvall                            name = mContext.getString(R.string.unknownNumber);
2309674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                        } else {
2319674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                            name = callCursor.getString(CALLS_NUMBER_COLUMN_INDEX);
23277ba5f6684f4dd7e4b7fc37982271da5654aec07Staffan Lindvall                        }
2332f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                    }
2342f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                    list.add(name);
2352f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                }
2362f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            }
237c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta        } catch (CursorWindowAllocationException e) {
238c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta            Log.e(TAG, "CursorWindowAllocationException while loading CallHistory");
2392f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        } finally {
2402f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            if (callCursor != null) {
2412f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                callCursor.close();
242c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                callCursor = null;
2432c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan            }
2442c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan        }
2452f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        return list;
2462c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    }
2472c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
2482b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    public final ArrayList<String> getPhonebookNameList(final int orderByWhat) {
2492f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        ArrayList<String> nameList = new ArrayList<String>();
250c7a57f31515107366589bd6875c3cc4af1fc806efredc        //Owner vCard enhancement. Use "ME" profile if configured
251c7a57f31515107366589bd6875c3cc4af1fc806efredc        String ownerName = null;
252c7a57f31515107366589bd6875c3cc4af1fc806efredc        if (BluetoothPbapConfig.useProfileForOwnerVcard()) {
253c7a57f31515107366589bd6875c3cc4af1fc806efredc            ownerName = BluetoothPbapUtils.getProfileName(mContext);
254c7a57f31515107366589bd6875c3cc4af1fc806efredc        }
255c7a57f31515107366589bd6875c3cc4af1fc806efredc        if (ownerName == null || ownerName.length()==0) {
256c7a57f31515107366589bd6875c3cc4af1fc806efredc            ownerName = BluetoothPbapService.getLocalPhoneName();
257c7a57f31515107366589bd6875c3cc4af1fc806efredc        }
258c7a57f31515107366589bd6875c3cc4af1fc806efredc        nameList.add(ownerName);
259c7a57f31515107366589bd6875c3cc4af1fc806efredc        //End enhancement
2604446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
2612b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        final Uri myUri = Contacts.CONTENT_URI;
2622b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        Cursor contactCursor = null;
2632f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        try {
2642b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_INDEXED) {
2650dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                if (V) Log.v(TAG, "getPhonebookNameList, order by index");
266cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue                contactCursor = mResolver.query(myUri, CONTACTS_PROJECTION, CLAUSE_ONLY_VISIBLE,
267cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue                        null, Contacts._ID);
2682b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            } else if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL) {
2690dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                if (V) Log.v(TAG, "getPhonebookNameList, order by alpha");
270cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue                contactCursor = mResolver.query(myUri, CONTACTS_PROJECTION, CLAUSE_ONLY_VISIBLE,
271cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue                        null, Contacts.DISPLAY_NAME);
2722b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            }
2732b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            if (contactCursor != null) {
2742b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                for (contactCursor.moveToFirst(); !contactCursor.isAfterLast(); contactCursor
2752f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                        .moveToNext()) {
2762b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    String name = contactCursor.getString(CONTACTS_NAME_COLUMN_INDEX);
277130969d18eadbd94361fe95bf16b8131cdea6168Hemant Gupta                    long id = contactCursor.getLong(CONTACTS_ID_COLUMN_INDEX);
2782f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                    if (TextUtils.isEmpty(name)) {
2792f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                        name = mContext.getString(android.R.string.unknownName);
2802f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                    }
281130969d18eadbd94361fe95bf16b8131cdea6168Hemant Gupta                    nameList.add(name + "," + id);
2822f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                }
2832f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            }
284c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta        } catch (CursorWindowAllocationException e) {
285c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta            Log.e(TAG, "CursorWindowAllocationException while getting Phonebook name list");
2862f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        } finally {
2872b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            if (contactCursor != null) {
2882b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                contactCursor.close();
289c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                contactCursor = null;
2902f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            }
2912f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        }
2922f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        return nameList;
2934446eaa935994bc91d6d308303e8d27526b4590dLixin Yue    }
2944446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
2950dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao    public final ArrayList<String> getContactNamesByNumber(final String phoneNumber) {
2960dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao        ArrayList<String> nameList = new ArrayList<String>();
2970dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao
2980dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao        Cursor contactCursor = null;
2994bba23a751f042596561eab0e677135d5267bcdfStaffan Lindvall        Uri uri = null;
3004bba23a751f042596561eab0e677135d5267bcdfStaffan Lindvall
3014bba23a751f042596561eab0e677135d5267bcdfStaffan Lindvall        if (phoneNumber != null && phoneNumber.length() == 0) {
3024bba23a751f042596561eab0e677135d5267bcdfStaffan Lindvall            uri = Contacts.CONTENT_URI;
3034bba23a751f042596561eab0e677135d5267bcdfStaffan Lindvall        } else {
3044bba23a751f042596561eab0e677135d5267bcdfStaffan Lindvall            uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
3050dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                Uri.encode(phoneNumber));
3064bba23a751f042596561eab0e677135d5267bcdfStaffan Lindvall        }
3074446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
3082f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        try {
3090dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao            contactCursor = mResolver.query(uri, CONTACTS_PROJECTION, CLAUSE_ONLY_VISIBLE,
3100dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                        null, Contacts._ID);
3110dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao
3120dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao            if (contactCursor != null) {
3130dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                for (contactCursor.moveToFirst(); !contactCursor.isAfterLast(); contactCursor
3142f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                        .moveToNext()) {
3150dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                    String name = contactCursor.getString(CONTACTS_NAME_COLUMN_INDEX);
3160dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                    long id = contactCursor.getLong(CONTACTS_ID_COLUMN_INDEX);
3170dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                    if (TextUtils.isEmpty(name)) {
3180dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                        name = mContext.getString(android.R.string.unknownName);
3192f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                    }
3200dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                    if (V) Log.v(TAG, "got name " + name + " by number " + phoneNumber + " @" + id);
321130969d18eadbd94361fe95bf16b8131cdea6168Hemant Gupta                    nameList.add(name + "," + id);
3222f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                }
3232f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            }
324c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta        } catch (CursorWindowAllocationException e) {
325c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta            Log.e(TAG, "CursorWindowAllocationException while getting contact names");
3262f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        } finally {
3270dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao            if (contactCursor != null) {
3280dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao                contactCursor.close();
329c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                contactCursor = null;
3302f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            }
3312c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan        }
3320dcd2262d853c2011e11617a8efba6758370c41fLiejun Tao        return nameList;
3332c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    }
3342c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
3350b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue    public final int composeAndSendCallLogVcards(final int type, Operation op,
3362f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            final int startPoint, final int endPoint, final boolean vcardType21) {
33759256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        if (startPoint < 1 || startPoint > endPoint) {
33859256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            Log.e(TAG, "internal error: startPoint or endPoint is not correct.");
33959256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
34059256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        }
3412f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        String typeSelection = BluetoothPbapObexServer.createSelectionPara(type);
34259256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh
3432b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        final Uri myUri = CallLog.Calls.CONTENT_URI;
34459256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        final String[] CALLLOG_PROJECTION = new String[] {
34559256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            CallLog.Calls._ID, // 0
34659256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        };
34759256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        final int ID_COLUMN_INDEX = 0;
34859256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh
34959256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        Cursor callsCursor = null;
35059256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        long startPointId = 0;
35159256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        long endPointId = 0;
35259256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        try {
35359256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            // Need test to see if order by _ID is ok here, or by date?
35459256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            callsCursor = mResolver.query(myUri, CALLLOG_PROJECTION, typeSelection, null,
3552b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    CALLLOG_SORT_ORDER);
35659256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            if (callsCursor != null) {
35759256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                callsCursor.moveToPosition(startPoint - 1);
35859256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                startPointId = callsCursor.getLong(ID_COLUMN_INDEX);
35959256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                if (V) Log.v(TAG, "Call Log query startPointId = " + startPointId);
36059256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                if (startPoint == endPoint) {
36159256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                    endPointId = startPointId;
36259256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                } else {
36359256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                    callsCursor.moveToPosition(endPoint - 1);
36459256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                    endPointId = callsCursor.getLong(ID_COLUMN_INDEX);
36559256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                }
36659256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                if (V) Log.v(TAG, "Call log query endPointId = " + endPointId);
36759256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            }
368c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta        } catch (CursorWindowAllocationException e) {
369c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta            Log.e(TAG, "CursorWindowAllocationException while composing calllog vcards");
37059256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        } finally {
37159256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            if (callsCursor != null) {
37259256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                callsCursor.close();
373c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                callsCursor = null;
37459256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            }
37559256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        }
37659256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh
3772f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        String recordSelection;
3782f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        if (startPoint == endPoint) {
37959256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            recordSelection = Calls._ID + "=" + startPointId;
3802f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        } else {
3812b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            // The query to call table is by "_id DESC" order, so change
3822b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            // correspondingly.
3832b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            recordSelection = Calls._ID + ">=" + endPointId + " AND " + Calls._ID + "<="
3842b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    + startPointId;
3854446eaa935994bc91d6d308303e8d27526b4590dLixin Yue        }
3864446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
3872f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        String selection;
3882f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        if (typeSelection == null) {
3892f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            selection = recordSelection;
3902f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        } else {
3912f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            selection = "(" + typeSelection + ") AND (" + recordSelection + ")";
3924446eaa935994bc91d6d308303e8d27526b4590dLixin Yue        }
3934446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
39459256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        if (V) Log.v(TAG, "Call log query selection is: " + selection);
3954446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
3962f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        return composeAndSendVCards(op, selection, vcardType21, null, false);
3974446eaa935994bc91d6d308303e8d27526b4590dLixin Yue    }
3984446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
3990b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue    public final int composeAndSendPhonebookVcards(Operation op, final int startPoint,
4002f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            final int endPoint, final boolean vcardType21, String ownerVCard) {
40159256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        if (startPoint < 1 || startPoint > endPoint) {
40259256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            Log.e(TAG, "internal error: startPoint or endPoint is not correct.");
40359256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
40459256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        }
4052b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        final Uri myUri = Contacts.CONTENT_URI;
40659256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh
40759256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        Cursor contactCursor = null;
40859256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        long startPointId = 0;
40959256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        long endPointId = 0;
41059256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        try {
411cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue            contactCursor = mResolver.query(myUri, CONTACTS_PROJECTION, CLAUSE_ONLY_VISIBLE, null,
4122b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    Contacts._ID);
41359256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            if (contactCursor != null) {
41459256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                contactCursor.moveToPosition(startPoint - 1);
4152b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                startPointId = contactCursor.getLong(CONTACTS_ID_COLUMN_INDEX);
41659256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                if (V) Log.v(TAG, "Query startPointId = " + startPointId);
41759256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                if (startPoint == endPoint) {
41859256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                    endPointId = startPointId;
41959256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                } else {
42059256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                    contactCursor.moveToPosition(endPoint - 1);
4212b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    endPointId = contactCursor.getLong(CONTACTS_ID_COLUMN_INDEX);
42259256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                }
42359256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                if (V) Log.v(TAG, "Query endPointId = " + endPointId);
42459256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            }
425c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta        } catch (CursorWindowAllocationException e) {
426c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta            Log.e(TAG, "CursorWindowAllocationException while composing phonebook vcards");
42759256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        } finally {
42859256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            if (contactCursor != null) {
42959256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                contactCursor.close();
430c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                contactCursor = null;
43159256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh            }
43259256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh        }
43359256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh
4342b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        final String selection;
4352f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        if (startPoint == endPoint) {
436cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue            selection = Contacts._ID + "=" + startPointId + " AND " + CLAUSE_ONLY_VISIBLE;
4372f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        } else {
4382b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            selection = Contacts._ID + ">=" + startPointId + " AND " + Contacts._ID + "<="
439cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue                    + endPointId + " AND " + CLAUSE_ONLY_VISIBLE;
4404446eaa935994bc91d6d308303e8d27526b4590dLixin Yue        }
4414446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
4422f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        if (V) Log.v(TAG, "Query selection is: " + selection);
4434446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
4442f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        return composeAndSendVCards(op, selection, vcardType21, ownerVCard, true);
4454446eaa935994bc91d6d308303e8d27526b4590dLixin Yue    }
4464446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
4470b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue    public final int composeAndSendPhonebookOneVcard(Operation op, final int offset,
4482b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            final boolean vcardType21, String ownerVCard, int orderByWhat) {
4492b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        if (offset < 1) {
4502b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            Log.e(TAG, "Internal error: offset is not correct.");
4512b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
4522b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        }
4532b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        final Uri myUri = Contacts.CONTENT_URI;
4542b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        Cursor contactCursor = null;
4552b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        String selection = null;
4562b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        long contactId = 0;
4572b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_INDEXED) {
4582b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            try {
459cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue                contactCursor = mResolver.query(myUri, CONTACTS_PROJECTION, CLAUSE_ONLY_VISIBLE,
460cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue                        null, Contacts._ID);
4612b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                if (contactCursor != null) {
4622b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    contactCursor.moveToPosition(offset - 1);
4632b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    contactId = contactCursor.getLong(CONTACTS_ID_COLUMN_INDEX);
4642b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    if (V) Log.v(TAG, "Query startPointId = " + contactId);
4652b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                }
466c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta            } catch (CursorWindowAllocationException e) {
467c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                Log.e(TAG, "CursorWindowAllocationException while composing phonebook one vcard order by index");
4682b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            } finally {
4692b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                if (contactCursor != null) {
4702b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    contactCursor.close();
471c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                    contactCursor = null;
4722b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                }
4732b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            }
4742b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        } else if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL) {
4752b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            try {
476cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue                contactCursor = mResolver.query(myUri, CONTACTS_PROJECTION, CLAUSE_ONLY_VISIBLE,
477cd5ed0c7d04119e508fbddfd9656ef8559e3e524Lixin Yue                        null, Contacts.DISPLAY_NAME);
4782b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                if (contactCursor != null) {
4792b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    contactCursor.moveToPosition(offset - 1);
4802b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    contactId = contactCursor.getLong(CONTACTS_ID_COLUMN_INDEX);
4812b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    if (V) Log.v(TAG, "Query startPointId = " + contactId);
4822b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                }
483c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta            } catch (CursorWindowAllocationException e) {
484c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                Log.e(TAG, "CursorWindowAllocationException while composing phonebook one vcard order by alphabetical");
4852b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            } finally {
4862b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                if (contactCursor != null) {
4872b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                    contactCursor.close();
488c592e5a6de0011cd60f23ac18a7bd56d8eeb5dd1Hemant Gupta                    contactCursor = null;
4892b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh                }
4902b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            }
4912b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        } else {
4922b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            Log.e(TAG, "Parameter orderByWhat is not supported!");
4932b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
4942b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        }
4952b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        selection = Contacts._ID + "=" + contactId;
4962b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh
4972b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        if (V) Log.v(TAG, "Query selection is: " + selection);
4982b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh
4992b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh        return composeAndSendVCards(op, selection, vcardType21, ownerVCard, true);
5002b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh    }
5012b36e1731eb5ed784abc1a374eb69d8523123df1Jaikumar Ganesh
5020b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue    public final int composeAndSendVCards(Operation op, final String selection,
5032f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            final boolean vcardType21, String ownerVCard, boolean isContacts) {
5042f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        long timestamp = 0;
5052f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        if (V) timestamp = System.currentTimeMillis();
5064446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
507198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa        if (isContacts) {
508198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa            VCardComposer composer = null;
5093c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa            HandlerForStringBuffer buffer = null;
510198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa            try {
511198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                // Currently only support Generic Vcard 2.1 and 3.0
512198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                int vcardType;
513198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                if (vcardType21) {
514e05d3a710c592db386b55a265a1e657b0467e49fDaisuke Miyakawa                    vcardType = VCardConfig.VCARD_TYPE_V21_GENERIC;
515198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                } else {
516e05d3a710c592db386b55a265a1e657b0467e49fDaisuke Miyakawa                    vcardType = VCardConfig.VCARD_TYPE_V30_GENERIC;
517198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                }
5184a53a55dc10d3a26c94e5844f7d4a2565a67142cfredc
5194a53a55dc10d3a26c94e5844f7d4a2565a67142cfredc                if (!BluetoothPbapConfig.includePhotosInVcard()) {
5204a53a55dc10d3a26c94e5844f7d4a2565a67142cfredc                    vcardType |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT;
5214a53a55dc10d3a26c94e5844f7d4a2565a67142cfredc                }
5224446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
523c7a57f31515107366589bd6875c3cc4af1fc806efredc                //Enhancement: customize Vcard based on preferences/settings and input from caller
524c7a57f31515107366589bd6875c3cc4af1fc806efredc                composer = BluetoothPbapUtils.createFilteredVCardComposer(mContext, vcardType,null);
525c7a57f31515107366589bd6875c3cc4af1fc806efredc                //End enhancement
526c7a57f31515107366589bd6875c3cc4af1fc806efredc
527d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                // BT does want PAUSE/WAIT conversion while it doesn't want the other formatting
528d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                // done by vCard library by default.
529d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                composer.setPhoneNumberTranslationCallback(
530d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                        new VCardPhoneNumberTranslationCallback() {
531d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                            public String onValueReceived(
532d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                                    String rawValue, int type, String label, boolean isPrimary) {
533d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                                // 'p' and 'w' are the standard characters for pause and wait
534d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                                // (see RFC 3601)
535d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                                // so use those when exporting phone numbers via vCard.
536d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                                String numberWithControlSequence = rawValue
537d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                                        .replace(PhoneNumberUtils.PAUSE, 'p')
538d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                                        .replace(PhoneNumberUtils.WAIT, 'w');
539d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                                return numberWithControlSequence;
540d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                            }
541d956b40b2f59599447ae0fa0762e055c0c0ce1a3Daisuke Miyakawa                        });
5423c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                buffer = new HandlerForStringBuffer(op, ownerVCard);
5433c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                if (!composer.init(Contacts.CONTENT_URI, selection, null, Contacts._ID) ||
5443c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                        !buffer.onInit(mContext)) {
5452f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                    return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
5464446eaa935994bc91d6d308303e8d27526b4590dLixin Yue                }
547198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa
548198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                while (!composer.isAfterLast()) {
5490b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue                    if (BluetoothPbapObexServer.sIsAborted) {
5500b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue                        ((ServerOperation)op).isAborted = true;
5510b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue                        BluetoothPbapObexServer.sIsAborted = false;
5520b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue                        break;
5530b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue                    }
5543c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                    String vcard = composer.createOneEntry();
5553c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                    if (vcard == null) {
556198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                        Log.e(TAG, "Failed to read a contact. Error reason: "
557198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                                + composer.getErrorReason());
558198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                        return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
559198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                    }
560c7a57f31515107366589bd6875c3cc4af1fc806efredc                    if (V) {
561c7a57f31515107366589bd6875c3cc4af1fc806efredc                        Log.v(TAG, "Vcard Entry:");
562c7a57f31515107366589bd6875c3cc4af1fc806efredc                        Log.v(TAG,vcard);
563c7a57f31515107366589bd6875c3cc4af1fc806efredc                    }
564c7a57f31515107366589bd6875c3cc4af1fc806efredc
5653c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                    if (!buffer.onEntryCreated(vcard)) {
5663c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                        // onEntryCreate() already emits error.
5673c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                        return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
5683c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                    }
569198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                }
570198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa            } finally {
571198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                if (composer != null) {
572198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                    composer.terminate();
573198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                }
5743c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                if (buffer != null) {
5753c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                    buffer.onTerminate();
5763c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                }
5774446eaa935994bc91d6d308303e8d27526b4590dLixin Yue            }
578198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa        } else { // CallLog
579198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa            BluetoothPbapCallLogComposer composer = null;
5803c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa            HandlerForStringBuffer buffer = null;
581198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa            try {
5823c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa
5833c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                composer = new BluetoothPbapCallLogComposer(mContext);
5843c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                buffer = new HandlerForStringBuffer(op, ownerVCard);
5854492b2c66cf3b26fd988f3b7f1f5df6cc9ed49f2Jaikumar Ganesh                if (!composer.init(CallLog.Calls.CONTENT_URI, selection, null,
5863c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                                   CALLLOG_SORT_ORDER) ||
5873c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                                   !buffer.onInit(mContext)) {
588198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                    return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
589198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                }
590198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa
591198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                while (!composer.isAfterLast()) {
5920b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue                    if (BluetoothPbapObexServer.sIsAborted) {
5930b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue                        ((ServerOperation)op).isAborted = true;
5940b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue                        BluetoothPbapObexServer.sIsAborted = false;
5950b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue                        break;
5960b1b0069658326e8c12dc0f887e4319c5227feb5Lixin Yue                    }
59773adcc0f5b6051ef514a3f16a2e28eabee2b367eConley Owens                    String vcard = composer.createOneEntry(vcardType21);
5983c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                    if (vcard == null) {
599198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                        Log.e(TAG, "Failed to read a contact. Error reason: "
600198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                                + composer.getErrorReason());
601198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                        return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
602198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                    }
603c7a57f31515107366589bd6875c3cc4af1fc806efredc                    if (V) {
604c7a57f31515107366589bd6875c3cc4af1fc806efredc                        Log.v(TAG, "Vcard Entry:");
605c7a57f31515107366589bd6875c3cc4af1fc806efredc                        Log.v(TAG,vcard);
606c7a57f31515107366589bd6875c3cc4af1fc806efredc                    }
607c7a57f31515107366589bd6875c3cc4af1fc806efredc
6083c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                    buffer.onEntryCreated(vcard);
609198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                }
610198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa            } finally {
611198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                if (composer != null) {
612198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                    composer.terminate();
613198e5d109571b27b7c45c30ed3ea42febcb99201Daisuke Miyakawa                }
6143c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                if (buffer != null) {
6153c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                    buffer.onTerminate();
6163c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa                }
6174446eaa935994bc91d6d308303e8d27526b4590dLixin Yue            }
6184446eaa935994bc91d6d308303e8d27526b4590dLixin Yue        }
6194446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
6202f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        if (V) Log.v(TAG, "Total vcard composing and sending out takes "
6212f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                    + (System.currentTimeMillis() - timestamp) + " ms");
6222f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue
6232f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        return ResponseCodes.OBEX_HTTP_OK;
6244446eaa935994bc91d6d308303e8d27526b4590dLixin Yue    }
6254446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
6262f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue    /**
627ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita     * Handler to emit vCards to PCE.
6282f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue     */
6293c4d2c77c2fffe675fbe89ba58856686b6873d2fDaisuke Miyakawa    public class HandlerForStringBuffer {
6302f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        private Operation operation;
6314446eaa935994bc91d6d308303e8d27526b4590dLixin Yue
6322f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        private OutputStream outputStream;
6332f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue
6342f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        private String phoneOwnVCard = null;
6352f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue
6362f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        public HandlerForStringBuffer(Operation op, String ownerVCard) {
6372f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            operation = op;
6382f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            if (ownerVCard != null) {
6392f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                phoneOwnVCard = ownerVCard;
6402f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                if (V) Log.v(TAG, "phone own number vcard:");
6412f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                if (V) Log.v(TAG, phoneOwnVCard);
6422c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan            }
6432c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan        }
6442c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
645ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita        private boolean write(String vCard) {
646ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita            try {
647ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita                if (vCard != null) {
648ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita                    outputStream.write(vCard.getBytes());
649ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita                    return true;
650ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita                }
651ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita            } catch (IOException e) {
652ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita                Log.e(TAG, "write outputstrem failed" + e.toString());
653ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita            }
654ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita            return false;
655ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita        }
656ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita
6572f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        public boolean onInit(Context context) {
6582f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            try {
6592f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                outputStream = operation.openOutputStream();
6602f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                if (phoneOwnVCard != null) {
661ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita                    return write(phoneOwnVCard);
6622c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan                }
663ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita                return true;
6642f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            } catch (IOException e) {
6652f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                Log.e(TAG, "open outputstrem failed" + e.toString());
6662c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan            }
667ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita            return false;
6682c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan        }
6692c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
6702f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        public boolean onEntryCreated(String vcard) {
671ce8d51a3a43d113a4a6bad30d595c2a81d0f623cYoshiharu Kurita            return write(vcard);
6722c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan        }
6732c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan
6742f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue        public void onTerminate() {
6752f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue            if (!BluetoothPbapObexServer.closeStream(outputStream, operation)) {
6762f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                if (V) Log.v(TAG, "CloseStream failed!");
6772c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan            } else {
6782f8fe66f45bac2bc61395bd4f8de553f4c2b7c30Lixin Yue                if (V) Log.v(TAG, "CloseStream ok!");
6792c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan            }
6802c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan        }
6812c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan    }
6822c282d5898ac0916470ebfa9ff26ba784cf4bb24Jackson Fan}
683