SMS发送流程 Android2.2

SMS发送流程

Android2.2packages/apps/Mms

1.      点击发送按钮Src/com/android/mms/ui/ComposeMessageActivity.java

public void onClick(View v) {
        if ((v == mSendButton) && isPreparedForSending()) {
            confirmSendMessageIfNeeded(); //确认是否需要发送短信—-》
        }
}

2.src/com/android/mms/ui/ComposeMessageActivity.java

private void confirmSendMessageIfNeeded() {
        if (!isRecipientsEditorVisible()) {  //编辑联系人不可见时,也就是给已存在会话的联系人发送短信时
            sendMessage(true);
            return;
        }
 
        boolean isMms = mWorkingMessage.requiresMms();   //是否需要以彩信形式发送
                if (mRecipientsEditor.hasInvalidRecipient(isMms)) {//是否含有不合法的收件人
            if (mRecipientsEditor.hasValidRecipient(isMms)) {//有合法的和不合法的,弹出尝试发送对话框
                String title =getResourcesString(R.string.has_invalid_recipient,
                        mRecipientsEditor.formatInvalidNumbers(isMms));
                new AlertDialog.Builder(this)
                   .setIcon(android.R.drawable.ic_dialog_alert)
                    .setTitle(title)
                    .setMessage(R.string.invalid_recipient_message)
                   .setPositiveButton(R.string.try_to_send,
                            newSendIgnoreInvalidRecipientListener())
                   .setNegativeButton(R.string.no, new CancelSendingListener())
                    .show();
            } else {//如果全是不合法的联系人,提示不能发送信息
                new AlertDialog.Builder(this)
                   .setIcon(android.R.drawable.ic_dialog_alert)
                    .setTitle(R.string.cannot_send_message)
                    .setMessage(R.string.cannot_send_message_reason)
                   .setPositiveButton(R.string.yes, new CancelSendingListener())
                    .show();
            }
        } else {//判断收件人没有问题,接着发送信息 --》
            sendMessage(true);
        }
}

3. src/com/android/mms/ui/ComposeMessageActivity.java

private void sendMessage(boolean bCheckEcmMode) {
    Log.v(TAG, "sendMessage");
        if (bCheckEcmMode) {
            // TODO: expose this in telephony layer for SDK build
            String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);     //判断电话是否处于紧急拨号模式,得到的inEcm一般为空
            Log.v(TAG, "inEcm = " + inEcm);
            if (Boolean.parseBoolean(inEcm)) {
                try {
                    startActivityForResult(
                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS,null),
                            REQUEST_CODE_ECM_EXIT_DIALOG);
                    return;
                } catch (ActivityNotFoundException e) {
                    // continue to send message
                    Log.e(TAG, "Cannot find EmergencyCallbackModeExitDialog", e);
                }
            }
        }
 
        if (!mSendingMessage) {
            // send can change the recipients. Make sure we remove the listeners firstand then add
            // them back once the recipient list has settled.
            removeRecipientsListeners();  //取消对收件人的监听
            mWorkingMessage.send();   //发送信息—-》
            mSentMessage = true;
            mSendingMessage = true;
            addRecipientsListeners(); //重新添加收件人监听
        }
        // But bail out if we are supposed to exit after the message is sent.
        if (mExitOnSent) {//如果mExitOnSent为true,信息发送完成后退出Activity
            finish();
        }
    }

4. src/com/android/mms/data/WorkingMessage.java

/**
     * Send this message over the network.  Will call back with onMessageSent() once
     * it has been dispatched to the telephonystack.  This WorkingMessage object is
     * no longer useful after this method hasbeen called.
     */
    public void send() {
        if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
            LogTag.debug("send");
        }
 
        // Get ready to write to disk.
        prepareForSave(true /* notify */);//主要做一下同步收件人和WorkingMessage,彩信时在准备其他一些东西
 
        // We need the recipient list for both SMS and MMS.
        final Conversation conv = mConversation;
        String msgTxt = mText.toString();
        Log.v(TAG, "msgText = " + msgTxt);
        if (requiresMms() ||addressContainsEmailToMms(conv, msgTxt)) {
            // Make local copies of the bits we need for sending a message,
            // because we will be doing it off of the main thread, which will
            // immediately continue on to resetting some of this state.
            final Uri mmsUri = mMessageUri;
            final PduPersister persister = PduPersister.getPduPersister(mContext);
 
            final SlideshowModel slideshow = mSlideshow;
            final SendReq sendReq = makeSendReq(conv,mSubject);
 
            // Do the dirty work of sending the message off of the main UI thread.
            new Thread(new Runnable() {
                public void run() {
                    // Make sure the text in slide 0 is no longer holding onto a reference to
                    // the text in the message text box.
                    slideshow.prepareForSend();
                    sendMmsWorker(conv, mmsUri,persister, slideshow, sendReq);
                }
            }).start();
        } else {
            // Same rules apply as above.
            final String msgText = mText.toString();//取出短消息
            Log.v(TAG, "msgText = " + msgText);
            new Thread(new Runnable() {
                public void run() {
                    preSendSmsWorker(conv, msgText);//发送信息--》
                }
            }).start();
        }
 
        // update the Recipient cache with the new to address, if it's different
        RecipientIdCache.updateNumbers(conv.getThreadId(),conv.getRecipients());
 
        // Mark the message as discarded because it is "off the market"after being sent.
        mDiscarded = true;
    }

5. src/com/android/mms/data/WorkingMessage.java

private void preSendSmsWorker(Conversation conv, StringmsgText) {
        // If user tries to send the message, it's a signal the inputtedtext is what they wanted.
        UserHappinessSignals.userAcceptedImeText(mContext);
 
        mStatusListener.onPreMessageSent();//重置一些信息,比如清空输入内容框、一些监听等等
 
        // Make sure we are still using the correct thread ID for our
        // recipient set.
        long threadId = conv.ensureThreadId();//新建获得会话线程ID
        Log.v(TAG, "threadId = " + threadId);
        final String semiSepRecipients =conv.getRecipients().serialize();
 
        // just do a regular send. We're already on a non-ui thread so noneed to fire
        // off another thread to do this work.
        sendSmsWorker(msgText, semiSepRecipients, threadId);//发送信息----》
 
        // Be paranoid and clean any draft SMS up.
        deleteDraftSmsMessage(threadId);//删除草稿
    }

 

6. src/com/android/mms/data/WorkingMessage.java

private void sendSmsWorker(String msgText, String semiSepRecipients, longthreaded) {
        String[] dests = TextUtils.split(semiSepRecipients,“;”);
        Log.v(TAG, “sendSmsWorker – semiSepRecipients is “ + semiSepRecipients);
        if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
            LogTag.debug(“sendSmsWorker sending message”);
        }
        MessageSender sender = new SmsMessageSender(mContext, dests, msgText, threaded);
        try {
            sender.sendMessage(threadId);//根据ThreadID发送信息----》
 
            // Make sure this thread isn't over the limits in message count
            Recycler.getSmsRecycler().deleteOldMessagesByThreadId(mContext, threadId);
        } catch (Exception e) {
            Log.e(TAG, "Failed to send SMS message, threadId=" + threadId, e);
        }
 
        mStatusListener.onMessageSent();
    }

7. src/com/android/mms/transaction/SmsMessageSender.java

public boolean sendMessage(long token) throwsMmsException {
        // In order to send the message one by one, instead of sending now, themessage will split,
        // and be put into the queue along with each destinations
        return queueMessage(token);
    }

8. src/com/android/mms/transaction/SmsMessageSender.java

private boolean queueMessage(long token) throwsMmsException {
        if ((mMessageText == null) || (mNumberOfDests == 0)) {
            // Don't try to send an empty message.
            throw new MmsException("Null message body or dest.");
        }
        Log.v("SMsMessageSender", "queueMessage");
        SharedPreferences prefs =PreferenceManager.getDefaultSharedPreferences(mContext);
        boolean requestDeliveryReport =prefs.getBoolean(
                MessagingPreferenceActivity.SMS_DELIVERY_REPORT_MODE,
                DEFAULT_DELIVERY_REPORT_MODE);
        Log.v("SmsMessageSender", "add Message to 'content://sms/queued'");
        for (int i = 0; i < mNumberOfDests; i++) {//根据收件人数目分别建立短信放入发送队列
            try {
                Sms.addMessageToUri(mContext.getContentResolver(),
                        Uri.parse("content://sms/queued"), mDests[i],
                        mMessageText, null, mTimestamp,
                        true /* read */,
                        requestDeliveryReport,
                        mThreadId);
            } catch (SQLiteException e) {
                SqliteWrapper.checkSQLiteException(mContext, e);
            }
        }
        // Notify the SmsReceiverService to send the message out
        mContext.sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
                null,
                mContext,
                SmsReceiver.class));  //通知SmsReceiverService来发送短信,传递参数ACTION_SEND_MESSAGE
        return false;
    }

9. src/com/android/mms/transaction/SmsReceiverService.java

/**
         * Handle incoming transactionrequests.
         * The incoming requests are initiatedby the MMSC Server or by the MMS Client itself.
         */
        @Override
        public void handleMessage(Message msg) {
            int serviceId = msg.arg1;
            Intent intent = (Intent)msg.obj;
            if (intent != null) {
                String action =intent.getAction();
 
                int error = intent.getIntExtra("errorCode", 0);
 
                if (MESSAGE_SENT_ACTION.equals(intent.getAction())){
                    handleSmsSent(intent,error);
                } else if (SMS_RECEIVED_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();//处理发送信息
                }
            }
            // NOTE: We MUST not call stopSelf() directly, since we need to
            // make sure the wake lock acquired by AlertReceiver is released.
            SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
        }
    }

10. src/com/android/mms/transaction/SmsReceiverService.java

private void handleSendMessage(){
    Log.v(TAG, "handleSendMessage");
        if (!mSending) {//如果没有发送,则准备发送
            sendFirstQueuedMessage();
        }
}

 

11. src/com/android/mms/transaction/SmsReceiverService.java

public synchronized void sendFirstQueuedMessage() {
    Log.v(TAG, "sendFirstQueuedMessage");
        boolean success = true;
        // get all the queued messages from the database
        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
                                                                   // same order the user tried
                                                                   // to send messages.
        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);
                    Log.v(TAG, "address = " + address);
                    Log.v(TAG, "msgText = " + msgText);
                    Log.v(TAG, "status = " + status);
                   
                    int msgId = c.getInt(SEND_COLUMN_ID);
                    Uri msgUri = ContentUris.withAppendedId(Sms.CONTENT_URI,msgId);
                    Log.v(TAG, "msgId = " + msgId);
                    SmsMessageSender sender = newSmsSingleRecipientSender(this,
                            address, msgText,threadId, status == Sms.STATUS_PENDING,
                            msgUri);
 
                    if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
                        Log.v(TAG, "sendFirstQueuedMessage " + msgUri +
                                ", address: " + address +
                                ", threadId: " + threadId +
                                ", body: " + msgText);
                    }
                    try {
                        sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);//进行单个信息发送
                        mSending = true;
                    } catch (MmsExceptione) {
                        Log.e(TAG, "sendFirstQueuedMessage: failed to send message" + msgUri
                                + ", caught ", e);
                        success = false;
                    }
                }
            } 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();
        }
}

12. src/com/android/mms/transaction/SmsSingleRecipientSender.java

public boolean sendMessage(long token) throwsMmsException {
        if (mMessageText == null) {
            // Don't try to send an empty message, and destination should be just
            // one.
            throw new MmsException("Null message body or have multiple destinations.");
        }
        SmsManager smsManager = SmsManager.getDefault();
        ArrayList 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 {
        Log.v("SmsSingleRecipient", "divideMessage");
           messages = smsManager.divideMessage(mMessageText);//短信通道被限制160个字节,因此内容过长将会以多条短信发送,这个动作就是将长短信拆分成合适的大小
           // remove spaces from destination number (e.g. "801 555 1212"-> "8015551212")
           mDest = mDest.replaceAll("", "");
        }
        int messageCount = messages.size();
 
        if (messageCount ==0) {
            // Don't try to send an empty message.
            throw new MmsException("SmsMessageSender.sendMessage: divideMessage returned " +
                    "empty messages. Original message is \"" + mMessageText + "\"");
        }
        Log.v("SmsSingleRecipientSender", "move to Sms.MESSAGE_TYPE_OUTBOX");
        Log.v("SmsSingleRecipientSender", "mUri = " + mUri);
        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);
        }
 
        ArrayListdeliveryIntents =  newArrayList(messageCount);
        ArrayListsentIntents = new ArrayList(messageCount);
        for (int i = 0; i < messageCount; i++) {
            if (mRequestDeliveryReport) {
                // TODO: Fix: It should not be necessary to
                // specifythe class in this intent.  Doing that
                // unnecessarily limits customizability.
               deliveryIntents.add(PendingIntent.getBroadcast(
                        mContext, 0,
                        new Intent(
                               MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,
                                mUri,
                                mContext,
                               MessageStatusReceiver.class),
                        0));
            }
            Intent intent  = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,
                    mUri,
                    mContext,
                    SmsReceiver.class);//触发SmsReceiverService的MESSAGE_SENT_ACTION消息
            if (i == messageCount -1) {
               intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true);
            }
            sentIntents.add(PendingIntent.getBroadcast(
                    mContext, 0, intent, 0));//设置回调的Intent为intent,
        }
        try {
            smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);//调用Framework中的API来发送短信,会回调sentIntents来处理发送的情况
        } catch (Exception ex) {
            throw new MmsException("SmsMessageSender.sendMessage: caught " + ex +
                    " from SmsManager.sendTextMessage()");
        }
        if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
            log("sendMessage: address=" + mDest + ", threadId=" + mThreadId +
                    ", uri=" + mUri + ", msgs.count=" + messageCount);
        }
        return false;
    }

 

13. src/com/android/mms/transaction/SmsReceiverService.java

/**
         * Handle incoming transactionrequests.
         * The incoming requests are initiatedby the MMSC Server or by the MMS Client itself.
         */
        @Override
        public void handleMessage(Message msg) {
            int serviceId = msg.arg1;
            Intent intent = (Intent)msg.obj;
            if (intent != null) {
                String action =intent.getAction();
 
                int error = intent.getIntExtra("errorCode", 0);
 
                if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
                    handleSmsSent(intent, error);
                } else if (SMS_RECEIVED_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();
                }
            }
            // NOTE: We MUST not call stopSelf() directly, since we need to
            // make sure the wake lock acquired by AlertReceiver is released.
            SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
        }
    }

14. src/com/android/mms/transaction/SmsReceiverService.java

private void handleSmsSent(Intentintent, int error) {
    Log.v(TAG, "handleSmsSent - error is " + error);
        Uri uri = intent.getData();
        Log.v(TAG, "uri = " + uri);
        mSending = false;
        boolean sendNextMsg =intent.getBooleanExtra(EXTRA_MESSAGE_SENT_SEND_NEXT, false);
 
        if (mResultCode == Activity.RESULT_OK) {//发送成功的情况
        Log.v(TAG, "mResultCode == Activity.RESULT_OK");
            if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
                Log.v(TAG, "handleSmsSent sending uri: " + uri);
            }
            Log.v(TAG, "moveMessageToFolder intoSms.MESSAGE_TYPE_SENT");
//将短信移动到已发送
            if (!Sms.moveMessageToFolder(this, uri, Sms.MESSAGE_TYPE_SENT,error)) {
                Log.e(TAG, "handleSmsSent: failed to move message " + uri + " to sentfolder");
            }
            if (sendNextMsg) {//如果需要,发送下一条
                sendFirstQueuedMessage();//只是查发送队列的信息去发送
            }
 
            // Update the notification for failed messages since they may be deleted.
            MessagingNotification.updateSendFailedNotification(this);
        } else if ((mResultCode == SmsManager.RESULT_ERROR_RADIO_OFF) ||
                (mResultCode == SmsManager.RESULT_ERROR_NO_SERVICE)) {
        Log.v(TAG, "mResultCode ==SmsManager.RESULT_ERROR_RADIO_OFF");
            if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
                Log.v(TAG, "handleSmsSent: no service, queuing message w/ uri:" + uri);
            }
            // We got an error with no service or no radio. Register for state changesso
            // when the status of the connection/radio changes, we can try to send the
            // queued up messages.
            registerForServiceStateChanges();//来服务和信号时调用sendFirstQueuedMessage()去发送
            // We couldn't send the message, put in the queue to retry later.
            Log.v(TAG, "uri = " + uri);
            Log.v(TAG, "moveMessageToFolder intoSms.MESSAGE_TYPE_QUEUED");
            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 {
        Log.v(TAG, "mResultCode == Other exception");
            if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
                Log.v(TAG, "handleSmsSent msg failed uri: " + uri);
            }
            Sms.moveMessageToFolder(this, uri, Sms.MESSAGE_TYPE_FAILED,error);
            MessagingNotification.notifySendFailed(getApplicationContext(),true);
            if (sendNextMsg) {
                sendFirstQueuedMessage();
            }
        }
    }


你可能感兴趣的:(Andriod)