Android短信发送流程之长短信发送(原)

 从前面《 Android短信发送流程之普通短信发送 》流程看到,长短信与普通短信的流程从SmsManager的sendMultipartTextMessage()方法开始区分,现在我们来看长短信的流程:
[java]  view plain  copy
  1. @SmsManager.java  
  2. public void sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {  
  3.     if (TextUtils.isEmpty(destinationAddress)) {  
  4.         throw new IllegalArgumentException("Invalid destinationAddress");  
  5.     }  
  6.     if (parts == null || parts.size() < 1) {  
  7.         throw new IllegalArgumentException("Invalid message body");  
  8.     }  
  9.   
  10.   
  11.     if (parts.size() > 1) {  
  12.         //长短信发送  
  13.         try {  
  14.             ISms iccISms = getISmsServiceOrThrow();  
  15.             iccISms.sendMultipartText(ActivityThread.currentPackageName(),  
  16.                     destinationAddress, scAddress, parts,  
  17.                     sentIntents, deliveryIntents);  
  18.         } catch (RemoteException ex) {  
  19.         }  
  20.     } else {  
  21.         //普通短信发送  
  22.         PendingIntent sentIntent = null;  
  23.         PendingIntent deliveryIntent = null;  
  24.         if (sentIntents != null && sentIntents.size() > 0) {  
  25.             sentIntent = sentIntents.get(0);  
  26.         }  
  27.         if (deliveryIntents != null && deliveryIntents.size() > 0) {  
  28.             deliveryIntent = deliveryIntents.get(0);  
  29.         }  
  30.         sendTextMessage(destinationAddress, scAddress, parts.get(0), sentIntent, deliveryIntent);  
  31.     }  
  32. }  
        在上面的方法中,对于长短信将会通过iccISms对象也就是UiccSmsController的sendMultipartText()方法发送出去:
[java]  view plain  copy
  1. @UiccSmsController.java  
  2. public void sendMultipartText(String callingPackage, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) throws android.os.RemoteException {  
  3.     sendMultipartTextForSubscriber(getPreferredSmsSubscription(), callingPackage, destAddr, scAddr, parts, sentIntents, deliveryIntents);  
  4. }  
  5. public void sendMultipartTextForSubscriber(long subId, String callingPackage, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) throws android.os.RemoteException {  
  6.     IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);  
  7.     if (iccSmsIntMgr != null ) {  
  8.         iccSmsIntMgr.sendMultipartText(callingPackage, destAddr, scAddr, parts, sentIntents,  
  9.                 deliveryIntents);  
  10.     } else {  
  11.     }  
  12. }  
        接下来UiccSmsController又把流程交给IccSmsInterfaceManager的sendMultipartText()来处理:
[java]  view plain  copy
  1. @IccSmsInterfaceManager.java  
  2. public void sendMultipartText(String callingPackage, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {  
  3.     //权限检查  
  4.     mPhone.getContext().enforceCallingPermission( Manifest.permission.SEND_SMS, "Sending SMS message");  
  5.     if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) {  
  6.         return;  
  7.     }  
  8.   
  9.   
  10.     if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) {  
  11.         //当前运营商不支持长短新,需要自行将短信分割后分别发送  
  12.         for (int i = 0; i < parts.size(); i++) {  
  13.             // If EMS is not supported, we have to break down EMS into single segment SMS  
  14.             // and add page info " x/y".  
  15.             String singlePart = parts.get(i);  
  16.             if (SmsMessage.shouldAppendPageNumberAsPrefix()) {  
  17.                 singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart;  
  18.             } else {  
  19.                 singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' + parts.size());  
  20.             }  
  21.   
  22.   
  23.             PendingIntent singleSentIntent = null;  
  24.             if (sentIntents != null && sentIntents.size() > i) {  
  25.                 singleSentIntent = sentIntents.get(i);  
  26.             }  
  27.   
  28.   
  29.             PendingIntent singleDeliveryIntent = null;  
  30.             if (deliveryIntents != null && deliveryIntents.size() > i) {  
  31.                 singleDeliveryIntent = deliveryIntents.get(i);  
  32.             }  
  33.   
  34.   
  35.             //将长短信分割,挨个发送  
  36.             mDispatcher.sendText(destAddr, scAddr, singlePart,  
  37.                     singleSentIntent, singleDeliveryIntent,  
  38.                     null/*messageUri*/, callingPackage);  
  39.         }  
  40.         return;  
  41.     }  
  42.     //运营商支持长短信,直接发送即可  
  43.     mDispatcher.sendMultipartText(destAddr, scAddr, (ArrayList<String>) parts,  
  44.             (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents,  
  45.             null/*messageUri*/, callingPackage);  
  46. }  
        从上面来看,对于长短信, 需要区分运营商是否支持的情况 ,如果不支持,需要我们将短信分割后逐条发送,如果支持,需要走不同流程,由于逐条发送时的流程与普通短信发送流程相同,因此这里主要分析以下运营商支持长短信的情况,也就时sendMultipartText()的流程:
[java]  view plain  copy
  1. @ImsSMSDispatcher.java  
  2. protected void sendMultipartText(String destAddr, String scAddr,  
  3.         ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,  
  4.         ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg) {  
  5.     if (isCdmaMo()) {  
  6.         //CDMA  
  7.         mCdmaDispatcher.sendMultipartText(destAddr, scAddr,  
  8.                 parts, sentIntents, deliveryIntents, messageUri, callingPkg);  
  9.     } else {  
  10.         //GSM  
  11.         mGsmDispatcher.sendMultipartText(destAddr, scAddr,  
  12.                 parts, sentIntents, deliveryIntents, messageUri, callingPkg);  
  13.     }  
  14. }  
        和普通短信类似,也许要区分当前的网络环境,对于GSM来说,就是使用GsmSMSDispatcher来继续处理,这个处理是在GsmSMSDispatcher父类SMSDispatcher中完成的:
[java]  view plain  copy
  1. @SMSDispatcher.java  
  2. protected void sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg) {  
  3.     //将短信移入或写入发件箱  
  4.     if (messageUri == null) {  
  5.         if (SmsApplication.shouldWriteMessageForPackage(callingPkg, mContext)) {  
  6.             messageUri = writeOutboxMessage(  
  7.                     getSubId(),  
  8.                     destAddr,  
  9.                     getMultipartMessageText(parts),  
  10.                     deliveryIntents != null && deliveryIntents.size() > 0,  
  11.                     callingPkg);  
  12.         }  
  13.     } else {  
  14.         moveToOutbox(getSubId(), messageUri, callingPkg);  
  15.     }  
  16.     int refNumber = getNextConcatenatedRef() & 0x00FF;  
  17.     int msgCount = parts.size();  
  18.     int encoding = SmsConstants.ENCODING_UNKNOWN;  
  19.   
  20.   
  21.     TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];  
  22.     for (int i = 0; i < msgCount; i++) {  
  23.         TextEncodingDetails details = calculateLength(parts.get(i), false);  
  24.         if (encoding != details.codeUnitSize  
  25.                 && (encoding == SmsConstants.ENCODING_UNKNOWN  
  26.                     || encoding == SmsConstants.ENCODING_7BIT)) {  
  27.             encoding = details.codeUnitSize;  
  28.                     }  
  29.         encodingForParts[i] = details;  
  30.     }  
  31.   
  32.   
  33.     // States to track at the message level (for all parts)  
  34.     final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);  
  35.     final AtomicBoolean anyPartFailed = new AtomicBoolean(false);  
  36.   
  37.   
  38.     for (int i = 0; i < msgCount; i++) {  
  39.         SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();  
  40.         concatRef.refNumber = refNumber;  
  41.         concatRef.seqNumber = i + 1;  // 1-based sequence  
  42.         concatRef.msgCount = msgCount;  
  43.         // TODO: We currently set this to true since our messaging app will never  
  44.         // send more than 255 parts (it converts the message to MMS well before that).  
  45.         // However, we should support 3rd party messaging apps that might need 16-bit  
  46.         // references  
  47.         // Note:  It's not sufficient to just flip this bit to true; it will have  
  48.         // ripple effects (several calculations assume 8-bit ref).  
  49.         concatRef.isEightBits = true;  
  50.         SmsHeader smsHeader = new SmsHeader();  
  51.         smsHeader.concatRef = concatRef;  
  52.   
  53.   
  54.         // Set the national language tables for 3GPP 7-bit encoding, if enabled.  
  55.         if (encoding == SmsConstants.ENCODING_7BIT) {  
  56.             smsHeader.languageTable = encodingForParts[i].languageTable;  
  57.             smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;  
  58.         }  
  59.   
  60.   
  61.         PendingIntent sentIntent = null;  
  62.         if (sentIntents != null && sentIntents.size() > i) {  
  63.             sentIntent = sentIntents.get(i);  
  64.         }  
  65.   
  66.   
  67.         PendingIntent deliveryIntent = null;  
  68.         if (deliveryIntents != null && deliveryIntents.size() > i) {  
  69.             deliveryIntent = deliveryIntents.get(i);  
  70.         }  
  71.   
  72.   
  73.         //逐条发送  
  74.         sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding,  
  75.                 sentIntent, deliveryIntent, (i == (msgCount - 1)),  
  76.                 unsentPartCount, anyPartFailed, messageUri);  
  77.     }  
  78. }  
        在上面的过程中我们看到,对于运营商支持的长短信情况, 需要把拆分出来的短信分别加上短信头编码 ,也就是SmsHeader,然后分别调用sendNewSubmitPdu()方法进行发送。
        这里需要简单介绍以下SmsHeader作用, 普通的短信中SmsHeader为空,所以只有长短信才会有该数据 。他内部确定了该长短信分组的大小、每个分组的索引、编码格式等信息。
        接下来看sendNewSubmitPdu()的过程,这个方法是在GsmSMSDispatcher中实现的:
[java]  view plain  copy
  1. 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) {  
  2.     //对短信内容进行编码  
  3.     SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress,  
  4.             message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader),  
  5.             encoding, smsHeader.languageTable, smsHeader.languageShiftTable);  
  6.     if (pdu != null) {  
  7.         HashMap map =  getSmsTrackerMap(destinationAddress, scAddress, message, pdu);  
  8.         //发送  
  9.         SmsTracker tracker = getSmsTracker(map, sentIntent,  
  10.                 deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri,  
  11.                 smsHeader, !lastPart);  
  12.         sendRawPdu(tracker);  
  13.     } else {  
  14.         Rlog.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null");  
  15.     }  
  16. }  
        接下来的流程和普通短信一样,最终通过RILJ将短信发送出去,并且注册回调消息为EVENT_SEND_SMS_COMPLETE。
        也就是说, 对于长短信而言,如果运营商不支持,那么就拆分为一个个普通短信然后逐条发送,如果运营商支持长短信,则会对每个分组短信添加SmsHeader的信息头,然后逐条发送。

        所以当SMSDispatcher接收到EVENT_SEND_SMS_COMPLETE消息时,就说明,无论是普通短信或者长短信,都已经发送完毕。

        以上就是长短信的发送流程。

        多收件人的情况,请见下节介绍。


Source: http://blog.csdn.net/u010961631/article/details/50272729

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值