當你在編輯界面ComposeMessageActivity.java按下發送按鈕的那一刻,就開始信息的發送之路。當然發短信和發彩信並不完全一樣,會用兩篇文章別說明,不過最後的圖是畫在一起的。
從ComposeMessageActivity.java的onclick()開始,在這裏對聯繫人的個數是有個判斷的,這個函數 isPreparedForSending(),這個判斷之後會通過confirmSendMessageIfNeeded()檢查聯繫人是否有效,如包含無效聯繫人會有對話框提示的,還是比較友好的。這裏要注意的是源碼判斷少於3個數字的聯繫人是非法的,並且數字號碼是否合法的判斷方法也不是很嚴密,4.0的代碼貌似把多選聯繫人的功能加上去,這個方法 launchMultiplePhonePicker(),對應代碼如下。
public void onClick(View v) {
if ((v == mSendButtonSms || v == mSendButtonMms) && isPreparedForSending()) {
confirmSendMessageIfNeeded();
} else if ((v == mRecipientsPicker)) {
launchMultiplePhonePicker();
}
}
檢查聯繫人之後接下來執行WorkingMessage.java的send()方法,在send()方法裏會判斷是發短信還是發彩信(彩信條件:有主題、圖片、音頻、視頻、幻燈片和含中文多於670個字或多於1350個字的純英文信息),短信和彩信在這裏分家了,兩個線程分別負責發送短信和彩信,本來就不是一個東西,早點分開有好處。先看短信
private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId) {//文本內容,收件人,會話ID
String[] dests = TextUtils.split(semiSepRecipients, ";");
MessageSender sender = new SmsMessageSender(mActivity, dests, msgText, threadId);//運行時綁定,這算是多態的一個應用吧。
try {
sender.sendMessage(threadId);
// Make sure this thread isn't over the limits in message count
Recycler.getSmsRecycler().deleteOldMessagesByThreadId(mActivity, threadId);
} catch (Exception e) {
Log.e(TAG, "Failed to send SMS message, threadId=" + threadId, e);
}
mStatusListener.onMessageSent();
}
接下來要走進發送隊列了SmsMessageSender.java的sendMessage.java,按收件人個數把短信寫入數據庫,uri是這個Uri.parse("content://sms/queued"),這裏代碼可以體現出短信和彩信發送區別,短信有多少個收件人發多少條,彩信多少個收件人都是一條,不一樣哦,那麼收件人多的時候短信和彩信用哪個啊?不知道大家有沒有看這個類的這個函數getOutgoingServiceCenter(),它是本意是從收到信息裏找出短信中心,如果沒有收到的信息怎麼辦?沒有短信中心不行的,實際上這個不用擔心了,一般下面的模塊會處理的。
到了短信的關鍵服務SmsReceiverService.java,關鍵的原因是因爲發送接收都在這裏,這是必經之路,發送是要走sendFirstQueuedMessage(),發送成功或失敗的消息handleSmsSent()這個函數處理,實際發送是在SmsSingleRecipientSender.java這個類裏,在這處理會把長短信分段,這個代碼:
messages = smsManager.divideMessage(mMessageText)
處理完長短信,發送信息執行下面代碼,這個代碼後我們就要離開packages層了。
smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);
Framework層 SmsManager.java的sendMultipartTextMessage()方法、sendTextMessage()和sendDataMessage()方法負責發送,前兩個發普通短信,最後一個發端口短信比如以短信形式發vcard。再向下跟GsmSMSDispatcher.java的sendText()方法,在個方法裏開始編碼了,看貼出的代碼:
protected void sendText(String destAddr, String scAddr, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
scAddr, destAddr, text, (deliveryIntent != null));
if (pdu != null) {
sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent);
} else {
Log.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null");
}
}
還在這個類裏sendSms()方法,這裏調用的Ril.java的方法,終於到ril了。
protected void sendSms(SmsTracker tracker) {
HashMap<String, Object> map = tracker.mData;
byte smsc[] = (byte[]) map.get("smsc");
byte pdu[] = (byte[]) map.get("pdu");
Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
mCm.sendSMS(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply);
}
Ril.java的方法,看好那個TAG,RIL_REQUEST_SEND_SMS這個我們會在Referece-ril.c的代碼中找到它,當然這是源碼,不同的vendor廠商可能會根據自己的需要修改的
public void sendSMS (String smscPDU, String pdu, Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_SEND_SMS, result);
rr.mp.writeInt(2);
rr.mp.writeString(smscPDU);
rr.mp.writeString(pdu);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}