我们先来看最简单的流程入手分析,即收件人只有一个,而且不是长短信的情况


一、地址有效性检测


        当点击发送按钮时,触发onClick事件:
[java]  view plain  copy
  1. @ComposeMessageActivity.java  
  2. public void onClick(View v) {  
  3.     if ((v == mSendButtonSms || v == mSendButtonMms) && isPreparedForSending()) {  
  4.         //确认发送  
  5.         confirmSendMessageIfNeeded();  
  6.     } else if ((v == mRecipientsPicker)) {  
  7.         launchMultiplePhonePicker();  
  8.     }  
  9. }  
        然后进行 收件人地址信息的确认
[java]  view plain  copy
  1. private void confirmSendMessageIfNeeded() {  
  2.     if (!isRecipientsEditorVisible()) {  
  3.         //当前的收件人编辑框不可见,说明所发送的对象已经存在短信的会话,也说明当前的收件人地址是ok的  
  4.         sendMessage(true);  
  5.         return;  
  6.     }  
  7.     //判断是否为MMS  
  8.     boolean isMms = mWorkingMessage.requiresMms();  
  9.     if (mRecipientsEditor.hasInvalidRecipient(isMms)) {  
  10.         //当前的收件人列表中包含无效地址  
  11.         if (mRecipientsEditor.hasValidRecipient(isMms)) {  
  12.             //当前的收件人列表中有无效地址和有效地址,提示用户是否忽略,只发送有效的地址  
  13.             String title = getResourcesString(R.string.has_invalid_recipient,  
  14.                     mRecipientsEditor.formatInvalidNumbers(isMms));  
  15.             new AlertDialog.Builder(this)  
  16.                 .setTitle(title)  
  17.                 .setMessage(R.string.invalid_recipient_message)  
  18.                 .setPositiveButton(R.string.try_to_send,  
  19.                         new SendIgnoreInvalidRecipientListener())  
  20.                 .setNegativeButton(R.string.no, new CancelSendingListener())  
  21.                 .show();  
  22.         } else {  
  23.             //当前的收件人列表中的地址全部无效,取消发送,提示用户  
  24.             new AlertDialog.Builder(this)  
  25.                 .setTitle(R.string.cannot_send_message)  
  26.                 .setMessage(R.string.cannot_send_message_reason)  
  27.                 .setPositiveButton(R.string.yes, new CancelSendingListener())  
  28.                 .show();  
  29.         }  
  30.     } else {  
  31.         //收件人地址都是有效的,发送  
  32.         ContactList contacts = mRecipientsEditor.constructContactsFromInput(false);  
  33.         mDebugRecipients = contacts.serialize();  
  34.         sendMessage(true);  
  35.     }  
  36. }  
        经过地址有效性检测后,通过sendMessage()继续流程,这里传递的bCheckEcmMode参数代表是否检查当前Phone的状态, 处于紧急状态时无法发送短信:
[java]  view plain  copy
  1. private void sendMessage(boolean bCheckEcmMode) {  
  2.     if (bCheckEcmMode) {  
  3.         //判断当前是否为紧急呼叫模式  
  4.         String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);  
  5.         if (Boolean.parseBoolean(inEcm)) {  
  6.             try {  
  7.                 //紧急状态下,无法发送短彩信  
  8.                 startActivityForResult( new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null), REQUEST_CODE_ECM_EXIT_DIALOG);  
  9.                 return;  
  10.             } catch (ActivityNotFoundException e) {  
  11.                 Log.e(TAG, "Cannot find EmergencyCallbackModeExitDialog", e);  
  12.             }  
  13.         }  
  14.     }  
  15.     //判断当前是否有短信正在发送  
  16.     if (!mSendingMessage) {  
  17.         //重置收件人控件的监听器  
  18.         removeRecipientsListeners();  
  19.         //进入WorkingMessage处理流程  
  20.         mWorkingMessage.send(mDebugRecipients);  
  21.   
  22.   
  23.         mSentMessage = true;  
  24.         mSendingMessage = true;  
  25.         addRecipientsListeners();  
  26.   
  27.   
  28.         mScrollOnSend = true;   // in the next onQueryComplete, scroll the list to the end.  
  29.     }  
  30.     // But bail out if we are supposed to exit after the message is sent.  
  31.     if (mSendDiscreetMode) {  
  32.         finish();  
  33.     }  
  34. }  


二、创建短彩信的发送线程


        在sendMessage()中经过对当前紧急服务的处理,然后判断如果当前没有短信正在发送,则通过WorkingMessage发送短信。这里的WorkingMessage是处理当前所编辑的信息的工具类,没有父类,在ComposeMessageActivity界面被创建时或者短信被发送出去时创建, 主要负责区分短彩信的流程以及发送短信时UI的更新
[java]  view plain  copy
  1. @WorkingMessage.java  
  2. public void send(final String recipientsInUI) {  
  3.     long origThreadId = mConversation.getThreadId();  
  4.     removeSubjectIfEmpty(true /* notify */);  
  5.     prepareForSave(true /* notify */);  
  6.   
  7.   
  8.     //拿到当前的会话  
  9.     final Conversation conv = mConversation;  
  10.     String msgTxt = mText.toString();  
  11.   
  12.   
  13.     if (requiresMms() || addressContainsEmailToMms(conv, msgTxt)) {  
  14.         //彩信发送  
  15.         if (MmsConfig.getUaProfUrl() == null) {  
  16.             String err = "WorkingMessage.send MMS sending failure. mms_config.xml is " +  
  17.                 "missing uaProfUrl setting.  uaProfUrl is required for MMS service, " +  
  18.                 "but can be absent for SMS.";  
  19.             RuntimeException ex = new NullPointerException(err);  
  20.             Log.e(TAG, err, ex);  
  21.             // now, let's just crash.  
  22.             throw ex;  
  23.         }  
  24.         final Uri mmsUri = mMessageUri;  
  25.         final PduPersister persister = PduPersister.getPduPersister(mActivity);  
  26.   
  27.   
  28.         final SlideshowModel slideshow = mSlideshow;  
  29.         final CharSequence subject = mSubject;  
  30.         final boolean textOnly = mAttachmentType == TEXT;  
  31.   
  32.   
  33.   
  34.   
  35.         //彩信发送线程  
  36.         new Thread(new Runnable() {  
  37.             @Override  
  38.             public void run() {  
  39.                 final SendReq sendReq = makeSendReq(conv, subject);  
  40.                 slideshow.prepareForSend();  
  41.                 sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, textOnly);  
  42.                 updateSendStats(conv);  
  43.             }  
  44.         }, "WorkingMessage.send MMS").start();  
  45.     } else {  
  46.         //短信发送流程  
  47.         final String msgText = mText.toString();  
  48.         new Thread(new Runnable() {  
  49.             @Override  
  50.             public void run() {  
  51.                 preSendSmsWorker(conv, msgText, recipientsInUI);  
  52.   
  53.   
  54.                 updateSendStats(conv);  
  55.             }  
  56.         }, "WorkingMessage.send SMS").start();  
  57.     }  
  58.   
  59.   
  60.     // update the Recipient cache with the new to address, if it's different  
  61.     RecipientIdCache.updateNumbers(conv.getThreadId(), conv.getRecipients());  
  62.     // Mark the message as discarded because it is "off the market" after being sent.  
  63.     mDiscarded = true;  
  64. }  
        在上面的send流程中,WorkingMessage对短彩信进行分类, 分别创建子线程进行发送,本节我们只关注短信流程,他是在preSendSmsWorker()中被发送的:
[java]  view plain  copy
  1. private void preSendSmsWorker(Conversation conv, String msgText, String recipientsInUI) {  
  2.     UserHappinessSignals.userAcceptedImeText(mActivity);  
  3.     //UI刷新  
  4.     mStatusListener.onPreMessageSent();  
  5.     //获取初始的线程ID  
  6.     long origThreadId = conv.getThreadId();  
  7.     //获取分配的线程ID  
  8.     long threadId = conv.ensureThreadId();  
  9.     String semiSepRecipients = conv.getRecipients().serialize();  
  10.   
  11.   
  12.     // recipientsInUI can be empty when the user types in a number and hits send  
  13.     if (LogTag.SEVERE_WARNING && ((origThreadId != 0 && origThreadId != threadId) || (!semiSepRecipients.equals(recipientsInUI) && !TextUtils.isEmpty(recipientsInUI)))) {  
  14.     }else {  
  15.         //发送短信  
  16.         sendSmsWorker(msgText, semiSepRecipients, threadId);  
  17.         //删除草稿  
  18.         deleteDraftSmsMessage(threadId);  
  19.     }  
  20. }  

        在上面的preSendSmsWorker中进行了四个处理:

            1、更新UI(更新编辑框等控件);

            2、获取当前发送的ThreadID;

            3、发送短信;

            4、删除草稿;

        接下来我们继续来看发送的过程:
[java]  view plain  copy
  1. private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId) {  
  2.     //获取当前发送的收件人地址  
  3.     String[] dests = TextUtils.split(semiSepRecipients, ";");  
  4.     //获取MessageSender对象,传递进去4个参数分别为:收件人、信息文本、当前的threadId、SimID。  
  5.     MessageSender sender = new SmsMessageSender(mActivity, dests, msgText, threadId);  
  6.     try {  
  7.         //通过MessageSender发送出去  
  8.         sender.sendMessage(threadId);  
  9.         // Make sure this thread isn't over the limits in message count  
  10.         Recycler.getSmsRecycler().deleteOldMessagesByThreadId(mActivity, threadId);  
  11.     } catch (Exception e) {  
  12.         Log.e(TAG, "Failed to send SMS message, threadId=" + threadId, e);  
  13.     }  
  14.     //更新UI  
  15.     mStatusListener.onMessageSent();  
  16.     MmsWidgetProvider.notifyDatasetChanged(mActivity);  
  17. }  

        经过上面WorkingMessage的sendSmsWorker过程,创建了MessageSender对象,并通过该对象的sendMessage()方法将信息发送出去,并在发送之后再次更新UI界面(正在发送中)。


三、通过SmsMessageSender拆分多个收件人


        上面创建的MessageSender对象,继承自MessageSender接口,主要方法只有三个:
[java]  view plain  copy
  1. public boolean sendMessage(long token) throws MmsException {};  
  2. private boolean queueMessage(long token) throws MmsException {};  
  3. private String getOutgoingServiceCenter(long threadId) {};  
        他的主要作用就是 对当前收件人信息拆分后,把群发的短信构建成一个短信队列并保存在数据库中,然后通知SmsReceiverService将队列读取出来并发送出去。
        下面来看其具体实现过程。
[java]  view plain  copy
  1. @SmsMessageSender.java  
  2. public boolean sendMessage(long token) throws MmsException {  
  3.     return queueMessage(token);  
  4. }  
  5. private boolean queueMessage(long token) throws MmsException {  
  6.     if ((mMessageText == null) || (mNumberOfDests == 0)) {  
  7.         //空信息不能发送  
  8.         throw new MmsException("Null message body or dest.");  
  9.     }  
  10.   
  11.   
  12.     SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);  
  13.     boolean requestDeliveryReport = prefs.getBoolean(  
  14.             MessagingPreferenceActivity.SMS_DELIVERY_REPORT_MODE,  
  15.             DEFAULT_DELIVERY_REPORT_MODE);  
  16.   
  17.   
  18.     //根据当前短信的收件人数目,遍历当前的发送队列  
  19.     for (int i = 0; i < mNumberOfDests; i++) {  
  20.         try {  
  21.             //将当前要发送的短消息放入发送队列中  
  22.             Sms.addMessageToUri(mContext.getContentResolver(),  
  23.                     Uri.parse("content://sms/queued"), mDests[i],  
  24.                     mMessageText, null, mTimestamp,  
  25.                     true /* read */,  
  26.                     requestDeliveryReport,  
  27.                     mThreadId);  
  28.         } catch (SQLiteException e) {  
  29.             if (LogTag.DEBUG_SEND) {  
  30.                 Log.e(TAG, "queueMessage SQLiteException", e);  
  31.             }  
  32.             SqliteWrapper.checkSQLiteException(mContext, e);  
  33.         }  
  34.     }  
  35.     //通知SmsReceiverService发送短信  
  36.     mContext.sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,  
  37.                 null,  
  38.                 mContext,  
  39.                 SmsReceiver.class));  
  40.     return false;  
  41. }  
        在上面这个过程中,将收件人地址拆分后,生成一个短信队列放入"content://sms/queued"中,然后给SmsReceiver发送了通知,这里的SmsReceiver作用仅仅是将该通知转发给SmsReceiverService而已:
[java]  view plain  copy
  1. @SmsReceiver.java  
  2. public void onReceive(Context context, Intent intent) {  
  3.     onReceiveWithPrivilege(context, intent, false);  
  4. }  
  5. protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {  
  6.     if (!privileged && intent.getAction().equals(Intents.SMS_DELIVER_ACTION)) {  
  7.         return;  
  8.     }  
  9.   
  10.   
  11.     //将请求转交给SmsReceiverService来处理  
  12.     intent.setClass(context, SmsReceiverService.class);  
  13.     intent.putExtra("result", getResultCode());  
  14.     beginStartingService(context, intent);  
  15. }  
        也就是说,SmsMessageSender将要发送的短信放入队列中之后,经过SmsReceiver将该消息发送给了SmsReceiverService, 这里的SmsReceiverService是负责短信的收发的Service。
        下面来看SmsReceiverService对于发送短消息的处理过程。
        这个Service被创建时,会创建一个子线程(HandlerThread)以及该线程的Handler对象(ServiceHandler):
[java]  view plain  copy
  1. @SmsReceiverService.java  
  2. public void onCreate() {  
  3.     //创建子线程处理各种消息  
  4.     HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);  
  5.     thread.start();  
  6.   
  7.   
  8.     mServiceLooper = thread.getLooper();  
  9.     mServiceHandler = new ServiceHandler(mServiceLooper);  
  10. }  
        当该Service被启动时,就会对当前的请求进行处理:
[java]  view plain  copy
  1. public int onStartCommand(Intent intent, int flags, int startId) {  
  2.     mResultCode = intent != null ? intent.getIntExtra("result"0) : 0;  
  3.     //通知Handler处理当前的请求  
  4.     Message msg = mServiceHandler.obtainMessage();  
  5.     msg.arg1 = startId;  
  6.     msg.obj = intent;  
  7.     mServiceHandler.sendMessage(msg);  
  8.     return Service.START_NOT_STICKY;  
  9. }  
        然后看当前Handler的处理: [java]  view plain  copy
  1. private final class ServiceHandler extends Handler {  
  2.     public ServiceHandler(Looper looper) {  
  3.         super(looper);  
  4.     }  
  5.     @Override  
  6.     public void handleMessage(Message msg) {  
  7.         int serviceId = msg.arg1;  
  8.         Intent intent = (Intent)msg.obj;  
  9.         if (intent != null && MmsConfig.isSmsEnabled(getApplicationContext())) {  
  10.             String action = intent.getAction();  
  11.             int error = intent.getIntExtra("errorCode"0);  
  12.   
  13.   
  14.             if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {  
  15.                 handleSmsSent(intent, error);  
  16.             } else if (SMS_DELIVER_ACTION.equals(action)) {  
  17.                 handleSmsReceived(intent, error);  
  18.             } else if (ACTION_BOOT_COMPLETED.equals(action)) {  
  19.                 handleBootCompleted();  
  20.             } else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {  
  21.                 handleServiceStateChanged(intent);  
  22.             } else if (ACTION_SEND_MESSAGE.endsWith(action)) {  
  23.                 //发送短信  
  24.                 handleSendMessage();  
  25.             } else if (ACTION_SEND_INACTIVE_MESSAGE.equals(action)) {  
  26.                 handleSendInactiveMessage();  
  27.             }  
  28.         }  
  29.         SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);  
  30.     }  
  31. }  
        从上面的case分支中我们看到,对于当前的发送短信的请求( ACTION_SEND_MESSAGE)将会通过handleSendMessage()来处理: [java]  view plain  copy
  1. private void handleSendMessage() {  
  2.     if (!mSending) {  
  3.         //当前没有其他任务时就触发发送的操作  
  4.         sendFirstQueuedMessage();  
  5.     }  
  6. }  
  7. public synchronized void sendFirstQueuedMessage() {  
  8.     boolean success = true;  
  9.     final Uri uri = Uri.parse("content://sms/queued");  
  10.     ContentResolver resolver = getContentResolver();  
  11.     //从队列中拿到要发送的短信  
  12.     Cursor c = SqliteWrapper.query(this, resolver, uri, SEND_PROJECTION, nullnull"date ASC");  
  13.     if (c != null) {  
  14.         try {  
  15.             //发送队列中第一条短信  
  16.             if (c.moveToFirst()) {  
  17.                 String msgText = c.getString(SEND_COLUMN_BODY);  
  18.                 String address = c.getString(SEND_COLUMN_ADDRESS);  
  19.                 int threadId = c.getInt(SEND_COLUMN_THREAD_ID);  
  20.                 int status = c.getInt(SEND_COLUMN_STATUS);  
  21.                 int msgId = c.getInt(SEND_COLUMN_ID);  
  22.                 Uri msgUri = ContentUris.withAppendedId(Sms.CONTENT_URI, msgId);  
  23.                 //构建SmsSingleRecipientSender对象  
  24.                 SmsMessageSender sender = new SmsSingleRecipientSender(this,  
  25.                         address, msgText, threadId, status == Sms.STATUS_PENDING,  
  26.                         msgUri);  
  27.   
  28.   
  29.                 try {  
  30.                     //发送  
  31.                     sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;  
  32.                     mSending = true;  
  33.                 } catch (MmsException e) {  
  34.                     mSending = false;  
  35.                     messageFailedToSend(msgUri, SmsManager.RESULT_ERROR_GENERIC_FAILURE);  
  36.                     success = false;  
  37.                     sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,  
  38.                             null,  
  39.                             this,  
  40.                             SmsReceiver.class));  
  41.                 }  
  42.             }  
  43.         } finally {  
  44.             c.close();  
  45.         }  
  46.     }  
  47.     if (success) {  
  48.         unRegisterForServiceStateChanges();  
  49.     }  
  50. }  

        我们看到,经过SmsReceiverService中Handler的处理,将数据库中的当前要发送的短信队列取出来,然后取出队列中第一个短消息任务,通过SmsSingleRecipientSender的sendMessage()方法发送出去。至此SmsReceiverService的流程就走完了,他的作用主要就是拿到队列中的第一条短消息,构建SmsSingleRecipientSender对象并发送出去


四、通过SmsSingleRecipientSender拆分长短信


        SmsSingleRecipientSender类继承自SmsMessageSender,他所提供的方法只有一个:
[java]  view plain  copy
  1. public boolean sendMessage(long token) throws MmsException {};  
        其处理内容就是对长短消息进行分割。然后注册两个广播(一个用于广播当前正在发送,另一个广播短信的送达状态报告),之后通过SmsManager发送出去。 [java]  view plain  copy
  1. @SmsSingleRecipientSender.java  
  2. public boolean sendMessage(long token) throws MmsException {  
  3.     if (mMessageText == null) {  
  4.         throw new MmsException("Null message body or have multiple destinations.");  
  5.     }  
  6.     SmsManager smsManager = SmsManager.getDefault();  
  7.     ArrayList messages = null;  
  8.     //拆分长短信  
  9.     if ((MmsConfig.getEmailGateway() != null) && (Mms.isEmailAddress(mDest) || MessageUtils.isAlias(mDest))) {  
  10.         //彩信  
  11.         String msgText;  
  12.         msgText = mDest + " " + mMessageText;  
  13.         mDest = MmsConfig.getEmailGateway();  
  14.         messages = smsManager.divideMessage(msgText);  
  15.     } else {  
  16.         //短信  
  17.         messages = smsManager.divideMessage(mMessageText);  
  18.         mDest = PhoneNumberUtils.stripSeparators(mDest);  
  19.         mDest = Conversation.verifySingleRecipient(mContext, mThreadId, mDest);  
  20.     }  
  21.     int messageCount = messages.size();  
  22.   
  23.   
  24.     if (messageCount == 0) {  
  25.         throw new MmsException("SmsMessageSender.sendMessage: divideMessage returned " + "empty messages. Original message is \"" + mMessageText + "\"");  
  26.     }  
  27.   
  28.   
  29.     boolean moved = Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0);  
  30.     if (!moved) {  
  31.         throw new MmsException("SmsMessageSender.sendMessage: couldn't move message " + "to outbox: " + mUri);  
  32.     }  
  33.     ArrayList deliveryIntents =  new ArrayList(messageCount);  
  34.     ArrayList sentIntents = new ArrayList(messageCount);  
  35.     for (int i = 0; i < messageCount; i++) {  
  36.         if (mRequestDeliveryReport && (i == (messageCount - 1))) {  
  37.             //所有短信被发送完毕后,在最后一条短信后面添加送达报告的Intent  
  38.             deliveryIntents.add(PendingIntent.getBroadcast(  
  39.                         mContext, 0,  
  40.                         new Intent(  
  41.                             MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,  
  42.                             mUri,  
  43.                             mContext,  
  44.                             MessageStatusReceiver.class),  
  45.                         0));  
  46.         } else {  
  47.             deliveryIntents.add(null);  
  48.         }  
  49.         //对于拆分后的短消息,需要在每条信息发送完毕后发送该Intent,从而接着发送剩下的拆分短信  
  50.         Intent intent  = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,  
  51.                 mUri,  
  52.                 mContext,  
  53.                 SmsReceiver.class);  
  54.   
  55.   
  56.         int requestCode = 0;  
  57.         if (i == messageCount -1) {  
  58.             //收到该附加数据说明当前的拆分短信已经发送完毕  
  59.             requestCode = 1;  
  60.             intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true);  
  61.         }  
  62.         sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0));  
  63.     }  
  64.     try {  
  65.         //发送  
  66.         smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);  
  67.     } catch (Exception ex) {  
  68.         throw new MmsException("SmsMessageSender.sendMessage: caught " + ex + " from SmsManager.sendTextMessage()");  
  69.     }  
  70.     return false;  
  71. }  
        经过上面的准备过程,在通过SmsManager发送信息之前,还添加了两个Intent:SmsReceiverService.MESSAGE_SENT_ACTION和MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION。这两个Intent的作用分别是:
         MESSAGE_STATUS_RECEIVED_ACTION:当所有长短信(或短消息)发送完毕后,发送该Intent。
         MESSAGE_SENT_ACTION:分割后的短消息,每发送一条,都会发送该Intent, 当最后一条发送完毕后,将会在该Intent中附加EXTRA_MESSAGE_SENT_SEND_NEXT=true的数据
        具体细节在发送完毕后再分析。
        接下来看SmsManager,这里的SmsManager是 单例模型,通过其自己的getDefault()或者getSmsManagerForSubscriber()方法就可以得到该对象。 [java]  view plain  copy
  1. @SmsManager.java  
  2. public void sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList parts, ArrayList sentIntents, ArrayList 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),  
  31.                 sentIntent, deliveryIntent);  
  32.     }  
  33. }  
        在上面的流程中 区分了长短信和普通短信的流程,我们目前只分析普通短消息,继续看sendTextMessage(): [java]  view plain  copy
  1. public void sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {  
  2.     if (TextUtils.isEmpty(destinationAddress)) {  
  3.         throw new IllegalArgumentException("Invalid destinationAddress");  
  4.     }  
  5.   
  6.   
  7.     if (TextUtils.isEmpty(text)) {  
  8.         throw new IllegalArgumentException("Invalid message body");  
  9.     }  
  10.   
  11.   
  12.     try {  
  13.         //继续  
  14.         ISms iccISms = getISmsServiceOrThrow();  
  15.         iccISms.sendText(ActivityThread.currentPackageName(), destinationAddress, scAddress, text, sentIntent, deliveryIntent);  
  16.     } catch (RemoteException ex) {  
  17.     }  
  18. }  

        到这里,SmsMessage通过调用iccISms对象的sendText()方法将短信继续传递,而SmsMessage的流程就此结束。


五、发送单条短信


        上面的iccISms对象是UiccSmsController的客户端:
[java]  view plain  copy
  1. private static ISms getISmsService() {  
  2.     return ISms.Stub.asInterface(ServiceManager.getService("isms"));  
  3. }  
        所以接下来我们需要进入UiccSmsController的流程中分析:
[java]  view plain  copy
  1. @UiccSmsController.java  
  2. public void sendText(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {  
  3.     sendTextForSubscriber(getPreferredSmsSubscription(), callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent);  
  4. }  
  5. public void sendTextForSubscriber(long subId, String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {  
  6.     IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);  
  7.     if (iccSmsIntMgr != null) {  
  8.         //通过IccSmsInterfaceManager发送短信  
  9.         iccSmsIntMgr.sendText(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent);  
  10.     } else {  
  11.     }  
  12. }  
        在上面的UiccSmsController中将任务交给IccSmsInterfaceManager来继续处理。
        IccSmsInterfaceManager这个类没有父类,他在创建PhoneProxy的时候进行初始化,其 作用是把请求发送给相应的处理者。比如对于sendText()将会转交给ImsSMSDispatcher来实现。 [java]  view plain  copy
  1. @IccSmsInterfaceManager.java  
  2. public void sendText(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {  
  3.     //是否声明了发短信的权限  
  4.     mPhone.getContext().enforceCallingPermission( Manifest.permission.SEND_SMS, "Sending SMS message");  
  5.     //该操作是否被用户允许  
  6.     if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) {  
  7.         return;  
  8.     }  
  9.     //调用ImsSMSDispatcher发送  
  10.     destAddr = filterDestAddress(destAddr);  
  11.     mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, null, callingPackage);  
  12. }  
        在上面这个过程中,先进行两级权限检查,然后通过ImsSMSDispatcher发送信息。
        SMSDispatcher总共派生出三个子类:CdmaSMSDispatcher、GsmSMSDispatcher、ImsSMSDispatcher,在IccSmsInterfaceManager创建时只创建ImsSMSDispatcher,而在ImsSMSDispatcher创建过程中会对创建其他两种制式的SMSDispatcher,IccSmsInterfaceManager把请求发送给ImsSMSDispatcher后,由ImsSMSDispatcher根据当前网络状态选择使用CdmaSMSDispatcher还是GsmSMSDispatcher。 [java]  view plain  copy
  1. @ImsSMSDispatcher.java  
  2. protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg) {  
  3.     //根据当前网络类型发送,我们只分析GSM  
  4.     if (isCdmaMo()) {  
  5.         mCdmaDispatcher.sendText(destAddr, scAddr,  
  6.                 text, sentIntent, deliveryIntent, messageUri, callingPkg);  
  7.     } else {  
  8.         mGsmDispatcher.sendText(destAddr, scAddr,  
  9.                 text, sentIntent, deliveryIntent, messageUri, callingPkg);  
  10.     }  
  11. }  
        在上面的过程中,根据当前网络环境使用不同的SMSDispatcher,对于GSM网络来说,当前使用的是GsmSMSDispatcher对象。
        这是Framework层与RILJ最接近的对象,他将请求发送给RILJ。 [java]  view plain  copy
  1. @GsmSMSDispatcher.java  
  2. protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg) {  
  3.     //对短信内容进行编码  
  4.     SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( scAddr, destAddr, text, (deliveryIntent != null));  
  5.     if (pdu != null) {  
  6.         if (messageUri == null) {  
  7.             if (SmsApplication.shouldWriteMessageForPackage(callingPkg, mContext)) {  
  8.                 //写入发件箱  
  9.                 messageUri = writeOutboxMessage(  
  10.                         getSubId(),  
  11.                         destAddr,  
  12.                         text,  
  13.                         deliveryIntent != null,  
  14.                         callingPkg);  
  15.             }  
  16.         } else {  
  17.             //移到发件箱  
  18.             moveToOutbox(getSubId(), messageUri, callingPkg);  
  19.         }  
  20.         HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);  
  21.         //发送  
  22.         SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(), messageUri, false);  
  23.         sendRawPdu(tracker);  
  24.     } else {  
  25.     }  
  26. }  
        在上面的过程中,对短消息内容进行编码,然后把短消息写入(或移入)发件箱,然后利用当前的发地址、收地址、文本、附加Intent等信息创建SmsTracker对象,然后调用sendRawPdu(),这个方法是在GsmSMSDispatcher的父类SMSDispatcher中实现的: [java]  view plain  copy
  1. @SMSDispatcher.java  
  2. protected void sendRawPdu(SmsTracker tracker) {  
  3.     HashMap map = tracker.mData;  
  4.     byte pdu[] = (byte[]) map.get("pdu");  
  5.   
  6.   
  7.     if (mSmsSendDisabled) {  
  8.         tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);  
  9.         return;  
  10.     }  
  11.     if (pdu == null) {  
  12.         tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/);  
  13.         return;  
  14.     }  
  15.     PackageManager pm = mContext.getPackageManager();  
  16.     String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());  
  17.   
  18.   
  19.     if (packageNames == null || packageNames.length == 0) {  
  20.         // Refuse to send SMS if we can't get the calling package name.  
  21.         tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);  
  22.         return;  
  23.     }  
  24.   
  25.   
  26.     // Get package info via packagemanager  
  27.     PackageInfo appInfo;  
  28.     try {  
  29.         // XXX this is lossy- apps can share a UID  
  30.         appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);  
  31.     } catch (PackageManager.NameNotFoundException e) {  
  32.         Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");  
  33.         tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);  
  34.         return;  
  35.     }  
  36.   
  37.   
  38.     // checkDestination() returns true if the destination is not a premium short code or the  
  39.     // sending app is approved to send to short codes. Otherwise, a message is sent to our  
  40.     // handler with the SmsTracker to request user confirmation before sending.  
  41.     if (checkDestination(tracker)) {  
  42.         // check for excessive outgoing SMS usage by this app  
  43.         if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {  
  44.             sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));  
  45.             return;  
  46.         }  
  47.         //发送  
  48.         sendSms(tracker);  
  49.     }  
  50. }  
        这里会对要发送的信息以及当前环境进行检测,然后进入sendSms()流程,这个方法又回到了GsmSMSDispatcher中实现: [java]  view plain  copy
  1. @GsmSMSDispatcher.java  
  2. protected void sendSms(SmsTracker tracker) {  
  3.     HashMap map = tracker.mData;  
  4.     byte pdu[] = (byte[]) map.get("pdu");  
  5.   
  6.   
  7.     if (tracker.mRetryCount > 0) {  
  8.         // per TS 23.040 Section 9.2.3.6:  If TP-MTI SMS-SUBMIT (0x01) type  
  9.         //   TP-RD (bit 2) is 1 for retry  
  10.         //   and TP-MR is set to previously failed sms TP-MR  
  11.         if (((0x01 & pdu[0]) == 0x01)) {  
  12.             pdu[0] |= 0x04// TP-RD  
  13.             pdu[1] = (byte) tracker.mMessageRef; // TP-MR  
  14.         }  
  15.     }  
  16.   
  17.   
  18.     // Send SMS via the carrier app.  
  19.     BroadcastReceiver resultReceiver = new SMSDispatcherReceiver(tracker);  
  20.   
  21.   
  22.     Intent intent = new Intent(Intents.SMS_SEND_ACTION);  
  23.     String carrierPackage = getCarrierAppPackageName(intent);  
  24.     if (carrierPackage != null) {  
  25.         intent.setPackage(carrierPackage);  
  26.         intent.putExtra("pdu", pdu);  
  27.         intent.putExtra("smsc", (byte[]) map.get("smsc"));  
  28.         intent.putExtra("format", getFormat());  
  29.         if (tracker.mSmsHeader != null && tracker.mSmsHeader.concatRef != null) {  
  30.             SmsHeader.ConcatRef concatRef = tracker.mSmsHeader.concatRef;  
  31.             intent.putExtra("concat.refNumber", concatRef.refNumber);  
  32.             intent.putExtra("concat.seqNumber", concatRef.seqNumber);  
  33.             intent.putExtra("concat.msgCount", concatRef.msgCount);  
  34.         }  
  35.         intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);  
  36.         Rlog.d(TAG, "Sending SMS by carrier app.");  
  37.         mContext.sendOrderedBroadcast(intent, android.Manifest.permission.RECEIVE_SMS,  
  38.                 AppOpsManager.OP_RECEIVE_SMS, resultReceiver,  
  39.                 null, Activity.RESULT_CANCELED, nullnull);  
  40.     } else {  
  41.         //发送  
  42.         sendSmsByPstn(tracker);  
  43.     }  
  44. }  
        然后来看sendSmsByPstn(): [java]  view plain  copy
  1. protected void sendSmsByPstn(SmsTracker tracker) {  
  2.     int ss = mPhone.getServiceState().getState();  
  3.     if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {  
  4.         tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);  
  5.         return;  
  6.     }  
  7.     //拿到SmsTracker中保存的信息  
  8.     HashMap map = tracker.mData;  
  9.   
  10.   
  11.     byte smsc[] = (byte[]) map.get("smsc");  
  12.     byte[] pdu = (byte[]) map.get("pdu");  
  13.     Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);  
  14.   
  15.   
  16.     if (0 == tracker.mImsRetry && !isIms()) {  
  17.         if (tracker.mRetryCount > 0) {  
  18.             if (((0x01 & pdu[0]) == 0x01)) {  
  19.                 pdu[0] |= 0x04// TP-RD  
  20.                 pdu[1] = (byte) tracker.mMessageRef; // TP-MR  
  21.             }  
  22.         }  
  23.         if (tracker.mRetryCount == 0 && tracker.mExpectMore) {  
  24.             //调用RILJ发送短信  
  25.             mCi.sendSMSExpectMore(IccUtils.bytesToHexString(smsc),  
  26.                     IccUtils.bytesToHexString(pdu), reply);  
  27.         } else {  
  28.             mCi.sendSMS(IccUtils.bytesToHexString(smsc),  
  29.                     IccUtils.bytesToHexString(pdu), reply);  
  30.         }  
  31.     } else {  
  32.         //通过IMS发送短信  
  33.         mCi.sendImsGsmSms(IccUtils.bytesToHexString(smsc),  
  34.                 IccUtils.bytesToHexString(pdu), tracker.mImsRetry,  
  35.                 tracker.mMessageRef, reply);  
  36.         // increment it here, so in case of SMS_FAIL_RETRY over IMS  
  37.         // next retry will be sent using IMS request again.  
  38.         tracker.mImsRetry++;  
  39.     }  
  40. }  
        在上面的发送之前,将SmsTracker中的内容解析出来,通过RILJ发送出去。并且注册了该请求的回应消息EVENT_SEND_SMS_COMPLETE,用于处理短信接收时的流程。

        以上就是普通单收件人,短信的发送流程。

        整个过程的流程图如下:


        下一节来介绍长短信的发送流程


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

更多相关文章

  1. 读取android手机流量信息
  2. Android(安卓)bluetooth介绍(四): a2dp connect流程分析
  3. android用户界面-组件Widget-地图视图MapView
  4. android打电话发短信
  5. Android(安卓)开发中的倒计时
  6. [APP] Android(安卓)开发笔记 006-使用短信验证SDK进行短信验证
  7. android studio升级方法
  8. android adb工具
  9. Android学习笔记_79_ Android(安卓)使用 搜索框

随机推荐

  1. Android笔记(一):Android工程目录介绍
  2. Android使用Ant多渠道打包
  3. Android(安卓)程序开发的插件化 模块化方
  4. Android(安卓)学习资料收集汇总
  5. 微软新应用:Android移植到Windows Phone
  6. Android(安卓)Studio keymap到Eclipse后,
  7. android实现连连看,附源码
  8. [Android] SurfaceView使用实例
  9. Android(安卓)Google Map实例 - 获取cdma
  10. Android(安卓)加解密类Cipher