Android短信發送流程之多收件人發送(原)

        前面的《Android短信發送流程之長短信發送》中介紹了長短信對於普通短信的區別,而對於多收件人的情況,在SmsMessageSender的queueMessage()方法中我們瞭解到,發送之前,將多收件人的短信進行拆分,放入"content://sms/queued"隊列中,在接下來的流程中,將會在SmsReceiverService中通過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);
            }
        }
        然後進入handleSendComplete()方法中處理:
        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 {
                //發送失敗
            }
        }
        在上面的過程中,對短信發送的結果進行區分,如果失敗,將會根據失敗原因通知SmsTracker,如果成功,將會進入SmsTracker中繼續處理:
        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");
                }
            }
        }
        由於此時無論是長短信還是普通短信,都已經發送完畢(只發送了一個收件人),因此isSinglePartOrLastPart的判定將會是true,從而更新數據庫中該短信的狀態,然後再將發送時附加在SmsTracker中的mSentIntent取出來併發送出去,同時指定返回結果爲“Activity.RESULT_OK”。
        而這裏的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;
        }
        從這裏我們看到,當前的mSentIntent發送對象是SmsReceiver,內容是MESSAGE_SENT_ACTION,而且包含了附加數據EXTRA_MESSAGE_SENT_SEND_NEXT=true,並且SmsTracker發送該Intent時傳送的結果是“Activity.RESULT_OK”。
        由於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);
        }
        對於當前的Intent,將會在handleSmsSent()中處理:
        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();
                }
            }
        }
        由於當前resultCode=OK,並且sendNextMsg=true,首先會通過Sms.moveMessageToFolder()操作將發送成功的短信從"content://sms/queued"隊列移動到"content://sms/sent"隊列。
        然後在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();
            }
        }
        在上面的過程中,檢測發送隊列中是否有未發送的短信,對於多收件人的情況,由於我們之前只發送出去了第一條短信,而且已經將已發送的短信從該隊列移出,因此此時的隊列中只有其他收件人的短信,然後取出其中的一條,再次進入發送通道,接下來的流程和之前的相同。
        這就是多收件人的發送流程。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章