您的位置:首页 > 其它

短信发送流程一:系统彩信(MMS)发送流程(2.2)

2012-02-15 17:19 411 查看
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();

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐