private final int pullVcardEntry(
      byte[] appParam,
      AppParamValue appParamValue,
      Operation op,
      final String name,
      final String current_path) {
    if (name == null || name.length() < VCARD_NAME_SUFFIX_LENGTH) {
      if (D) Log.d(TAG, "Name is Null, or the length of name < 5 !");
      return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
    }
    String strIndex = name.substring(0, name.length() - VCARD_NAME_SUFFIX_LENGTH + 1);
    int intIndex = 0;
    if (strIndex.trim().length() != 0) {
      try {
        intIndex = Integer.parseInt(strIndex);
      } catch (NumberFormatException e) {
        Log.e(TAG, "catch number format exception " + e.toString());
        return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
      }
    }

    int size = mVcardManager.getPhonebookSize(appParamValue.needTag);
    if (size == 0) {
      if (V) Log.v(TAG, "PhonebookSize is 0, return.");
      return ResponseCodes.OBEX_HTTP_OK;
    }

    boolean vcard21 = appParamValue.vcard21;
    if (appParamValue.needTag == 0) {
      Log.w(TAG, "wrong path!");
      return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
    } else if (appParamValue.needTag == ContentType.PHONEBOOK) {
      if (intIndex < 0 || intIndex >= size) {
        Log.w(TAG, "The requested vcard is not acceptable! name= " + name);
        return ResponseCodes.OBEX_HTTP_OK;
      } else if (intIndex == 0) {
        // For PB_PATH, 0.vcf is the phone number of this phone.
        String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21);
        return pushBytes(op, ownerVcard);
      } else {
        return mVcardManager.composeAndSendPhonebookOneVcard(op, intIndex, vcard21, null, mOrderBy);
      }
    } else {
      if (intIndex <= 0 || intIndex > size) {
        Log.w(TAG, "The requested vcard is not acceptable! name= " + name);
        return ResponseCodes.OBEX_HTTP_OK;
      }
      // For others (ich/och/cch/mch), 0.vcf is meaningless, and must
      // begin from 1.vcf
      if (intIndex >= 1) {
        return mVcardManager.composeAndSendCallLogVcards(
            appParamValue.needTag, op, intIndex, intIndex, vcard21);
      }
    }
    return ResponseCodes.OBEX_HTTP_OK;
  }
  public BluetoothPbapObexServer(Handler callback, Context context) {
    super();
    mConnectionId = -1;
    mCallback = callback;
    mContext = context;
    mVcardManager = new BluetoothPbapVcardManager(mContext);

    // set initial value when ObexServer created
    mMissedCallSize = mVcardManager.getPhonebookSize(ContentType.MISSED_CALL_HISTORY);
    if (D) Log.d(TAG, "Initialize mMissedCallSize=" + mMissedCallSize);
  }
  private final int pullPhonebook(
      byte[] appParam,
      AppParamValue appParamValue,
      HeaderSet reply,
      Operation op,
      final String name) {
    // code start for passing PTS3.2 TC_PSE_PBD_BI_01_C
    if (name != null) {
      int dotIndex = name.indexOf(".");
      String vcf = "vcf";
      if (dotIndex >= 0 && dotIndex <= name.length()) {
        if (name.regionMatches(dotIndex + 1, vcf, 0, vcf.length()) == false) {
          Log.w(TAG, "name is not .vcf");
          return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
        }
      }
    } // code end for passing PTS3.2 TC_PSE_PBD_BI_01_C

    int pbSize = mVcardManager.getPhonebookSize(appParamValue.needTag);
    int needSendBody = handleAppParaForResponse(appParamValue, pbSize, reply, op);
    if (needSendBody != NEED_SEND_BODY) {
      return needSendBody;
    }

    if (pbSize == 0) {
      if (V) Log.v(TAG, "PhonebookSize is 0, return.");
      return ResponseCodes.OBEX_HTTP_OK;
    }

    int requestSize = pbSize >= appParamValue.maxListCount ? appParamValue.maxListCount : pbSize;
    int startPoint = appParamValue.listStartOffset;
    if (startPoint < 0 || startPoint >= pbSize) {
      Log.w(TAG, "listStartOffset is not correct! " + startPoint);
      return ResponseCodes.OBEX_HTTP_OK;
    }

    // Limit the number of call log to CALLLOG_NUM_LIMIT
    if (appParamValue.needTag != BluetoothPbapObexServer.ContentType.PHONEBOOK) {
      if (requestSize > CALLLOG_NUM_LIMIT) {
        requestSize = CALLLOG_NUM_LIMIT;
      }
    }

    int endPoint = startPoint + requestSize - 1;
    if (endPoint > pbSize - 1) {
      endPoint = pbSize - 1;
    }
    if (D)
      Log.d(
          TAG,
          "pullPhonebook(): requestSize="
              + requestSize
              + " startPoint="
              + startPoint
              + " endPoint="
              + endPoint);

    String result = null;
    boolean vcard21 = appParamValue.vcard21;
    if (appParamValue.needTag == BluetoothPbapObexServer.ContentType.PHONEBOOK) {
      if (startPoint == 0) {
        String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21);
        if (endPoint == 0) {
          return pushBytes(op, ownerVcard);
        } else {
          return mVcardManager.composeAndSendPhonebookVcards(op, 1, endPoint, vcard21, ownerVcard);
        }
      } else {
        return mVcardManager.composeAndSendPhonebookVcards(op, startPoint, endPoint, vcard21, null);
      }
    } else {
      return mVcardManager.composeAndSendCallLogVcards(
          appParamValue.needTag, op, startPoint + 1, endPoint + 1, vcard21);
    }
  }
  private final int pullVcardListing(
      byte[] appParam, AppParamValue appParamValue, HeaderSet reply, Operation op) {
    String searchAttr = appParamValue.searchAttr.trim();

    if (searchAttr == null || searchAttr.length() == 0) {
      // 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.equals("0") && !searchAttr.equals("1")) {
      Log.w(TAG, "search attr not supported");
      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;
      }
      return ResponseCodes.OBEX_HTTP_PRECON_FAILED;
    } else {
      Log.i(TAG, "searchAttr is valid: " + searchAttr);
    }

    int size = mVcardManager.getPhonebookSize(appParamValue.needTag);
    int needSendBody = handleAppParaForResponse(appParamValue, size, reply, op);
    if (needSendBody != NEED_SEND_BODY) {
      return needSendBody;
    }

    if (size == 0) {
      if (V) Log.v(TAG, "PhonebookSize is 0, return.");
      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.
      orderPara = "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);
    return sendResult;
  }