高通android 7.0短信发送流程

原创 2017年09月11日 14:03:00
ComposeMessageActivity.java
sendMessage
mWorkingMessage.setWorkingMessageSub(mSelectedSubId);设置subId
mWorkingMessage.send(mDebugRecipients);
我们注意,在输入收件人获取的收件人和当前的mConversation.getRecipients()是不一样的,我们并不会每次编辑一次收件人就将其设置mConversation中,而我们发送短信时,当是新建短信人,其收件人是从收件编辑框获取,而不是新建,则是从mConversation中获取。

WorkingMessage.java代表着是一个当前正在编辑的短信
Conversation.java代表着当前的会话(一个会话对应着和一个联系人的联系,包含着多条短信彩信)

mText里面放着是发送的文本

new Thread(new Runnable() {
    @Override
    public void run() {
        preSendSmsWorker(conv, msgText, recipientsInUI);
        updateSendStats(conv);
    }
}, "WorkingMessage.send SMS").start();
启动后台线程来发送短信

preSendSmsWorker
mStatusListener.onPreMessageSent(); ComposeMessageActivity实现了这个借口,这样是根据短信当前状态来更新UI
发送之前对UI进行更新
ComposeMessageActivity
resetMessage() 有可能之前是新建短信,所以发送后要隐藏收件人编辑框等,还有处理焦点等

sendSmsWorker(msgText, semiSepRecipients, threadId);
调用SmsMessageSender的sendMessage来发送短信

deleteDraftSmsMessage(threadId);因为发送了,所以将属于这个thread对话的所有草稿都删除。

SmsMessageSender.java 其实这个类并不是执行真正发送短信的类,主要工作是新建sms记录,然后启动广播
sender = new SmsMessageSender(mActivity, dests, msgText, threadId,
                    mCurrentConvSubId);
先将发送短信需要的参数都传递进去

mStatusListener.onMessageSent();更新短信UI

SmsMessageSender.java
sendMessage
queueMessage
requestDeliveryReport是否需要发送报告,对应短信设置中的送达情况报告

int slotId = SubscriptionManager.getSlotId(mSubId);
这里对subId和slotId进行大致讲解:
subId,对应物理卡槽的位置,所以对于双卡,subId就分别为1和2,默认-1
slotId,是不断往上递增,也就是手机记录了手机插入的所有卡的信息,然后将他们存入到数据库中,可以看telephony表

Sms.addMessageToUri调用Telephony的方法在短信数据库的sms表中创建一条记录,thread表在之前获取threadId的时候就已经创建记录了。
Uri.parse("content://sms/queued")这是表示待发送的短信,一般uri后边附上queued这些类型的,都是设置字段type,表示当前短信的各种状态。
这里注意一点
if (deliveryReport) {
    values.put(STATUS, STATUS_PENDING);
}即如果需要发送情况报告的话,要将表中的status设置为pending

Intent intent = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, mContext,
                SmsReceiver.class);
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mSubId);
// Notify the SmsReceiverService to send the message out
mContext.sendBroadcast(intent);
接着启动广播

启动广播SmsReceiver.java
其action是SmsReceiverService中的
public static final String ACTION_SEND_MESSAGE =
            "com.android.mms.transaction.SEND_MESSAGE";

onReceive
onReceiveWithPrivilege
intent.setClass(context, SmsReceiverService.class);
intent.putExtra("result", getResultCode());
beginStartingService(context, intent);

启动服务SmsReceiverService,因为intent是之前传递过来的,所以之前设置的一些内容,例如action都还在的
onStartCommand
ServiceHandler mServiceHandler
handleSendMessage(intent);
sendFirstQueuedMessage(subId)为什么是first?这是考虑到长短信的场景,一条长短信要被分割成多条短信进行发送,但是数据库中只有一条,显示也只显示一条

final Uri uri = Uri.parse("content://sms/queued");
ContentResolver resolver = getContentResolver();
String where = "sub_id=?";
String[] whereArgs = new String[] {Integer.toString(subscription)};
Cursor c = SqliteWrapper.query(this, resolver, uri, SEND_PROJECTION, where, whereArgs, "date ASC"); 
将数据库中,queue状态的,subId等于要发送的subId,都从数据库查找出来,这样群发的就会将所有要群发的都查找出来。

 if (c.moveToNext()) {
   isExpectMore = true; 所以这个表示了是否还有短信要发送,跟群发有关
 }
SmsSingleRecipientSender这个类才是真正负责发送短信的类
调用sendMessage来发送短信
messageFailedToSend(msgUri, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
如果遇到异常,会将其type修改为failed

SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(mSubId);
ArrayList<String> messages 长短信会被切割
messages = smsManager.divideMessage(mMessageText); 分割短信

boolean moved = Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0);
改变其字段type,将其移动到发件箱

ArrayList<PendingIntent> deliveryIntents =  new ArrayList<PendingIntent>(messageCount);送达情况报告,这个是要送达到对方手机
ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(messageCount);发送出去,只要发送成功就可以
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);
            intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mSubId);
sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0));

smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages,
                    sentIntents, deliveryIntents, mPriority, isExpectMore, validityPeriod);
这个才是真正发送短信的,当前,这个是在应用层的最终地方,到了framework层还有其他流程。

前面sentIntents,当短信发送,无论成功还是失败,会调用这个Intent,所以SmsReceiver->SmsReceiverService还是这个流程。
if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
     handleSmsSent(intent, error);
}

if (resultCode == Activity.RESULT_OK) 如果之前的发送成功,则
boolean sendNextMsg = intent.getBooleanExtra(EXTRA_MESSAGE_SENT_SEND_NEXT, false);
是否还有待发送的短信,记得之前isExpectMore ,应该就是和这个对应,有的话
if (sendNextMsg) {
    Log.v(TAG, "handleSmsSent: move message to sent folder uri: " + uri);
    if (!Sms.moveMessageToFolder(this, uri, Sms.MESSAGE_TYPE_SENT, error)) {
       Log.e(TAG, "handleSmsSent: failed to move message " + uri + " to sent folder");
    }
    sendFirstQueuedMessage(subId);
}

else if ((resultCode == SmsManager.RESULT_ERROR_RADIO_OFF) ||
                (resultCode == SmsManager.RESULT_ERROR_NO_SERVICE))
如果是因为这两种情况,一种是射频关闭,例如飞行模式(其中,如果处于飞行模式的时候,发送按钮是不可用的),一种是没有信号,则重新将他们放入到queue中
Sms.moveMessageToFolder(this, uri, Sms.MESSAGE_TYPE_QUEUED, error);
然后弹出目前无法发送信息,系统会在服务恢复后发送。提醒
这个系统服务恢复是否在下一次用同一个subId发送短信的时候才检测?看代码应该是。

else if (resultCode == SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE)
标志为错误,然后提醒,您只能向固定拨号号码发送信息。接着发送下一条短信如果有的话

最后剩下的,则归类于发送失败,然后接着发送下一条
messageFailedToSend(uri, error); 
if (sendNextMsg) {
     sendFirstQueuedMessage(subId);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

大四课程设计之基于RFID技术的考勤管理系统(一)项目介绍

大四课程设计之基于RFID技术的考勤管理系统(一)项目介绍

程序员的八重境界

看到一篇有趣的文章The Eight Levels of Programmers。以前似乎看过不少这种程序员的多少个级别、境界,但这篇语言很风趣,而且分类比较细化,让人觉得挺合情合理、无法反驳的。绝大...
  • dc_726
  • dc_726
  • 2017-08-31 04:58
  • 22200

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

MySQL数据类型-decimal详解

1.首先,对于精度比较高的东西,比如money,我会用decimal类型,不会考虑float,double,因为他们容易产生误差,numeric和decimal同义,numeric将自动转成decim...
  • zyu67
  • zyu67
  • 2015-02-27 14:29
  • 888

php调用新浪短链接API转短链接

调用新浪短链api,长链接可转为http://t.cn/RX7mLZh这种t.cn短链,同时转会原链接!//新浪的App_Key const SINAAPPKEY = '291**161014'; p...

高通Android4.4短信发送流程

高通Android4.4短信发送流程

大型分布式数据库中间件MyCat的安装与使用

官网资料MyCat官网:http://www.mycat.io/MyCat权威指南:http://www.mycat.io/document/Mycat_V1.6.0.pdfMyCat下载地址:htt...

delphi相对数据库连接

搞了好久 今天在网上找了一个 方法procedure TForm1.FormCreate(Sender: TObject); begin SetCurrentDir(Extractfilepath(A...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)