PullvCardList implemented according to specification

The value tag sent as a byte array was not parsed correctly
leading to illegal strings. The list count value was not used
according to the specification, now refers to number of entries
that should be returned. Specification for Phone book access
profile chapter 5.3 default max list size of OxFFFF (65535)
taken from 5.3.4.4. Now uses default values when Application
Parameter headers are missing.

Change-Id: Ib17f2208a91b4f896d9beebaf3a21566502ac291
diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java b/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java
index 3ce324c..cc14634 100644
--- a/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java
+++ b/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java
@@ -398,7 +398,7 @@
             }
         }
 
-        if (!parseApplicationParameter(appParam, appParamValue)) {
+        if ((appParam != null) && !parseApplicationParameter(appParam, appParamValue)) {
             return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
         }
 
@@ -454,7 +454,7 @@
         public boolean vcard21;
 
         public AppParamValue() {
-            maxListCount = 0;
+            maxListCount = 0xFFFF;
             listStartOffset = 0;
             searchValue = "";
             searchAttr = "";
@@ -488,11 +488,10 @@
                     break;
                 case ApplicationParameter.TRIPLET_TAGID.SEARCH_VALUE_TAGID:
                     i += 1; // length field in triplet
-                    for (int k = 1; k <= appParam[i]; k++) {
-                        appParamValue.searchValue += Byte.toString(appParam[i + k]);
-                    }
                     // length of search value is variable
-                    i += appParam[i];
+                    int length = appParam[i];
+                    appParamValue.searchValue = new String(appParam, i + 1, length);
+                    i += length;
                     i += 1;
                     break;
                 case ApplicationParameter.TRIPLET_TAGID.SEARCH_ATTRIBUTE_TAGID:
@@ -549,72 +548,14 @@
 
         // Phonebook listing request
         if (type == ContentType.PHONEBOOK) {
-            // begin of search by name
-            if (searchAttr.equals("0")) {
+            if (searchAttr.equals("0")) { // search by name
                 ArrayList<String> nameList = mVcardManager.getPhonebookNameList(mOrderBy );
-                int requestSize = nameList.size() >= maxListCount ? maxListCount : nameList.size();
-                int startPoint = listStartOffset;
-                int endPoint = startPoint + requestSize;
-                if (endPoint > nameList.size()) {
-                    endPoint = nameList.size();
-                }
-
-                if (D) Log.d(TAG, "search by name, size=" + requestSize + " offset=" +
-                        listStartOffset + " searchValue=" + searchValue);
-
-
-                // if searchValue if not set by client,provide the entire
-                // list by name
-                if (searchValue == null || searchValue.trim().length() == 0) {
-                    for (int j = startPoint; j < endPoint; j++) {
-                        result.append("<card handle=\"" + j + ".vcf\" name=\"" + nameList.get(j)
-                                + "\"" + "/>");
-                        itemsFound++;
-                    }
-                } else {
-                    for (int j = startPoint; j < endPoint; j++) {
-                        // only find the name which begins with the searchValue
-                        if (nameList.get(j).startsWith(searchValue.trim())) {
-                            // TODO: PCE not work with it
-                            itemsFound++;
-                            result.append("<card handle=\"" + j + ".vcf\" name=\""
-                                    + nameList.get(j) + "\"" + "/>");
-                        }
-                    }
-                }
-            }// end of search by name
-            // begin of search by number
-            else if (searchAttr.equals("1")) {
+                itemsFound = createList(maxListCount, listStartOffset, searchValue, result,
+                        nameList, "name");
+            } else if (searchAttr.equals("1")) { // search by number
                 ArrayList<String> numberList = mVcardManager.getPhonebookNumberList();
-                int requestSize = numberList.size() >= maxListCount ? maxListCount : numberList
-                        .size();
-                int startPoint = listStartOffset;
-                int endPoint = startPoint + requestSize;
-                if (endPoint > numberList.size()) {
-                    endPoint = numberList.size();
-                }
-
-                if (D) Log.d(TAG, "search by number, size=" + requestSize + " offset="
-                            + listStartOffset + " searchValue=" + searchValue);
-
-                // if searchValue if not set by client,provide the entire
-                // list by number
-                if (searchValue == null || searchValue.trim().length() == 0) {
-                    for (int j = startPoint; j < endPoint; j++) {
-                        result.append("<card handle=\"" + j + ".vcf\" number=\""
-                                + numberList.get(j) + "\"" + "/>");
-                        itemsFound++;
-                    }
-                } else {
-                    for (int j = startPoint; j < endPoint; j++) {
-                        // only find the name which begins with the searchValue
-                        if (numberList.get(j).startsWith(searchValue.trim())) {
-                            itemsFound++;
-                            result.append("<card handle=\"" + j + ".vcf\" number=\""
-                                    + numberList.get(j) + "\"" + "/>");
-                        }
-                    }
-                }
+                itemsFound = createList(maxListCount, listStartOffset, searchValue, result,
+                        numberList, "number");
             }// end of search by number
             else {
                 return ResponseCodes.OBEX_HTTP_PRECON_FAILED;
@@ -645,6 +586,26 @@
         return pushBytes(op, result.toString());
     }
 
+    private int createList(final int maxListCount, final int listStartOffset,
+            final String searchValue, StringBuilder result,
+            ArrayList<String> dataList, String type) {
+        int itemsFound = 0;
+        int requestSize = dataList.size() >= maxListCount ? maxListCount : dataList.size();
+
+        if (D) Log.d(TAG, "search by " + type + ", size=" + requestSize + " offset="
+                    + listStartOffset + " searchValue=" + searchValue);
+
+        for (int pos = listStartOffset; pos < dataList.size() && itemsFound < requestSize; pos++) {
+            String currentValue = dataList.get(pos);
+            if (searchValue == null || currentValue.startsWith(searchValue.trim())) {
+                itemsFound++;
+                result.append("<card handle=\"" + pos + ".vcf\" " + type + "=\""
+                        + currentValue + "\"" + "/>");
+            }
+        }
+        return itemsFound;
+    }
+
     /**
      * Function to send obex header back to client such as get phonebook size
      * request