@SmsManager.java public void sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { if (TextUtils.isEmpty(destinationAddress)) { throw new IllegalArgumentException("Invalid destinationAddress"); } if (parts == null || parts.size() < 1) { throw new IllegalArgumentException("Invalid message body"); } if (parts.size() > 1) { //长短信发送 try { ISms iccISms = getISmsServiceOrThrow(); iccISms.sendMultipartText(ActivityThread.currentPackageName(), destinationAddress, scAddress, parts, sentIntents, deliveryIntents); } catch (RemoteException ex) { } } else { //普通短信发送 PendingIntent sentIntent = null; PendingIntent deliveryIntent = null; if (sentIntents != null && sentIntents.size() > 0) { sentIntent = sentIntents.get(0); } if (deliveryIntents != null && deliveryIntents.size() > 0) { deliveryIntent = deliveryIntents.get(0); } sendTextMessage(destinationAddress, scAddress, parts.get(0), sentIntent, deliveryIntent); } }在上面的方法中,对于长短信将会通过iccISms对象也就是UiccSmsController的sendMultipartText()方法发送出去:
@UiccSmsController.java public void sendMultipartText(String callingPackage, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) throws android.os.RemoteException { sendMultipartTextForSubscriber(getPreferredSmsSubscription(), callingPackage, destAddr, scAddr, parts, sentIntents, deliveryIntents); } public void sendMultipartTextForSubscriber(long subId, String callingPackage, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) throws android.os.RemoteException { IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null ) { iccSmsIntMgr.sendMultipartText(callingPackage, destAddr, scAddr, parts, sentIntents, deliveryIntents); } else { } }接下来UiccSmsController又把流程交给IccSmsInterfaceManager的sendMultipartText()来处理:
@IccSmsInterfaceManager.java public void sendMultipartText(String callingPackage, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { //权限检查 mPhone.getContext().enforceCallingPermission( Manifest.permission.SEND_SMS, "Sending SMS message"); if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) { return; } if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) { //当前运营商不支持长短新,需要自行将短信分割后分别发送 for (int i = 0; i < parts.size(); i++) { // If EMS is not supported, we have to break down EMS into single segment SMS // and add page info " x/y". String singlePart = parts.get(i); if (SmsMessage.shouldAppendPageNumberAsPrefix()) { singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart; } else { singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' + parts.size()); } PendingIntent singleSentIntent = null; if (sentIntents != null && sentIntents.size() > i) { singleSentIntent = sentIntents.get(i); } PendingIntent singleDeliveryIntent = null; if (deliveryIntents != null && deliveryIntents.size() > i) { singleDeliveryIntent = deliveryIntents.get(i); } //将长短信分割,挨个发送 mDispatcher.sendText(destAddr, scAddr, singlePart, singleSentIntent, singleDeliveryIntent, null/*messageUri*/, callingPackage); } return; } //运营商支持长短信,直接发送即可 mDispatcher.sendMultipartText(destAddr, scAddr, (ArrayList<String>) parts, (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents, null/*messageUri*/, callingPackage); }从上面来看,对于长短信, 需要区分运营商是否支持的情况,如果不支持,需要我们将短信分割后逐条发送,如果支持,需要走不同流程,由于逐条发送时的流程与普通短信发送流程相同,因此这里主要分析以下运营商支持长短信的情况,也就时sendMultipartText()的流程:
@ImsSMSDispatcher.java protected void sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg) { if (isCdmaMo()) { //CDMA mCdmaDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri, callingPkg); } else { //GSM mGsmDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri, callingPkg); } }和普通短信类似,也许要区分当前的网络环境,对于GSM来说,就是使用GsmSMSDispatcher来继续处理,这个处理是在GsmSMSDispatcher父类SMSDispatcher中完成的:
@SMSDispatcher.java protected void sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg) { //将短信移入或写入发件箱 if (messageUri == null) { if (SmsApplication.shouldWriteMessageForPackage(callingPkg, mContext)) { messageUri = writeOutboxMessage( getSubId(), destAddr, getMultipartMessageText(parts), deliveryIntents != null && deliveryIntents.size() > 0, callingPkg); } } else { moveToOutbox(getSubId(), messageUri, callingPkg); } int refNumber = getNextConcatenatedRef() & 0x00FF; int msgCount = parts.size(); int encoding = SmsConstants.ENCODING_UNKNOWN; TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount]; for (int i = 0; i < msgCount; i++) { TextEncodingDetails details = calculateLength(parts.get(i), false); if (encoding != details.codeUnitSize && (encoding == SmsConstants.ENCODING_UNKNOWN || encoding == SmsConstants.ENCODING_7BIT)) { encoding = details.codeUnitSize; } encodingForParts[i] = details; } // States to track at the message level (for all parts) final AtomicInteger unsentPartCount = new AtomicInteger(msgCount); final AtomicBoolean anyPartFailed = new AtomicBoolean(false); 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; // Set the national language tables for 3GPP 7-bit encoding, if enabled. if (encoding == SmsConstants.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); } //逐条发送 sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding, sentIntent, deliveryIntent, (i == (msgCount - 1)), unsentPartCount, anyPartFailed, messageUri); } }在上面的过程中我们看到,对于运营商支持的长短信情况, 需要把拆分出来的短信分别加上短信头编码,也就是SmsHeader,然后分别调用sendNewSubmitPdu()方法进行发送。
protected void sendNewSubmitPdu(String destinationAddress, String scAddress, String message, SmsHeader smsHeader, int encoding, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart, AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri) { //对短信内容进行编码 SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader), encoding, smsHeader.languageTable, smsHeader.languageShiftTable); if (pdu != null) { HashMap map = getSmsTrackerMap(destinationAddress, scAddress, message, pdu); //发送 SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader, !lastPart); sendRawPdu(tracker); } else { Rlog.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null"); } }接下来的流程和普通短信一样,最终通过RILJ将短信发送出去,并且注册回调消息为EVENT_SEND_SMS_COMPLETE。
所以当SMSDispatcher接收到EVENT_SEND_SMS_COMPLETE消息时,就说明,无论是普通短信或者长短信,都已经发送完毕。
以上就是长短信的发送流程。
多收件人的情况,请见下节介绍。