/**
   * Dispatches inbound messages that are in the WAP PDU format. See wap-230-wsp-20010705-a section
   * 8 for details on the WAP PDU format.
   *
   * @param pdu The WAP PDU, made up of one or more SMS PDUs
   * @return a result code from {@link Telephony.Sms.Intents}, or {@link Activity#RESULT_OK} if the
   *     message has been broadcast to applications
   */
  public int dispatchWapPdu(byte[] pdu) {

    if (Config.DEBUG) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));

    int index = 0;
    int transactionId = pdu[index++] & 0xFF;
    int pduType = pdu[index++] & 0xFF;
    int headerLength = 0;

    if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH)
        && (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
      if (Config.DEBUG) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
      return Intents.RESULT_SMS_HANDLED;
    }

    pduDecoder = new WspTypeDecoder(pdu);

    /**
     * Parse HeaderLen(unsigned integer). From wap-230-wsp-20010705-a section 8.1.2 The maximum size
     * of a uintvar is 32 bits. So it will be encoded in no more than 5 octets.
     */
    if (pduDecoder.decodeUintvarInteger(index) == false) {
      if (Config.DEBUG) Log.w(LOG_TAG, "Received PDU. Header Length error.");
      return Intents.RESULT_SMS_GENERIC_ERROR;
    }
    headerLength = (int) pduDecoder.getValue32();
    index += pduDecoder.getDecodedDataLength();

    int headerStartIndex = index;

    /**
     * Parse Content-Type. From wap-230-wsp-20010705-a section 8.4.2.24
     *
     * <p>Content-type-value = Constrained-media | Content-general-form Content-general-form =
     * Value-length Media-type Media-type = (Well-known-media | Extension-Media) *(Parameter)
     * Value-length = Short-length | (Length-quote Length) Short-length = <Any octet 0-30> (octet <=
     * WAP_PDU_SHORT_LENGTH_MAX) Length-quote = <Octet 31> (WAP_PDU_LENGTH_QUOTE) Length =
     * Uintvar-integer
     */
    if (pduDecoder.decodeContentType(index) == false) {
      if (Config.DEBUG) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
      return Intents.RESULT_SMS_GENERIC_ERROR;
    }

    String mimeType = pduDecoder.getValueString();

    index += pduDecoder.getDecodedDataLength();

    byte[] header = new byte[headerLength];
    System.arraycopy(pdu, headerStartIndex, header, 0, header.length);

    byte[] intentData;
    String permission;

    if (mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) {
      intentData = pdu;
    } else {
      int dataIndex = headerStartIndex + headerLength;
      intentData = new byte[pdu.length - dataIndex];
      System.arraycopy(pdu, dataIndex, intentData, 0, intentData.length);
    }

    if (mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_MMS)) {
      permission = "android.permission.RECEIVE_MMS";
    } else {
      permission = "android.permission.RECEIVE_WAP_PUSH";
    }

    Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
    intent.setType(mimeType);
    intent.putExtra("transactionId", transactionId);
    intent.putExtra("pduType", pduType);
    intent.putExtra("header", header);
    intent.putExtra("data", intentData);
    intent.putExtra("contentTypeParameters", pduDecoder.getContentParameters());

    mSmsDispatcher.dispatch(intent, permission);

    return Activity.RESULT_OK;
  }
  /**
   * Dispatches inbound messages that are in the WAP PDU format. See wap-230-wsp-20010705-a section
   * 8 for details on the WAP PDU format.
   *
   * @param pdu The WAP PDU, made up of one or more SMS PDUs
   * @return a result code from {@link Telephony.Sms.Intents}, or {@link Activity#RESULT_OK} if the
   *     message has been broadcast to applications
   */
  public int dispatchWapPdu(byte[] pdu) {

    if (false) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));

    int index = 0;
    int transactionId = pdu[index++] & 0xFF;
    int pduType = pdu[index++] & 0xFF;
    int headerLength = 0;

    if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH)
        && (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
      if (false) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
      return Intents.RESULT_SMS_HANDLED;
    }

    pduDecoder = new WspTypeDecoder(pdu);

    /**
     * Parse HeaderLen(unsigned integer). From wap-230-wsp-20010705-a section 8.1.2 The maximum size
     * of a uintvar is 32 bits. So it will be encoded in no more than 5 octets.
     */
    if (pduDecoder.decodeUintvarInteger(index) == false) {
      if (false) Log.w(LOG_TAG, "Received PDU. Header Length error.");
      return Intents.RESULT_SMS_GENERIC_ERROR;
    }
    headerLength = (int) pduDecoder.getValue32();
    index += pduDecoder.getDecodedDataLength();

    int headerStartIndex = index;

    /**
     * Parse Content-Type. From wap-230-wsp-20010705-a section 8.4.2.24
     *
     * <p>Content-type-value = Constrained-media | Content-general-form Content-general-form =
     * Value-length Media-type Media-type = (Well-known-media | Extension-Media) *(Parameter)
     * Value-length = Short-length | (Length-quote Length) Short-length = <Any octet 0-30> (octet <=
     * WAP_PDU_SHORT_LENGTH_MAX) Length-quote = <Octet 31> (WAP_PDU_LENGTH_QUOTE) Length =
     * Uintvar-integer
     */
    if (pduDecoder.decodeContentType(index) == false) {
      if (false) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
      return Intents.RESULT_SMS_GENERIC_ERROR;
    }

    String mimeType = pduDecoder.getValueString();
    long binaryContentType = pduDecoder.getValue32();
    index += pduDecoder.getDecodedDataLength();

    byte[] header = new byte[headerLength];
    System.arraycopy(pdu, headerStartIndex, header, 0, header.length);

    byte[] intentData;

    if (mimeType != null && mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) {
      intentData = pdu;
    } else {
      int dataIndex = headerStartIndex + headerLength;
      intentData = new byte[pdu.length - dataIndex];
      System.arraycopy(pdu, dataIndex, intentData, 0, intentData.length);
    }

    /**
     * Seek for application ID field in WSP header. If application ID is found, WapPushManager
     * substitute the message processing. Since WapPushManager is optional module, if WapPushManager
     * is not found, legacy message processing will be continued.
     */
    if (pduDecoder.seekXWapApplicationId(index, index + headerLength - 1)) {
      index = (int) pduDecoder.getValue32();
      pduDecoder.decodeXWapApplicationId(index);
      String wapAppId = pduDecoder.getValueString();
      if (wapAppId == null) {
        wapAppId = Integer.toString((int) pduDecoder.getValue32());
      }

      String contentType = ((mimeType == null) ? Long.toString(binaryContentType) : mimeType);
      if (false) Log.v(LOG_TAG, "appid found: " + wapAppId + ":" + contentType);

      try {
        boolean processFurther = true;
        IWapPushManager wapPushMan = mWapConn.getWapPushManager();

        if (wapPushMan == null) {
          if (false) Log.w(LOG_TAG, "wap push manager not found!");
        } else {
          Intent intent = new Intent();
          intent.putExtra("transactionId", transactionId);
          intent.putExtra("pduType", pduType);
          intent.putExtra("header", header);
          intent.putExtra("data", intentData);
          intent.putExtra("contentTypeParameters", pduDecoder.getContentParameters());

          int procRet = wapPushMan.processMessage(wapAppId, contentType, intent);
          if (false) Log.v(LOG_TAG, "procRet:" + procRet);
          if ((procRet & WapPushManagerParams.MESSAGE_HANDLED) > 0
              && (procRet & WapPushManagerParams.FURTHER_PROCESSING) == 0) {
            processFurther = false;
          }
        }
        if (!processFurther) {
          return Intents.RESULT_SMS_HANDLED;
        }
      } catch (RemoteException e) {
        if (false) Log.w(LOG_TAG, "remote func failed...");
      }
    }
    if (false) Log.v(LOG_TAG, "fall back to existing handler");

    if (mimeType == null) {
      if (false) Log.w(LOG_TAG, "Header Content-Type error.");
      return Intents.RESULT_SMS_GENERIC_ERROR;
    }

    String permission;

    if (mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_MMS)) {
      permission = "android.permission.RECEIVE_MMS";
    } else {
      permission = "android.permission.RECEIVE_WAP_PUSH";
    }

    Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
    intent.setType(mimeType);
    intent.putExtra("transactionId", transactionId);
    intent.putExtra("pduType", pduType);
    intent.putExtra("header", header);
    intent.putExtra("data", intentData);
    intent.putExtra("contentTypeParameters", pduDecoder.getContentParameters());

    mSmsDispatcher.dispatch(intent, permission);

    return Activity.RESULT_OK;
  }