From 2b36e1731eb5ed784abc1a374eb69d8523123df1 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Fri, 30 Oct 2009 11:32:36 -0700 Subject: [PATCH] Fix get contact size not correct issue. Call history handles should be ordered by "date DESC" per spec. The first handle 1.vcf should be the most recently happend call. Add order support for pullVcardListing reqeust: One typical use case for PBAP is: first use pullVcardListing request to display the contacts list, then use pullVcardEntry request to tirgger the selected contact vcard. In such case, we need keep the contact db query consistent for pullVcardListing and pullVcardEntry. Use "Own number" for phone owner number instead of "Unknown name" in case can not get the name from system. Original Change: Fan Jackson Dr No: Eastham Bug Id: 2183320 --- res/values/strings_pbap.xml | 1 + .../bluetooth/pbap/BluetoothPbapObexServer.java | 70 ++++++++--- .../bluetooth/pbap/BluetoothPbapService.java | 2 +- .../bluetooth/pbap/BluetoothPbapVcardManager.java | 130 ++++++++++++++++----- 4 files changed, 155 insertions(+), 48 deletions(-) diff --git a/res/values/strings_pbap.xml b/res/values/strings_pbap.xml index 7949500e..30673749 100644 --- a/res/values/strings_pbap.xml +++ b/res/values/strings_pbap.xml @@ -24,5 +24,6 @@ Always allowed? Carkit Unknown name + My phone number 000000 diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java b/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java index 5a1121b8..bfadf70f 100644 --- a/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java +++ b/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java @@ -38,6 +38,7 @@ import android.os.Handler; import android.text.TextUtils; import android.util.Log; import android.provider.CallLog.Calls; +import android.provider.ContactsContract.Contacts; import android.provider.CallLog; import java.io.IOException; @@ -144,6 +145,12 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private BluetoothPbapVcardManager mVcardManager; + private int mOrderBy = ORDER_BY_INDEXED; + + public static int ORDER_BY_INDEXED = 0; + + public static int ORDER_BY_ALPHABETICAL = 1; + public static class ContentType { public static final int PHONEBOOK = 1; @@ -330,16 +337,16 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { if (D) Log.d(TAG, "Guess what carkit actually want from current path (" + mCurrentPath + ")"); - if (mCurrentPath.compareTo(PB_PATH) == 0) { + if (mCurrentPath.equals(PB_PATH)) { appParamValue.needTag = ContentType.PHONEBOOK; - } else if (mCurrentPath.compareTo(ICH_PATH) == 0) { + } else if (mCurrentPath.equals(ICH_PATH)) { appParamValue.needTag = ContentType.INCOMING_CALL_HISTORY; - } else if (mCurrentPath.compareTo(OCH_PATH) == 0) { + } else if (mCurrentPath.equals(OCH_PATH)) { appParamValue.needTag = ContentType.OUTGOING_CALL_HISTORY; - } else if (mCurrentPath.compareTo(MCH_PATH) == 0) { + } else if (mCurrentPath.equals(MCH_PATH)) { appParamValue.needTag = ContentType.MISSED_CALL_HISTORY; mNeedNewMissedCallsNum = true; - } else if (mCurrentPath.compareTo(CCH_PATH) == 0) { + } else if (mCurrentPath.equals(CCH_PATH)) { appParamValue.needTag = ContentType.COMBINED_CALL_HISTORY; } else { Log.w(TAG, "mCurrentpath is not valid path!!!"); @@ -419,8 +426,16 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { public String searchValue; + // Indicate which vCard parameter the search operation shall be carried + // out on. Can be "Name | Number | Sound", default value is "Name". public String searchAttr; + // Indicate which sorting order shall be used for the + // listing object. + // Can be "Alphabetical | Indexed | Phonetical", default value is + // "Indexed". + public String order; + public int needTag; public boolean vcard21; @@ -430,6 +445,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { listStartOffset = 0; searchValue = ""; searchAttr = ""; + order = ""; needTag = 0x00; vcard21 = true; } @@ -437,7 +453,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { public void dump() { Log.i(TAG, "maxListCount=" + maxListCount + " listStartOffset=" + listStartOffset + " searchValue=" + searchValue + " searchAttr=" + searchAttr + " needTag=" - + needTag + " vcard21=" + vcard21); + + needTag + " vcard21=" + vcard21 + " order=" + order); } } @@ -453,8 +469,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { i += ApplicationParameter.TRIPLET_LENGTH.FILTER_LENGTH; break; case ApplicationParameter.TRIPLET_TAGID.ORDER_TAGID: - // TODO capture this field to use i += 2; // length and tag field in triplet + appParamValue.order = Byte.toString(appParam[i]); i += ApplicationParameter.TRIPLET_LENGTH.ORDER_LENGTH; break; case ApplicationParameter.TRIPLET_TAGID.SEARCH_VALUE_TAGID: @@ -491,7 +507,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { break; case ApplicationParameter.TRIPLET_TAGID.FORMAT_TAGID: i += 2;// length field in triplet - if (Byte.toString(appParam[i]).compareTo("0") != 0) { + if (appParam[i] != 0) { appParamValue.vcard21 = false; } i += ApplicationParameter.TRIPLET_LENGTH.FORMAT_LENGTH; @@ -521,8 +537,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { // Phonebook listing request if (type == ContentType.PHONEBOOK) { // begin of search by name - if (searchAttr.compareTo("0") == 0) { - ArrayList nameList = mVcardManager.getPhonebookNameList(); + if (searchAttr.equals("0")) { + ArrayList nameList = mVcardManager.getPhonebookNameList(mOrderBy ); int requestSize = nameList.size() >= maxListCount ? maxListCount : nameList.size(); int startPoint = listStartOffset; int endPoint = startPoint + requestSize; @@ -555,7 +571,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { } }// end of search by name // begin of search by number - else if (searchAttr.compareTo("1") == 0) { + else if (searchAttr.equals("1")) { ArrayList numberList = mVcardManager.getPhonebookNumberList(); int requestSize = numberList.size() >= maxListCount ? maxListCount : numberList .size(); @@ -770,9 +786,9 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { // If searchAttr is not set by PCE, set default value per spec. appParamValue.searchAttr = "0"; if (D) Log.d(TAG, "searchAttr is not set by PCE, assume search by name by default"); - } else if (searchAttr.compareTo("0") != 0 && searchAttr.compareTo("1") != 0) { + } else if (!searchAttr.equals("0") && !searchAttr.equals("1")) { Log.w(TAG, "search attr not supported"); - if (searchAttr.compareTo("2") == 0) { + if (searchAttr.equals("2")) { // search by sound is not supported currently Log.w(TAG, "do not support search by sound"); return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; @@ -793,6 +809,30 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { return ResponseCodes.OBEX_HTTP_OK; } + String orderPara = appParamValue.order.trim(); + if (TextUtils.isEmpty(orderPara)) { + // If order parameter is not set by PCE, set default value per spec. + appParamValue.order = "0"; + if (D) Log.d(TAG, "Order parameter is not set by PCE. " + + "Assume order by 'Indexed' by default"); + } else if (!orderPara.equals("0") && !orderPara.equals("1")) { + if (V) Log.v(TAG, "Order parameter is not supported: " + appParamValue.order); + if (orderPara.equals("2")) { + // Order by sound is not supported currently + Log.w(TAG, "Do not support order by sound"); + return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; + } + return ResponseCodes.OBEX_HTTP_PRECON_FAILED; + } else { + Log.i(TAG, "Order parameter is valid: " + orderPara); + } + + if (orderPara.equals("0")) { + mOrderBy = ORDER_BY_INDEXED; + } else if (orderPara.equals("1")) { + mOrderBy = ORDER_BY_ALPHABETICAL; + } + int sendResult = sendVcardListingXml(appParamValue.needTag, op, appParamValue.maxListCount, appParamValue.listStartOffset, appParamValue.searchValue, appParamValue.searchAttr); @@ -835,8 +875,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21); return pushBytes(op, ownerVcard); } else { - return mVcardManager.composeAndSendPhonebookVcards(op, intIndex, intIndex, vcard21, - null); + return mVcardManager.composeAndSendPhonebookOneVcard(op, intIndex, vcard21, null, + mOrderBy ); } } else { if (intIndex <= 0 || intIndex > size) { diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapService.java b/src/com/android/bluetooth/pbap/BluetoothPbapService.java index 6c7f7dd2..b32265df 100644 --- a/src/com/android/bluetooth/pbap/BluetoothPbapService.java +++ b/src/com/android/bluetooth/pbap/BluetoothPbapService.java @@ -427,7 +427,7 @@ public class BluetoothPbapService extends Service { } sLocalPhoneName = tm.getLine1AlphaTag(); if (TextUtils.isEmpty(sLocalPhoneName)) { - sLocalPhoneName = this.getString(R.string.unknownName); + sLocalPhoneName = this.getString(R.string.ownNumber); } } diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java b/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java index 96c53439..3a8ce3a3 100644 --- a/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java +++ b/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java @@ -90,10 +90,23 @@ public class BluetoothPbapVcardManager { private static final int CONTACTS_DISPLAY_NAME_COLUMN_INDEX = 4; - static final String SORT_ORDER_NAME = Contacts.DISPLAY_NAME + " ASC"; - static final String SORT_ORDER_PHONE_NUMBER = CommonDataKinds.Phone.NUMBER + " ASC"; + static final String[] CONTACTS_PROJECTION = new String[] { + Contacts._ID, // 0 + Contacts.DISPLAY_NAME, // 1 + }; + + static final int CONTACTS_ID_COLUMN_INDEX = 0; + + static final int CONTACTS_NAME_COLUMN_INDEX = 1; + + // call histories use dynamic handles, and handles should order by date; the + // most recently one should be the first handle. In table "calls", _id and + // date are consistent in ordering, to implement simply, we sort by _id + // here. + static final String CALLLOG_SORT_ORDER = Calls._ID + " DESC"; + public BluetoothPbapVcardManager(final Context context) { mContext = context; mResolver = mContext.getContentResolver(); @@ -123,7 +136,7 @@ public class BluetoothPbapVcardManager { } public final int getContactsSize() { - Uri myUri = RawContacts.CONTENT_URI; + final Uri myUri = Contacts.CONTENT_URI; int size = 0; Cursor contactCursor = null; try { @@ -140,7 +153,7 @@ public class BluetoothPbapVcardManager { } public final int getCallHistorySize(final int type) { - Uri myUri = CallLog.Calls.CONTENT_URI; + final Uri myUri = CallLog.Calls.CONTENT_URI; String selection = BluetoothPbapObexServer.createSelectionPara(type); int size = 0; Cursor callCursor = null; @@ -159,7 +172,7 @@ public class BluetoothPbapVcardManager { } public final ArrayList loadCallHistoryList(final int type) { - Uri myUri = CallLog.Calls.CONTENT_URI; + final Uri myUri = CallLog.Calls.CONTENT_URI; String selection = BluetoothPbapObexServer.createSelectionPara(type); String[] projection = new String[] { Calls.NUMBER, Calls.CACHED_NAME @@ -171,7 +184,7 @@ public class BluetoothPbapVcardManager { ArrayList list = new ArrayList(); try { callCursor = mResolver.query(myUri, projection, selection, null, - CallLog.Calls.DEFAULT_SORT_ORDER); + CALLLOG_SORT_ORDER); if (callCursor != null) { for (callCursor.moveToFirst(); !callCursor.isAfterLast(); callCursor.moveToNext()) { @@ -191,18 +204,24 @@ public class BluetoothPbapVcardManager { return list; } - public final ArrayList getPhonebookNameList() { + public final ArrayList getPhonebookNameList(final int orderByWhat) { ArrayList nameList = new ArrayList(); nameList.add(BluetoothPbapService.getLocalPhoneName()); - Uri myUri = Phone.CONTENT_URI; - Cursor phoneCursor = null; + final Uri myUri = Contacts.CONTENT_URI; + Cursor contactCursor = null; try { - phoneCursor = mResolver.query(myUri, PHONES_PROJECTION, null, null, SORT_ORDER_NAME); - if (phoneCursor != null) { - for (phoneCursor.moveToFirst(); !phoneCursor.isAfterLast(); phoneCursor + if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_INDEXED) { + contactCursor = mResolver.query(myUri, CONTACTS_PROJECTION, null, null, + Contacts._ID); + } else if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL) { + contactCursor = mResolver.query(myUri, CONTACTS_PROJECTION, null, null, + Contacts.DISPLAY_NAME); + } + if (contactCursor != null) { + for (contactCursor.moveToFirst(); !contactCursor.isAfterLast(); contactCursor .moveToNext()) { - String name = phoneCursor.getString(CONTACTS_DISPLAY_NAME_COLUMN_INDEX); + String name = contactCursor.getString(CONTACTS_NAME_COLUMN_INDEX); if (TextUtils.isEmpty(name)) { name = mContext.getString(android.R.string.unknownName); } @@ -210,8 +229,8 @@ public class BluetoothPbapVcardManager { } } } finally { - if (phoneCursor != null) { - phoneCursor.close(); + if (contactCursor != null) { + contactCursor.close(); } } return nameList; @@ -221,7 +240,7 @@ public class BluetoothPbapVcardManager { ArrayList numberList = new ArrayList(); numberList.add(BluetoothPbapService.getLocalPhoneNum()); - Uri myUri = Phone.CONTENT_URI; + final Uri myUri = Phone.CONTENT_URI; Cursor phoneCursor = null; try { phoneCursor = mResolver.query(myUri, PHONES_PROJECTION, null, null, @@ -252,7 +271,7 @@ public class BluetoothPbapVcardManager { } String typeSelection = BluetoothPbapObexServer.createSelectionPara(type); - Uri myUri = CallLog.Calls.CONTENT_URI; + final Uri myUri = CallLog.Calls.CONTENT_URI; final String[] CALLLOG_PROJECTION = new String[] { CallLog.Calls._ID, // 0 }; @@ -264,7 +283,7 @@ public class BluetoothPbapVcardManager { try { // Need test to see if order by _ID is ok here, or by date? callsCursor = mResolver.query(myUri, CALLLOG_PROJECTION, typeSelection, null, - CallLog.Calls._ID); + CALLLOG_SORT_ORDER); if (callsCursor != null) { callsCursor.moveToPosition(startPoint - 1); startPointId = callsCursor.getLong(ID_COLUMN_INDEX); @@ -287,8 +306,10 @@ public class BluetoothPbapVcardManager { if (startPoint == endPoint) { recordSelection = Calls._ID + "=" + startPointId; } else { - recordSelection = Calls._ID + ">=" + startPointId + " AND " + Calls._ID + "<=" - + endPointId; + // The query to call table is by "_id DESC" order, so change + // correspondingly. + recordSelection = Calls._ID + ">=" + endPointId + " AND " + Calls._ID + "<=" + + startPointId; } String selection; @@ -309,27 +330,23 @@ public class BluetoothPbapVcardManager { Log.e(TAG, "internal error: startPoint or endPoint is not correct."); return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } - Uri myUri = RawContacts.CONTENT_URI; - final String[] RAW_CONTACTS_PROJECTION = new String[] { - RawContacts._ID, // 0 - }; - final int ID_COLUMN_INDEX = 0; + final Uri myUri = Contacts.CONTENT_URI; Cursor contactCursor = null; long startPointId = 0; long endPointId = 0; try { - contactCursor = mResolver.query(myUri, RAW_CONTACTS_PROJECTION, null, null, - RawContacts._ID); + contactCursor = mResolver.query(myUri, CONTACTS_PROJECTION, null, null, + Contacts._ID); if (contactCursor != null) { contactCursor.moveToPosition(startPoint - 1); - startPointId = contactCursor.getLong(ID_COLUMN_INDEX); + startPointId = contactCursor.getLong(CONTACTS_ID_COLUMN_INDEX); if (V) Log.v(TAG, "Query startPointId = " + startPointId); if (startPoint == endPoint) { endPointId = startPointId; } else { contactCursor.moveToPosition(endPoint - 1); - endPointId = contactCursor.getLong(ID_COLUMN_INDEX); + endPointId = contactCursor.getLong(CONTACTS_ID_COLUMN_INDEX); } if (V) Log.v(TAG, "Query endPointId = " + endPointId); } @@ -339,11 +356,11 @@ public class BluetoothPbapVcardManager { } } - String selection; + final String selection; if (startPoint == endPoint) { - selection = RawContacts._ID + "=" + startPointId; + selection = Contacts._ID + "=" + startPointId; } else { - selection = RawContacts._ID + ">=" + startPointId + " AND " + RawContacts._ID + "<=" + selection = Contacts._ID + ">=" + startPointId + " AND " + Contacts._ID + "<=" + endPointId; } @@ -352,6 +369,55 @@ public class BluetoothPbapVcardManager { return composeAndSendVCards(op, selection, vcardType21, ownerVCard, true); } + public final int composeAndSendPhonebookOneVcard(final Operation op, final int offset, + final boolean vcardType21, String ownerVCard, int orderByWhat) { + if (offset < 1) { + Log.e(TAG, "Internal error: offset is not correct."); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + final Uri myUri = Contacts.CONTENT_URI; + Cursor contactCursor = null; + String selection = null; + long contactId = 0; + if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_INDEXED) { + try { + contactCursor = mResolver.query(myUri, CONTACTS_PROJECTION, null, null, + Contacts._ID); + if (contactCursor != null) { + contactCursor.moveToPosition(offset - 1); + contactId = contactCursor.getLong(CONTACTS_ID_COLUMN_INDEX); + if (V) Log.v(TAG, "Query startPointId = " + contactId); + } + } finally { + if (contactCursor != null) { + contactCursor.close(); + } + } + } else if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL) { + try { + contactCursor = mResolver.query(myUri, CONTACTS_PROJECTION, null, null, + Contacts.DISPLAY_NAME); + if (contactCursor != null) { + contactCursor.moveToPosition(offset - 1); + contactId = contactCursor.getLong(CONTACTS_ID_COLUMN_INDEX); + if (V) Log.v(TAG, "Query startPointId = " + contactId); + } + } finally { + if (contactCursor != null) { + contactCursor.close(); + } + } + } else { + Log.e(TAG, "Parameter orderByWhat is not supported!"); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + selection = Contacts._ID + "=" + contactId; + + if (V) Log.v(TAG, "Query selection is: " + selection); + + return composeAndSendVCards(op, selection, vcardType21, ownerVCard, true); + } + public final int composeAndSendVCards(final Operation op, final String selection, final boolean vcardType21, String ownerVCard, boolean isContacts) { long timestamp = 0; -- 2.11.0