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<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 {
- 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);
- }
- ArrayList<PendingIntent>deliveryIntents = newArrayList<PendingIntent>(messageCount);
- ArrayList<PendingIntent>sentIntents = new ArrayList<PendingIntent>(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();
- }
- }
- }