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();            }        }    }


更多相关文章

  1. IOS/Android 读取蓝牙设备电量信息
  2. Android 指定Toast信息显示的位置并使用Toast显示其他View
  3. android屏幕信息获取的两种方法
  4. android之获取手机安装包里面的信息、获取目录空间的大小
  5. Android Eclipse Logcat 没有任何的信息 ?
  6. 南青信息查询 for Android客户端

随机推荐

  1. Android中Message机制的灵活应用
  2. 安装 Android(安卓)1.6 SDK
  3. Android(安卓)Jetpack Compose总结
  4. Android(安卓)解析 ByteArrayInputStream
  5. Android(安卓)SystemProperties 系统属性
  6. Android应用框架无边界
  7. Android(安卓)中会出现的问题:This Androi
  8. Android(安卓)layout xml总结
  9. android 设置横屏竖屏
  10. activity以dialog形式显示