/** {@inheritDoc} */
  protected void sendMultipartText(
      String destinationAddress,
      String scAddress,
      ArrayList<String> parts,
      ArrayList<PendingIntent> sentIntents,
      ArrayList<PendingIntent> deliveryIntents) {

    int refNumber = getNextConcatenatedRef() & 0x00FF;
    int msgCount = parts.size();
    int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;

    mRemainingMessages = msgCount;

    TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
    for (int i = 0; i < msgCount; i++) {
      TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
      if (encoding != details.codeUnitSize
          && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
              || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
        encoding = details.codeUnitSize;
      }
      encodingForParts[i] = details;
    }

    for (int i = 0; i < msgCount; i++) {
      SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
      concatRef.refNumber = refNumber;
      concatRef.seqNumber = i + 1; // 1-based sequence
      concatRef.msgCount = msgCount;
      // TODO: We currently set this to true since our messaging app will never
      // send more than 255 parts (it converts the message to MMS well before that).
      // However, we should support 3rd party messaging apps that might need 16-bit
      // references
      // Note:  It's not sufficient to just flip this bit to true; it will have
      // ripple effects (several calculations assume 8-bit ref).
      concatRef.isEightBits = true;
      SmsHeader smsHeader = new SmsHeader();
      smsHeader.concatRef = concatRef;
      if (encoding == android.telephony.SmsMessage.ENCODING_7BIT) {
        smsHeader.languageTable = encodingForParts[i].languageTable;
        smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
      }

      PendingIntent sentIntent = null;
      if (sentIntents != null && sentIntents.size() > i) {
        sentIntent = sentIntents.get(i);
      }

      PendingIntent deliveryIntent = null;
      if (deliveryIntents != null && deliveryIntents.size() > i) {
        deliveryIntent = deliveryIntents.get(i);
      }

      SmsMessage.SubmitPdu pdus =
          SmsMessage.getSubmitPdu(
              scAddress,
              destinationAddress,
              parts.get(i),
              deliveryIntent != null,
              SmsHeader.toByteArray(smsHeader),
              encoding,
              smsHeader.languageTable,
              smsHeader.languageShiftTable);

      sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
    }
  }
  /**
   * Send a multi-part text based SMS which already passed SMS control check.
   *
   * It is the working function for sendMultipartText().
   *
   * @param destinationAddress the address to send the message to
   * @param scAddress is the service center address or null to use
   *   the current default SMSC
   * @param parts an <code>ArrayList</code> of strings that, in order,
   *   comprise the original message
   * @param sentIntents if not null, an <code>ArrayList</code> of
   *   <code>PendingIntent</code>s (one for each message part) that is
   *   broadcast when the corresponding message part has been sent.
   *   The result code will be <code>Activity.RESULT_OK<code> for success,
   *   or one of these errors:
   *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
   *   <code>RESULT_ERROR_RADIO_OFF</code>
   *   <code>RESULT_ERROR_NULL_PDU</code>.
   * @param deliveryIntents if not null, an <code>ArrayList</code> of
   *   <code>PendingIntent</code>s (one for each message part) that is
   *   broadcast when the corresponding message part has been delivered
   *   to the recipient.  The raw pdu of the status report is in the
   *   extended data ("pdu").
   */
  private void sendMultipartTextWithPermit(
      String destinationAddress,
      String scAddress,
      ArrayList<String> parts,
      ArrayList<PendingIntent> sentIntents,
      ArrayList<PendingIntent> deliveryIntents) {

    // check if in service
    int ss = mPhone.getServiceState().getState();
    if (ss != ServiceState.STATE_IN_SERVICE) {
      for (int i = 0, count = parts.size(); i < count; i++) {
        PendingIntent sentIntent = null;
        if (sentIntents != null && sentIntents.size() > i) {
          sentIntent = sentIntents.get(i);
        }
        SmsTracker tracker = SmsTrackerFactory(null, sentIntent, null);
        handleNotInService(ss, tracker);
      }
      return;
    }

    int refNumber = getNextConcatenatedRef() & 0x00FF;
    int msgCount = parts.size();
    int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;

    mRemainingMessages = msgCount;

    TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
    for (int i = 0; i < msgCount; i++) {
      TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
      if (encoding != details.codeUnitSize
          && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
              || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
        encoding = details.codeUnitSize;
      }
      encodingForParts[i] = details;
    }

    for (int i = 0; i < msgCount; i++) {
      SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
      concatRef.refNumber = refNumber;
      concatRef.seqNumber = i + 1; // 1-based sequence
      concatRef.msgCount = msgCount;
      concatRef.isEightBits = false;
      SmsHeader smsHeader = new SmsHeader();
      smsHeader.concatRef = concatRef;
      if (encoding == android.telephony.SmsMessage.ENCODING_7BIT) {
        smsHeader.languageTable = encodingForParts[i].languageTable;
        smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
      }

      PendingIntent sentIntent = null;
      if (sentIntents != null && sentIntents.size() > i) {
        sentIntent = sentIntents.get(i);
      }

      PendingIntent deliveryIntent = null;
      if (deliveryIntents != null && deliveryIntents.size() > i) {
        deliveryIntent = deliveryIntents.get(i);
      }

      SmsMessage.SubmitPdu pdus =
          SmsMessage.getSubmitPdu(
              scAddress,
              destinationAddress,
              parts.get(i),
              deliveryIntent != null,
              SmsHeader.toByteArray(smsHeader),
              encoding,
              smsHeader.languageTable,
              smsHeader.languageShiftTable);

      HashMap<String, Object> map = new HashMap<String, Object>();
      map.put("smsc", pdus.encodedScAddress);
      map.put("pdu", pdus.encodedMessage);

      SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent);
      sendSms(tracker);
    }
  }
  /**
   * Get an SMS-SUBMIT PDU for a destination address and a message using the specified encoding.
   *
   * @param scAddress Service Centre address. Null means use default.
   * @param encoding Encoding defined by constants in
   *     com.android.internal.telephony.SmsConstants.ENCODING_*
   * @param languageTable
   * @param languageShiftTable
   * @return a <code>SubmitPdu</code> containing the encoded SC address, if applicable, and the
   *     encoded message. Returns null on encode error.
   * @hide
   */
  public static SubmitPdu getSubmitPdu(
      String scAddress,
      String destinationAddress,
      String message,
      boolean statusReportRequested,
      byte[] header,
      int encoding,
      int languageTable,
      int languageShiftTable) {

    // Perform null parameter checks.
    if (message == null || destinationAddress == null) {
      return null;
    }

    if (encoding == ENCODING_UNKNOWN) {
      // Find the best encoding to use
      TextEncodingDetails ted = calculateLength(message, false);
      encoding = ted.codeUnitSize;
      languageTable = ted.languageTable;
      languageShiftTable = ted.languageShiftTable;

      if (encoding == ENCODING_7BIT && (languageTable != 0 || languageShiftTable != 0)) {
        if (header != null) {
          SmsHeader smsHeader = SmsHeader.fromByteArray(header);
          if (smsHeader.languageTable != languageTable
              || smsHeader.languageShiftTable != languageShiftTable) {
            Rlog.w(
                LOG_TAG,
                "Updating language table in SMS header: "
                    + smsHeader.languageTable
                    + " -> "
                    + languageTable
                    + ", "
                    + smsHeader.languageShiftTable
                    + " -> "
                    + languageShiftTable);
            smsHeader.languageTable = languageTable;
            smsHeader.languageShiftTable = languageShiftTable;
            header = SmsHeader.toByteArray(smsHeader);
          }
        } else {
          SmsHeader smsHeader = new SmsHeader();
          smsHeader.languageTable = languageTable;
          smsHeader.languageShiftTable = languageShiftTable;
          header = SmsHeader.toByteArray(smsHeader);
        }
      }
    }

    SubmitPdu ret = new SubmitPdu();
    // MTI = SMS-SUBMIT, UDHI = header != null
    byte mtiByte = (byte) (0x01 | (header != null ? 0x40 : 0x00));
    ByteArrayOutputStream bo =
        getSubmitPduHead(scAddress, destinationAddress, mtiByte, statusReportRequested, ret);

    // User Data (and length)
    byte[] userData;
    try {
      if (encoding == ENCODING_7BIT) {
        userData =
            GsmAlphabet.stringToGsm7BitPackedWithHeader(
                message, header, languageTable, languageShiftTable);
      } else { // assume UCS-2
        try {
          userData = encodeUCS2(message, header);
        } catch (UnsupportedEncodingException uex) {
          Rlog.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex);
          return null;
        }
      }
    } catch (EncodeException ex) {
      // Encoding to the 7-bit alphabet failed. Let's see if we can
      // send it as a UCS-2 encoded message
      try {
        userData = encodeUCS2(message, header);
        encoding = ENCODING_16BIT;
      } catch (UnsupportedEncodingException uex) {
        Rlog.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex);
        return null;
      }
    }

    if (encoding == ENCODING_7BIT) {
      if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) {
        // Message too long
        Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " septets)");
        return null;
      }
      // TP-Data-Coding-Scheme
      // Default encoding, uncompressed
      // To test writing messages to the SIM card, change this value 0x00
      // to 0x12, which means "bits 1 and 0 contain message class, and the
      // class is 2". Note that this takes effect for the sender. In other
      // words, messages sent by the phone with this change will end up on
      // the receiver's SIM card. You can then send messages to yourself
      // (on a phone with this change) and they'll end up on the SIM card.
      bo.write(0x00);
    } else { // assume UCS-2
      if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) {
        // Message too long
        Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " bytes)");
        return null;
      }
      // TP-Data-Coding-Scheme
      // UCS-2 encoding, uncompressed
      bo.write(0x08);
    }

    // (no TP-Validity-Period)
    bo.write(userData, 0, userData.length);
    ret.encodedMessage = bo.toByteArray();
    return ret;
  }