Loading android/app/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java 0 → 100644 +322 −0 Original line number Diff line number Diff line /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.bluetooth.pbap; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteException; import android.net.Uri; import android.pim.vcard.VCardBuilder; import android.pim.vcard.VCardConfig; import android.pim.vcard.VCardConstants; import android.pim.vcard.VCardUtils; import android.pim.vcard.VCardComposer.OneEntryHandler; import android.provider.CallLog; import android.provider.CallLog.Calls; import android.text.TextUtils; import android.text.format.Time; import android.util.Log; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * VCard composer especially for Call Log used in Bluetooth. */ public class BluetoothPbapCallLogComposer { private static final String TAG = "CallLogComposer"; private static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO = "Failed to get database information"; private static final String FAILURE_REASON_NO_ENTRY = "There's no exportable in the database"; private static final String FAILURE_REASON_NOT_INITIALIZED = "The vCard composer object is not correctly initialized"; /** Should be visible only from developers... (no need to translate, hopefully) */ private static final String FAILURE_REASON_UNSUPPORTED_URI = "The Uri vCard composer received is not supported by the composer."; private static final String NO_ERROR = "No error"; /** The projection to use when querying the call log table */ private static final String[] sCallLogProjection = new String[] { Calls.NUMBER, Calls.DATE, Calls.TYPE, Calls.CACHED_NAME, Calls.CACHED_NUMBER_TYPE, Calls.CACHED_NUMBER_LABEL }; private static final int NUMBER_COLUMN_INDEX = 0; private static final int DATE_COLUMN_INDEX = 1; private static final int CALL_TYPE_COLUMN_INDEX = 2; private static final int CALLER_NAME_COLUMN_INDEX = 3; private static final int CALLER_NUMBERTYPE_COLUMN_INDEX = 4; private static final int CALLER_NUMBERLABEL_COLUMN_INDEX = 5; // Property for call log entry private static final String VCARD_PROPERTY_X_TIMESTAMP = "X-IRMC-CALL-DATETIME"; private static final String VCARD_PROPERTY_CALLTYPE_INCOMING = "INCOMING"; private static final String VCARD_PROPERTY_CALLTYPE_OUTGOING = "OUTGOING"; private static final String VCARD_PROPERTY_CALLTYPE_MISSED = "MISSED"; private static final String FLAG_TIMEZONE_UTC = "Z"; private final Context mContext; private ContentResolver mContentResolver; private Cursor mCursor; private final boolean mCareHandlerErrors; private boolean mTerminateIsCalled; private final List<OneEntryHandler> mHandlerList; private String mErrorReason = NO_ERROR; public BluetoothPbapCallLogComposer(final Context context, boolean careHandlerErrors) { mContext = context; mContentResolver = context.getContentResolver(); mCareHandlerErrors = careHandlerErrors; mHandlerList = new ArrayList<OneEntryHandler>(); } public boolean init(final Uri contentUri, final String selection, final String[] selectionArgs, final String sortOrder) { final String[] projection; if (CallLog.Calls.CONTENT_URI.equals(contentUri)) { projection = sCallLogProjection; } else { mErrorReason = FAILURE_REASON_UNSUPPORTED_URI; return false; } mCursor = mContentResolver.query( contentUri, projection, selection, selectionArgs, sortOrder); if (mCursor == null) { mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO; return false; } if (mCareHandlerErrors) { List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>( mHandlerList.size()); for (OneEntryHandler handler : mHandlerList) { if (!handler.onInit(mContext)) { for (OneEntryHandler finished : finishedList) { finished.onTerminate(); } return false; } } } else { // Just ignore the false returned from onInit(). for (OneEntryHandler handler : mHandlerList) { handler.onInit(mContext); } } if (mCursor.getCount() == 0 || !mCursor.moveToFirst()) { try { mCursor.close(); } catch (SQLiteException e) { Log.e(TAG, "SQLiteException on Cursor#close(): " + e.getMessage()); } finally { mErrorReason = FAILURE_REASON_NO_ENTRY; mCursor = null; } return false; } return true; } public void addHandler(OneEntryHandler handler) { if (handler != null) { mHandlerList.add(handler); } } public boolean createOneEntry() { if (mCursor == null || mCursor.isAfterLast()) { mErrorReason = FAILURE_REASON_NOT_INITIALIZED; return false; } final String vcard; try { vcard = createOneCallLogEntryInternal(); } catch (OutOfMemoryError error) { Log.e(TAG, "OutOfMemoryError occured. Ignore the entry"); System.gc(); return true; } if (mCareHandlerErrors) { List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>( mHandlerList.size()); for (OneEntryHandler handler : mHandlerList) { if (!handler.onEntryCreated(vcard)) { return false; } } } else { for (OneEntryHandler handler : mHandlerList) { handler.onEntryCreated(vcard); } } return true; } private String createOneCallLogEntryInternal() { final VCardBuilder builder = new VCardBuilder(VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8); String name = mCursor.getString(CALLER_NAME_COLUMN_INDEX); if (TextUtils.isEmpty(name)) { name = mCursor.getString(NUMBER_COLUMN_INDEX); } final boolean needCharset = !(VCardUtils.containsOnlyPrintableAscii(name)); builder.appendLine(VCardConstants.PROPERTY_FN, name, needCharset, false); builder.appendLine(VCardConstants.PROPERTY_N, name, needCharset, false); final String number = mCursor.getString(NUMBER_COLUMN_INDEX); final int type = mCursor.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX); String label = mCursor.getString(CALLER_NUMBERLABEL_COLUMN_INDEX); if (TextUtils.isEmpty(label)) { label = Integer.toString(type); } builder.appendTelLine(type, label, number, false); tryAppendCallHistoryTimeStampField(builder); return builder.toString(); } /** * This static function is to compose vCard for phone own number */ public String composeVCardForPhoneOwnNumber(int phonetype, String phoneName, String phoneNumber, boolean vcardVer21) { final int vcardType = (vcardVer21 ? VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8 : VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8); final VCardBuilder builder = new VCardBuilder(vcardType); boolean needCharset = false; if (!(VCardUtils.containsOnlyPrintableAscii(phoneName))) { needCharset = true; } builder.appendLine(VCardConstants.PROPERTY_FN, phoneName, needCharset, false); builder.appendLine(VCardConstants.PROPERTY_N, phoneName, needCharset, false); if (!TextUtils.isEmpty(phoneNumber)) { String label = Integer.toString(phonetype); builder.appendTelLine(phonetype, label, phoneNumber, false); } return builder.toString(); } /** * Format according to RFC 2445 DATETIME type. * The format is: ("%Y%m%dT%H%M%SZ"). */ private final String toRfc2455Format(final long millSecs) { Time startDate = new Time(); startDate.set(millSecs); String date = startDate.format2445(); return date + FLAG_TIMEZONE_UTC; } /** * Try to append the property line for a call history time stamp field if possible. * Do nothing if the call log type gotton from the database is invalid. */ private void tryAppendCallHistoryTimeStampField(final VCardBuilder builder) { // Extension for call history as defined in // in the Specification for Ic Mobile Communcation - ver 1.1, // Oct 2000. This is used to send the details of the call // history - missed, incoming, outgoing along with date and time // to the requesting device (For example, transferring phone book // when connected over bluetooth) // // e.g. "X-IRMC-CALL-DATETIME;MISSED:20050320T100000Z" final int callLogType = mCursor.getInt(CALL_TYPE_COLUMN_INDEX); final String callLogTypeStr; switch (callLogType) { case Calls.INCOMING_TYPE: { callLogTypeStr = VCARD_PROPERTY_CALLTYPE_INCOMING; break; } case Calls.OUTGOING_TYPE: { callLogTypeStr = VCARD_PROPERTY_CALLTYPE_OUTGOING; break; } case Calls.MISSED_TYPE: { callLogTypeStr = VCARD_PROPERTY_CALLTYPE_MISSED; break; } default: { Log.w(TAG, "Call log type not correct."); return; } } final long dateAsLong = mCursor.getLong(DATE_COLUMN_INDEX); builder.appendLine(VCARD_PROPERTY_X_TIMESTAMP, Arrays.asList(callLogTypeStr), toRfc2455Format(dateAsLong)); } public void terminate() { for (OneEntryHandler handler : mHandlerList) { handler.onTerminate(); } if (mCursor != null) { try { mCursor.close(); } catch (SQLiteException e) { Log.e(TAG, "SQLiteException on Cursor#close(): " + e.getMessage()); } mCursor = null; } mTerminateIsCalled = true; } @Override public void finalize() { if (!mTerminateIsCalled) { terminate(); } } public int getCount() { if (mCursor == null) { return 0; } return mCursor.getCount(); } public boolean isAfterLast() { if (mCursor == null) { return false; } return mCursor.isAfterLast(); } public String getErrorReason() { return mErrorReason; } } android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java +56 −39 Original line number Diff line number Diff line Loading @@ -32,35 +32,31 @@ package com.android.bluetooth.pbap; import com.android.bluetooth.R; import android.net.Uri; import android.os.Handler; import android.text.TextUtils; import android.util.Log; import android.database.Cursor; import android.content.ContentResolver; import android.content.Context; import android.provider.CallLog; import android.provider.CallLog.Calls; import android.provider.ContactsContract.RawContacts; import android.provider.ContactsContract.PhoneLookup; import android.database.Cursor; import android.net.Uri; import android.pim.vcard.VCardComposer; import android.pim.vcard.VCardConfig; import android.pim.vcard.VCardComposer.OneEntryHandler; import android.provider.ContactsContract; import android.provider.CallLog; import android.provider.CallLog.Calls; import android.provider.ContactsContract.CommonDataKinds; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Data; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.text.TextUtils; import android.util.Log; import com.android.bluetooth.R; import javax.obex.ResponseCodes; import javax.obex.Operation; import java.io.IOException; import java.io.OutputStream; import java.io.Writer; import java.util.ArrayList; import javax.obex.Operation; import javax.obex.ResponseCodes; public class BluetoothPbapVcardManager { private static final String TAG = "BluetoothPbapVcardManager"; Loading Loading @@ -115,7 +111,7 @@ public class BluetoothPbapVcardManager { } public final String getOwnerPhoneNumberVcard(final boolean vcardType21) { VCardComposer composer = new VCardComposer(mContext); BluetoothPbapCallLogComposer composer = new BluetoothPbapCallLogComposer(mContext, false); String name = BluetoothPbapService.getLocalPhoneName(); String number = BluetoothPbapService.getLocalPhoneNum(); String vcard = composer.composeVCardForPhoneOwnNumber(Phone.TYPE_MOBILE, name, number, Loading Loading @@ -425,6 +421,7 @@ public class BluetoothPbapVcardManager { long timestamp = 0; if (V) timestamp = System.currentTimeMillis(); if (isContacts) { VCardComposer composer = null; try { // Currently only support Generic Vcard 2.1 and 3.0 Loading @@ -436,9 +433,28 @@ public class BluetoothPbapVcardManager { } composer = new VCardComposer(mContext, vcardType, true); if (!composer.init(Contacts.CONTENT_URI, selection, null, null)) { return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } while (!composer.isAfterLast()) { if (!composer.createOneEntry()) { Log.e(TAG, "Failed to read a contact. Error reason: " + composer.getErrorReason()); return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } } } finally { if (composer != null) { composer.terminate(); } } } else { // CallLog BluetoothPbapCallLogComposer composer = null; try { composer = new BluetoothPbapCallLogComposer(mContext, true); composer.addHandler(new HandlerForStringBuffer(op, ownerVCard)); final Uri contentUri = (isContacts ? Contacts.CONTENT_URI : CallLog.Calls.CONTENT_URI); if (!composer.init(contentUri, selection, null, null)) { if (!composer.init(CallLog.Calls.CONTENT_URI, selection, null, null)) { return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } Loading @@ -454,6 +470,7 @@ public class BluetoothPbapVcardManager { composer.terminate(); } } } if (V) Log.v(TAG, "Total vcard composing and sending out takes " + (System.currentTimeMillis() - timestamp) + " ms"); Loading Loading
android/app/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java 0 → 100644 +322 −0 Original line number Diff line number Diff line /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.bluetooth.pbap; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteException; import android.net.Uri; import android.pim.vcard.VCardBuilder; import android.pim.vcard.VCardConfig; import android.pim.vcard.VCardConstants; import android.pim.vcard.VCardUtils; import android.pim.vcard.VCardComposer.OneEntryHandler; import android.provider.CallLog; import android.provider.CallLog.Calls; import android.text.TextUtils; import android.text.format.Time; import android.util.Log; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * VCard composer especially for Call Log used in Bluetooth. */ public class BluetoothPbapCallLogComposer { private static final String TAG = "CallLogComposer"; private static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO = "Failed to get database information"; private static final String FAILURE_REASON_NO_ENTRY = "There's no exportable in the database"; private static final String FAILURE_REASON_NOT_INITIALIZED = "The vCard composer object is not correctly initialized"; /** Should be visible only from developers... (no need to translate, hopefully) */ private static final String FAILURE_REASON_UNSUPPORTED_URI = "The Uri vCard composer received is not supported by the composer."; private static final String NO_ERROR = "No error"; /** The projection to use when querying the call log table */ private static final String[] sCallLogProjection = new String[] { Calls.NUMBER, Calls.DATE, Calls.TYPE, Calls.CACHED_NAME, Calls.CACHED_NUMBER_TYPE, Calls.CACHED_NUMBER_LABEL }; private static final int NUMBER_COLUMN_INDEX = 0; private static final int DATE_COLUMN_INDEX = 1; private static final int CALL_TYPE_COLUMN_INDEX = 2; private static final int CALLER_NAME_COLUMN_INDEX = 3; private static final int CALLER_NUMBERTYPE_COLUMN_INDEX = 4; private static final int CALLER_NUMBERLABEL_COLUMN_INDEX = 5; // Property for call log entry private static final String VCARD_PROPERTY_X_TIMESTAMP = "X-IRMC-CALL-DATETIME"; private static final String VCARD_PROPERTY_CALLTYPE_INCOMING = "INCOMING"; private static final String VCARD_PROPERTY_CALLTYPE_OUTGOING = "OUTGOING"; private static final String VCARD_PROPERTY_CALLTYPE_MISSED = "MISSED"; private static final String FLAG_TIMEZONE_UTC = "Z"; private final Context mContext; private ContentResolver mContentResolver; private Cursor mCursor; private final boolean mCareHandlerErrors; private boolean mTerminateIsCalled; private final List<OneEntryHandler> mHandlerList; private String mErrorReason = NO_ERROR; public BluetoothPbapCallLogComposer(final Context context, boolean careHandlerErrors) { mContext = context; mContentResolver = context.getContentResolver(); mCareHandlerErrors = careHandlerErrors; mHandlerList = new ArrayList<OneEntryHandler>(); } public boolean init(final Uri contentUri, final String selection, final String[] selectionArgs, final String sortOrder) { final String[] projection; if (CallLog.Calls.CONTENT_URI.equals(contentUri)) { projection = sCallLogProjection; } else { mErrorReason = FAILURE_REASON_UNSUPPORTED_URI; return false; } mCursor = mContentResolver.query( contentUri, projection, selection, selectionArgs, sortOrder); if (mCursor == null) { mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO; return false; } if (mCareHandlerErrors) { List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>( mHandlerList.size()); for (OneEntryHandler handler : mHandlerList) { if (!handler.onInit(mContext)) { for (OneEntryHandler finished : finishedList) { finished.onTerminate(); } return false; } } } else { // Just ignore the false returned from onInit(). for (OneEntryHandler handler : mHandlerList) { handler.onInit(mContext); } } if (mCursor.getCount() == 0 || !mCursor.moveToFirst()) { try { mCursor.close(); } catch (SQLiteException e) { Log.e(TAG, "SQLiteException on Cursor#close(): " + e.getMessage()); } finally { mErrorReason = FAILURE_REASON_NO_ENTRY; mCursor = null; } return false; } return true; } public void addHandler(OneEntryHandler handler) { if (handler != null) { mHandlerList.add(handler); } } public boolean createOneEntry() { if (mCursor == null || mCursor.isAfterLast()) { mErrorReason = FAILURE_REASON_NOT_INITIALIZED; return false; } final String vcard; try { vcard = createOneCallLogEntryInternal(); } catch (OutOfMemoryError error) { Log.e(TAG, "OutOfMemoryError occured. Ignore the entry"); System.gc(); return true; } if (mCareHandlerErrors) { List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>( mHandlerList.size()); for (OneEntryHandler handler : mHandlerList) { if (!handler.onEntryCreated(vcard)) { return false; } } } else { for (OneEntryHandler handler : mHandlerList) { handler.onEntryCreated(vcard); } } return true; } private String createOneCallLogEntryInternal() { final VCardBuilder builder = new VCardBuilder(VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8); String name = mCursor.getString(CALLER_NAME_COLUMN_INDEX); if (TextUtils.isEmpty(name)) { name = mCursor.getString(NUMBER_COLUMN_INDEX); } final boolean needCharset = !(VCardUtils.containsOnlyPrintableAscii(name)); builder.appendLine(VCardConstants.PROPERTY_FN, name, needCharset, false); builder.appendLine(VCardConstants.PROPERTY_N, name, needCharset, false); final String number = mCursor.getString(NUMBER_COLUMN_INDEX); final int type = mCursor.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX); String label = mCursor.getString(CALLER_NUMBERLABEL_COLUMN_INDEX); if (TextUtils.isEmpty(label)) { label = Integer.toString(type); } builder.appendTelLine(type, label, number, false); tryAppendCallHistoryTimeStampField(builder); return builder.toString(); } /** * This static function is to compose vCard for phone own number */ public String composeVCardForPhoneOwnNumber(int phonetype, String phoneName, String phoneNumber, boolean vcardVer21) { final int vcardType = (vcardVer21 ? VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8 : VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8); final VCardBuilder builder = new VCardBuilder(vcardType); boolean needCharset = false; if (!(VCardUtils.containsOnlyPrintableAscii(phoneName))) { needCharset = true; } builder.appendLine(VCardConstants.PROPERTY_FN, phoneName, needCharset, false); builder.appendLine(VCardConstants.PROPERTY_N, phoneName, needCharset, false); if (!TextUtils.isEmpty(phoneNumber)) { String label = Integer.toString(phonetype); builder.appendTelLine(phonetype, label, phoneNumber, false); } return builder.toString(); } /** * Format according to RFC 2445 DATETIME type. * The format is: ("%Y%m%dT%H%M%SZ"). */ private final String toRfc2455Format(final long millSecs) { Time startDate = new Time(); startDate.set(millSecs); String date = startDate.format2445(); return date + FLAG_TIMEZONE_UTC; } /** * Try to append the property line for a call history time stamp field if possible. * Do nothing if the call log type gotton from the database is invalid. */ private void tryAppendCallHistoryTimeStampField(final VCardBuilder builder) { // Extension for call history as defined in // in the Specification for Ic Mobile Communcation - ver 1.1, // Oct 2000. This is used to send the details of the call // history - missed, incoming, outgoing along with date and time // to the requesting device (For example, transferring phone book // when connected over bluetooth) // // e.g. "X-IRMC-CALL-DATETIME;MISSED:20050320T100000Z" final int callLogType = mCursor.getInt(CALL_TYPE_COLUMN_INDEX); final String callLogTypeStr; switch (callLogType) { case Calls.INCOMING_TYPE: { callLogTypeStr = VCARD_PROPERTY_CALLTYPE_INCOMING; break; } case Calls.OUTGOING_TYPE: { callLogTypeStr = VCARD_PROPERTY_CALLTYPE_OUTGOING; break; } case Calls.MISSED_TYPE: { callLogTypeStr = VCARD_PROPERTY_CALLTYPE_MISSED; break; } default: { Log.w(TAG, "Call log type not correct."); return; } } final long dateAsLong = mCursor.getLong(DATE_COLUMN_INDEX); builder.appendLine(VCARD_PROPERTY_X_TIMESTAMP, Arrays.asList(callLogTypeStr), toRfc2455Format(dateAsLong)); } public void terminate() { for (OneEntryHandler handler : mHandlerList) { handler.onTerminate(); } if (mCursor != null) { try { mCursor.close(); } catch (SQLiteException e) { Log.e(TAG, "SQLiteException on Cursor#close(): " + e.getMessage()); } mCursor = null; } mTerminateIsCalled = true; } @Override public void finalize() { if (!mTerminateIsCalled) { terminate(); } } public int getCount() { if (mCursor == null) { return 0; } return mCursor.getCount(); } public boolean isAfterLast() { if (mCursor == null) { return false; } return mCursor.isAfterLast(); } public String getErrorReason() { return mErrorReason; } }
android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java +56 −39 Original line number Diff line number Diff line Loading @@ -32,35 +32,31 @@ package com.android.bluetooth.pbap; import com.android.bluetooth.R; import android.net.Uri; import android.os.Handler; import android.text.TextUtils; import android.util.Log; import android.database.Cursor; import android.content.ContentResolver; import android.content.Context; import android.provider.CallLog; import android.provider.CallLog.Calls; import android.provider.ContactsContract.RawContacts; import android.provider.ContactsContract.PhoneLookup; import android.database.Cursor; import android.net.Uri; import android.pim.vcard.VCardComposer; import android.pim.vcard.VCardConfig; import android.pim.vcard.VCardComposer.OneEntryHandler; import android.provider.ContactsContract; import android.provider.CallLog; import android.provider.CallLog.Calls; import android.provider.ContactsContract.CommonDataKinds; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Data; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.text.TextUtils; import android.util.Log; import com.android.bluetooth.R; import javax.obex.ResponseCodes; import javax.obex.Operation; import java.io.IOException; import java.io.OutputStream; import java.io.Writer; import java.util.ArrayList; import javax.obex.Operation; import javax.obex.ResponseCodes; public class BluetoothPbapVcardManager { private static final String TAG = "BluetoothPbapVcardManager"; Loading Loading @@ -115,7 +111,7 @@ public class BluetoothPbapVcardManager { } public final String getOwnerPhoneNumberVcard(final boolean vcardType21) { VCardComposer composer = new VCardComposer(mContext); BluetoothPbapCallLogComposer composer = new BluetoothPbapCallLogComposer(mContext, false); String name = BluetoothPbapService.getLocalPhoneName(); String number = BluetoothPbapService.getLocalPhoneNum(); String vcard = composer.composeVCardForPhoneOwnNumber(Phone.TYPE_MOBILE, name, number, Loading Loading @@ -425,6 +421,7 @@ public class BluetoothPbapVcardManager { long timestamp = 0; if (V) timestamp = System.currentTimeMillis(); if (isContacts) { VCardComposer composer = null; try { // Currently only support Generic Vcard 2.1 and 3.0 Loading @@ -436,9 +433,28 @@ public class BluetoothPbapVcardManager { } composer = new VCardComposer(mContext, vcardType, true); if (!composer.init(Contacts.CONTENT_URI, selection, null, null)) { return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } while (!composer.isAfterLast()) { if (!composer.createOneEntry()) { Log.e(TAG, "Failed to read a contact. Error reason: " + composer.getErrorReason()); return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } } } finally { if (composer != null) { composer.terminate(); } } } else { // CallLog BluetoothPbapCallLogComposer composer = null; try { composer = new BluetoothPbapCallLogComposer(mContext, true); composer.addHandler(new HandlerForStringBuffer(op, ownerVCard)); final Uri contentUri = (isContacts ? Contacts.CONTENT_URI : CallLog.Calls.CONTENT_URI); if (!composer.init(contentUri, selection, null, null)) { if (!composer.init(CallLog.Calls.CONTENT_URI, selection, null, null)) { return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } Loading @@ -454,6 +470,7 @@ public class BluetoothPbapVcardManager { composer.terminate(); } } } if (V) Log.v(TAG, "Total vcard composing and sending out takes " + (System.currentTimeMillis() - timestamp) + " ms"); Loading