发送短信流程
短信/彩信发送流程如图所示:
第一部分:UI 部分
1. ComposeMessageActivity.java->onClick():
点击发送按钮。
public void onClick(View v)
{
if ((v == mSendButton) && isPreparedForSending())
{
//确认是否需要发送短信
confirmSendMessageIfNeeded(); //2
}
……
}
2. ComposeMessageActivity.java-> confirmSendMessageIfNeeded ():
进入该方法后做如下判断:
(1)判断接收者编辑是否可见,如果不可见则表示会话已经存在,接收者肯定有效。
如果可见则需要进行下面的判断。
(2)是否可以发送,即判断信息发送的条件,如果条件允许则进入下面判断。
(3)判断是否有无效接收者,如果没有则表示接收者有效。若存在无效接收者,则需
要进行下面判断。
(4)判断是否存在有效接收者,如果存在则会提示有无效接收者,包含尝试发送按钮。
如果没有,则会提示接收者无效,仅有取消发送按钮.
private void confirmSendMessageIfNeeded()
{
//是否需要以彩信形式发送
boolean isMms = mWorkingMessage.requiresMms();
……
//编辑联系人不可见时,也就是给已存在会话的联系人发送短信时
if (!isRecipientsEditorVisible())
{
sendMessage(true);
return;
}
//是否含有不合法的收件人
if (mRecipientsEditor.hasInvalidRecipient(isMms))
{
//有合法的和不合法的,弹出尝试发送对话框
if (mRecipientsEditor.hasValidRecipient(isMms))
{
……
}
//如果全是不合法的联系人,提示不能发送信息
else
{
……
}
}
//判断收件人没有问题,发送信息
else
{
sendMessage(true); 3
}
}
3. ComposeMessageActivity.java-> sendMessage ():
(1)判断是否为紧急状态。如果是紧急状态,则需要判断手机是否为紧急模式,如果是紧
急模式则转为紧急模式 Activity;如果不是紧急模式和紧急状态则进行如下判断。
(2)判断信息是否处于发送状态,如果为发送状态则继续发送直到发送完毕;如果不为发
送状态,则需要做出相应处理:
a.移除接收者监听器;
b.调 用 WorkingMessage.send()方法,回调一次 onMessageSent()方法是信息放入发送堆
栈中;
c.添加接收者监听器。
(3)等待发送完该信息后,需要做是否退出 Activity 的判断。
private WorkingMessage mWorkingMessage;
private void sendMessage(boolean bCheckEcmMode)
{
if (bCheckEcmMode)
{
String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
//判断电话是否处于紧急拨号模式,得到的 inEcm 一般为空
if (Boolean.parseBoolean(inEcm))
{
startActivityForResult(
new
Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),
REQUEST_CODE_ECM_EXIT_DIALOG);
}
if (!mSendingMessage)
{
……
int phoneId =
TelephonyManager.getDefaultSim(this,TelephonyManager.MODE_MMS);
……
//设置 phoneId
mWorkingMessage.setPhoneId(phoneId);
//取消对收件人的监听
removeRecipientsListeners();
//发送信息
if(mWorkingMessage.send(mDebugRecipients)) //4
{
mSentMessage = true;
mSendingMessage = true;
addRecipientsListeners(); //重新添加收件人监听
}
}
}
if (mExitOnSent || "folder".equals(launchMode))
{
finish(); //如果 mExitOnSent 为 true,信息发送完成后退出 Activity
}
}
第二部分:Frameworks 部分
4. WorkingMessage.java->send():
根据短信和彩信的区别调用各自不同的方法对短信和彩信进行一些处理。进入方法后进行
如下操作:
(1)将接收者列表放到当前会话中。
( 2 ) 判 断 是 否 需 要 发 送 彩 信 或 者 包 含 Email 到 彩 信 的 地 址 。 若 果 不 是 则 调
用 preSendSmsWorker()此方法继续执行。如果是则进行如下操作(对彩信进行一些预处理)。
(3)则创建所发信息的本地副本,因为后续的操作将不在主线程中进行,并且通过
makeSendReq()获取返回一个非空的发送地址。创建并调用一个新的线程,并且确保幻灯片
文 本 0 不 再 持 有 引 用 信 息 文 本 框 中 的 引 用 ( 即 使 用 创 建 的 副 本 )。 在 线 程 中 调 用
sendMmsWorker()进行发送。
public boolean send(final String recipientsInUI)
{
……
//主要做一下同步收件人和 WorkingMessage,彩信时在准备其他一些东西
prepareForSave(true /* notify */);
final Conversation conv = mConversation;
String msgTxt = mText.toString();
if (requiresMms() || addressContainsEmailToMms(conv, msgTxt))
{
final Uri mmsUri = mMessageUri;
final PduPersister persister = PduPersister.getPduPersister(mActivity);
final SlideshowModel slideshow = mSlideshow;
final SendReq sendReq = makeSendReq(conv, mSubject);
Runnable run = new Runnable(){
public void run(){
slideshow.prepareForSend();
sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq);
}
};
new Thread(run).start();
}
else
{
final String msgText = mText.toString(); //取出短消息
Runnable run = new Runnable(){
public void run(){
preSendSmsWorker(conv, msgText, recipientsInUI); //发送信息5
}
};
}
RecipientIdCache.updateNumbers(conv.getThreadId(), conv.getRecipients());
mDiscarded = true;
return true;
}
5. WorkingMessage.java-> preSendSmsWorker():
对短信进行发送前的一些处理。
(1)设置为用户接受的文本。即表示用户输入的需要发送的文本。
(2)设置状态为发送前。设置为丢弃,在被送到“市场后”。
(3)获取会话的线程 id,确保我们在正确的线程 id 中设置收件人。
(4)将会话的收件人序列化。
(5)调用 sendSmsWorke()方法进行发送。
( 6 ) 当 执 行 完 sendSmsWorker() 方 法 后 , 就 需 要 删 除 会 话 短 信 的 草 案 了 。 即 调 用
deleteDraftSmsMessage(threadId).
private void preSendSmsWorker(Conversation conv, String msgText, String recipientsInUI)
{
UserHappinessSignals.userAcceptedImeText(mActivity);
//重置一些信息,比如清空输入内容框、一些监听等等
mStatusListener.onPreMessageSent();
long origThreadId = conv.getThreadId();
long threadId = conv.ensureThreadId(); //新建获得会话线程 ID,确保使用正确的线程 ID
final String semiSepRecipients = conv.getRecipients().serialize();
……
sendSmsWorker(msgText, semiSepRecipients, threadId); //发送信息6
deleteDraftSmsMessage(threadId); //删除草稿
}
6. WorkingMessage.java-> sendSmsWorker():
在这里做一个定期的的发送,不需要关闭另一个线程来完成该项工作,因为我们已经
在一个非 UI 的线程中了。
(1)分隔会话的收件人(用分号分隔),因为一个会话可能包含多个收件者。
(2)创建一个 SmsMessageSender 对象,并且调用 sendMessage()方法发送消息。
(3) 等 sendMessage() 执 行完 以 后, 为 了确 保 线程 不 超 过限 制 信息 计 数, 所 以调 用
deleteOldMessagesByThreadId()方法按线程 id 删除已经发送过的信息。
(4)将状态监听器设置为 onMessageSent()。
private void sendSmsWorker(final String msgText, String semiSepRecipients,
final
long
threadId){
final String[] dests = TextUtils.split(semiSepRecipients, ";");
MessageSender sender = new SmsMessageSender(mActivity,
dests,
msgText,
threadId,
mPhoneId);
……
sender.sendMessage(threadId); //根据 ThreadID 发送信息7
Recycler.getSmsRecycler().deleteOldMessagesByThreadId(mActivity, threadId);
mStatusListener.onMessageSent();
}
7. SmsMessageSender.java-> sendMessage():
public boolean sendMessage(long token) throws MmsException
{
return queueMessage(token); //8
}
8. SmsMessageSender.java-> queueMessage ():
为了一个一个发送,而不是立刻发送消息,需要将消息分隔,并且沿着目的地把它放入
到队列中。这就需要调用 queueMessage()。下面直接进入 queueMessage()方法,将信息分隔
放入到队列中。
(1)这个方法中涉及到一个数据库操作,其 Uri 为:content://sms/queued,即将消息放到
队列中。
(2)通知短信服务器发送信息。
private boolean queueMessage(long token) throws MmsException
{
if ((mMessageText == null) || (mNumberOfDests == 0))
{
throw new MmsException("Null message body or dest.");
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
boolean requestDeliveryReport = prefs.getBoolean(
MessagingPreferenceActivity.SMS_DELIVERY_REPORT_MODE,
DEFAULT_DELIVERY_REPORT_MODE);
//根据收件人数目分别建立短信放入发送队列
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,
mPhoneId);
} catch (SQLiteException e) {
SqliteWrapper.checkSQLiteException(mContext, e);
}
}
//通知 SmsReceiverService 发送短信,传递参数 ACTION_SEND_MESSAGE
mContext.sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
null,
mContext,
SmsReceiver.class)); //9
return false;
}
9. SmsReceiverService.java-> ServiceHandler.handleMessage():
信息服务器接收到 ACTION_SEND_MESSAGE 广播后,调用 handleSmsSent()方法。
public void handleMessage(Message msg)
{
int serviceId = msg.arg1;
Intent intent = (Intent)msg.obj;