前面的《
Android短信发送流程之长短信发送
》中介绍了长短信对于普通短信的区别,而对于多收件人的情况,在SmsMessageSender的queueMessage()方法中我们了解到,发送之前,将多收件人的短信进行拆分,放入"content://sms/queued"队列中,在接下来的流程中,将会在SmsReceiverService中通过sendFirstQueuedMessage()方法取出队列中的第一条短信并发送,那么,队列中的其他消息是如何被发送出去的呢?
我们从第一条短信发送完毕后的流程来寻找答案。
由于在GsmSMSDispatcher向RILJ发送消息时所注册的回应消息是EVENT_SEND_SMS_COMPLETE,所以当短信发送成功时,就会收到该消息的回应。
在SMSDispatcher中对该回应进行处理:
然后进入handleSendComplete()方法中处理:
在上面的过程中,对短信发送的结果进行区分,如果失败,将会根据失败原因通知SmsTracker,如果成功,将会进入SmsTracker中继续处理:
由于此时无论是长短信还是普通短信,都已经发送完毕(只发送了一个收件人),因此isSinglePartOrLastPart的判定将会是true,从而更新数据库中该短信的状态,然后再将发送时附加在SmsTracker中的mSentIntent取出来并发送出去,同时指定返回结果为“Activity.RESULT_OK”。
而这里的mSentIntent就是在SmsSingleRecipientSender中指定的,我们再来回顾以下当时的状态:
从这里我们看到,当前的mSentIntent发送对象是SmsReceiver,内容是MESSAGE_SENT_ACTION,而且包含了附加数据EXTRA_MESSAGE_SENT_SEND_NEXT=true,并且SmsTracker发送该Intent时传送的结果是“Activity.RESULT_OK”。
由于SmsReceiver会把所有Intent转交给SmsReceiverService处理,我们直接来看SmsReceiverService的处理:
对于当前的Intent,将会在handleSmsSent()中处理:
由于当前resultCode=OK,并且sendNextMsg=true,首先会通过Sms.moveMessageToFolder()操作将发送成功的短信从"content://sms/queued"队列移动到"content://sms/sent"队列。
然后在sendFirstQueuedMessage()中继续处理:
在上面的过程中,检测发送队列中是否有未发送的短信,对于多收件人的情况,由于我们之前只发送出去了第一条短信,而且已经将已发送的短信从该队列移出,因此此时的队列中只有其他收件人的短信,然后取出其中的一条,再次进入发送通道,接下来的流程和之前的相同。
我们从第一条短信发送完毕后的流程来寻找答案。
由于在GsmSMSDispatcher向RILJ发送消息时所注册的回应消息是EVENT_SEND_SMS_COMPLETE,所以当短信发送成功时,就会收到该消息的回应。
在SMSDispatcher中对该回应进行处理:
- @SMSDispatcher.java
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_SEND_SMS_COMPLETE:
- //发送成功
- handleSendComplete((AsyncResult) msg.obj);
- break;
- default:
- Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what);
- }
- }
- protected void handleSendComplete(AsyncResult ar) {
- SmsTracker tracker = (SmsTracker) ar.userObj;
- PendingIntent sentIntent = tracker.mSentIntent;
- if (ar.result != null) {
- tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
- } else {
- }
- if (ar.exception == null) {
- //发送成功
- if (tracker.mDeliveryIntent != null) {
- //将当前短信的tracker保存
- deliveryPendingList.add(tracker);
- }
- //回调到SmsTracker内部
- tracker.onSent(mContext);
- } else {
- //发送失败
- }
- }
- public void onSent(Context context) {
- boolean isSinglePartOrLastPart = true;
- if (mUnsentPartCount != null) {
- //判断是否已经将长短新最后一条发送完毕
- isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
- }
- if (isSinglePartOrLastPart) {
- //当前所有短信发送完毕,更新数据库状态
- boolean success = true;
- if (mAnyPartFailed != null && mAnyPartFailed.get()) {
- success = false;
- }
- if (success) {
- setMessageFinalState(context, Sms.MESSAGE_TYPE_SENT);
- } else {
- setMessageFinalState(context, Sms.MESSAGE_TYPE_FAILED);
- }
- }
- //把发送短信之前保存在SmsTracker中的Intent取出来发送出去,通知短信已经发送成功。
- if (mSentIntent != null) {
- try {
- // Extra information to send with the sent intent
- Intent fillIn = new Intent();
- if (mMessageUri != null) {
- // Pass this to SMS apps so that they know where it is stored
- fillIn.putExtra("uri", mMessageUri.toString());
- }
- if (mUnsentPartCount != null && isSinglePartOrLastPart) {
- // Is multipart and last part
- fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
- }
- mSentIntent.send(context, Activity.RESULT_OK, fillIn);
- } catch (CanceledException ex) {
- Rlog.e(TAG, "Failed to send result");
- }
- }
- }
而这里的mSentIntent就是在SmsSingleRecipientSender中指定的,我们再来回顾以下当时的状态:
- @SmsSingleRecipientSender.java
- public boolean sendMessage(long token) throws MmsException {
- if (mMessageText == null) {
- throw new MmsException("Null message body or have multiple destinations.");
- }
- SmsManager smsManager = SmsManager.getDefault();
- ArrayList<String> messages = null;
- //拆分长短信
- if ((MmsConfig.getEmailGateway() != null) && (Mms.isEmailAddress(mDest) || MessageUtils.isAlias(mDest))) {
- //彩信
- String msgText;
- msgText = mDest + " " + mMessageText;
- mDest = MmsConfig.getEmailGateway();
- messages = smsManager.divideMessage(msgText);
- } else {
- //短信
- messages = smsManager.divideMessage(mMessageText);
- mDest = PhoneNumberUtils.stripSeparators(mDest);
- mDest = Conversation.verifySingleRecipient(mContext, mThreadId, mDest);
- }
- int messageCount = messages.size();
- if (messageCount == 0) {
- throw new MmsException("SmsMessageSender.sendMessage: divideMessage returned " + "empty messages. Original message is \"" + mMessageText + "\"");
- }
- boolean moved = Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0);
- if (!moved) {
- throw new MmsException("SmsMessageSender.sendMessage: couldn't move message " + "to outbox: " + mUri);
- }
- ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>(messageCount);
- ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(messageCount);
- for (int i = 0; i < messageCount; i++) {
- if (mRequestDeliveryReport && (i == (messageCount - 1))) {
- //所有短信被发送完毕后,在最后一条短信后面添加送达报告的Intent
- deliveryIntents.add(PendingIntent.getBroadcast(
- mContext, 0,
- new Intent(
- MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,
- mUri,
- mContext,
- MessageStatusReceiver.class),
- 0));
- } else {
- deliveryIntents.add(null);
- }
- //对于拆分后的短消息,需要在每条信息发送完毕后发送该Intent,从而接着发送剩下的拆分短信
- Intent intent = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,
- mUri,
- mContext,
- SmsReceiver.class);
- int requestCode = 0;
- if (i == messageCount -1) {
- //收到该附加数据说明当前的拆分短信已经发送完毕
- requestCode = 1;
- intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true);
- }
- sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0));
- }
- try {
- //发送
- smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);
- } catch (Exception ex) {
- throw new MmsException("SmsMessageSender.sendMessage: caught " + ex + " from SmsManager.sendTextMessage()");
- }
- return false;
- }
由于SmsReceiver会把所有Intent转交给SmsReceiverService处理,我们直接来看SmsReceiverService的处理:
- @SmsReceiverService.java
- public void handleMessage(Message msg) {
- int serviceId = msg.arg1;
- Intent intent = (Intent)msg.obj;
- if (intent != null && MmsConfig.isSmsEnabled(getApplicationContext())) {
- String action = intent.getAction();
- int error = intent.getIntExtra("errorCode", 0);
- if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
- //处理
- handleSmsSent(intent, error);
- } else if (SMS_DELIVER_ACTION.equals(action)) {
- handleSmsReceived(intent, error);
- } else if (ACTION_BOOT_COMPLETED.equals(action)) {
- handleBootCompleted();
- } else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
- handleServiceStateChanged(intent);
- } else if (ACTION_SEND_MESSAGE.endsWith(action)) {
- handleSendMessage();
- } else if (ACTION_SEND_INACTIVE_MESSAGE.equals(action)) {
- handleSendInactiveMessage();
- }
- }
- SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
- }
- private void handleSmsSent(Intent intent, int error) {
- Uri uri = intent.getData();
- mSending = false;
- //EXTRA_MESSAGE_SENT_SEND_NEXT表示是否是长短新的最后一条
- boolean sendNextMsg = intent.getBooleanExtra(EXTRA_MESSAGE_SENT_SEND_NEXT, false);
- if (mResultCode == Activity.RESULT_OK) {
- //将已经发送成功的短信移入发件箱,更新其状态为已发送
- if (!Sms.moveMessageToFolder(this, uri, Sms.MESSAGE_TYPE_SENT, error)) {
- Log.e(TAG, "handleSmsSent: failed to move message " + uri + " to sent folder");
- }
- if (sendNextMsg) {
- //继续发送其他收件人
- sendFirstQueuedMessage();
- }
- // Update the notification for failed messages since they may be deleted.
- MessagingNotification.nonBlockingUpdateSendFailedNotification(this);
- } else if ((mResultCode == SmsManager.RESULT_ERROR_RADIO_OFF) ||
- (mResultCode == SmsManager.RESULT_ERROR_NO_SERVICE)) {
- // We got an error with no service or no radio. Register for state changes so
- // when the status of the connection/radio changes, we can try to send the
- // queued up messages.
- registerForServiceStateChanges();
- // We couldn't send the message, put in the queue to retry later.
- Sms.moveMessageToFolder(this, uri, Sms.MESSAGE_TYPE_QUEUED, error);
- mToastHandler.post(new Runnable() {
- public void run() {
- Toast.makeText(SmsReceiverService.this, getString(R.string.message_queued),
- Toast.LENGTH_SHORT).show();
- }
- });
- } else if (mResultCode == SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE) {
- messageFailedToSend(uri, mResultCode);
- mToastHandler.post(new Runnable() {
- public void run() {
- Toast.makeText(SmsReceiverService.this, getString(R.string.fdn_check_failure),
- Toast.LENGTH_SHORT).show();
- }
- });
- } else {
- messageFailedToSend(uri, error);
- if (sendNextMsg) {
- sendFirstQueuedMessage();
- }
- }
- }
然后在sendFirstQueuedMessage()中继续处理:
- public synchronized void sendFirstQueuedMessage() {
- boolean success = true;
- final Uri uri = Uri.parse("content://sms/queued");
- ContentResolver resolver = getContentResolver();
- Cursor c = SqliteWrapper.query(this, resolver, uri, SEND_PROJECTION, null, null, "date ASC"); // date ASC so we send out in
- if (c != null) {
- try {
- if (c.moveToFirst()) {
- //从队列中取出第一个并发送
- String msgText = c.getString(SEND_COLUMN_BODY);
- String address = c.getString(SEND_COLUMN_ADDRESS);
- int threadId = c.getInt(SEND_COLUMN_THREAD_ID);
- int status = c.getInt(SEND_COLUMN_STATUS);
- int msgId = c.getInt(SEND_COLUMN_ID);
- Uri msgUri = ContentUris.withAppendedId(Sms.CONTENT_URI, msgId);
- SmsMessageSender sender = new SmsSingleRecipientSender(this,
- address, msgText, threadId, status == Sms.STATUS_PENDING,
- msgUri);
- try {
- sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
- mSending = true;
- } catch (MmsException e) {
- mSending = false;
- messageFailedToSend(msgUri, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
- success = false;
- // Sending current message fails. Try to send more pending messages
- // if there is any.
- sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
- null,
- this,
- SmsReceiver.class));
- }
- }
- } finally {
- c.close();
- }
- }
- if (success) {
- // We successfully sent all the messages in the queue. We don't need to
- // be notified of any service changes any longer.
- unRegisterForServiceStateChanges();
- }
- }
这就是多收件人的发送流程。
Source: http://blog.csdn.net/u010961631/article/details/50272753