OSDN Git Service

Fix get contact size not correct issue.
authorJaikumar Ganesh <jaikumar@google.com>
Fri, 30 Oct 2009 18:32:36 +0000 (11:32 -0700)
committerJaikumar Ganesh <jaikumar@google.com>
Mon, 2 Nov 2009 18:19:37 +0000 (10:19 -0800)
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
src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java
src/com/android/bluetooth/pbap/BluetoothPbapService.java
src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java

index 7949500..3067374 100644 (file)
@@ -24,5 +24,6 @@
     <string name="alwaysallowed">Always allowed?</string>
     <string name="defaultname">Carkit</string>
     <string name="unknownName">Unknown name</string>
+    <string name="ownNumber">My phone number</string>
     <string name="defaultnumber">000000</string>
 </resources>
index 5a1121b..bfadf70 100644 (file)
@@ -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
+        // <x-bt/vcard-listing> 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<String> nameList = mVcardManager.getPhonebookNameList();
+            if (searchAttr.equals("0")) {
+                ArrayList<String> 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<String> 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) {
index 6c7f7dd..b32265d 100644 (file)
@@ -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);
             }
         }
 
index 96c5343..3a8ce3a 100644 (file)
@@ -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<String> 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<String> list = new ArrayList<String>();
         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<String> getPhonebookNameList() {
+    public final ArrayList<String> getPhonebookNameList(final int orderByWhat) {
         ArrayList<String> nameList = new ArrayList<String>();
         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<String> numberList = new ArrayList<String>();
         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;