发送SMS与MMS过程
2016-02-29 18:58
267 查看
Android4.2
pending_msgs表: 等待下载或发送的信息
proto_type:0代表sms,1代表mms。
msg_id :代表pdu表或sms表的id
msg_type : 128代表等待发送的信息,130代表失败后等待重发的信息。在发送时这个筛选掉了已发送的信息。
err_type :0代表没异常。
点击发送按钮触发发送,短信是个ImageButton,彩信是个带图片的TextView
一、短信SMS
调用了preSendSmsWorker(conv, msgText, recipientsInUI);方法,在此方法中调用了sendSmsWorker(msgText, semiSepRecipients, threadId);方法。
接着调用了SmsMessageSender.java类的sendMessage方法发送信息,SmsMessageSender.java在构造时通过getOutgoingServiceCenter(mThreadId)方法试图从收件箱中获取服务中心号码,留给子类所用。sendMessage方法调用了queueMessage(token)方法,在此方法中把短信存到sms数据库中,每一个联系人存一条,type=0。接着发广播到SmsReceiver.class中,收到广播后启动SmsReceiverService服务。
SmsReceiverService中调用hander处理信息,发短信的Action为ACTION_SEND_MESSAGE,调用了handleSendMessage()方法,接着sendFirstQueuedMessage()被调用,在sendFirstQueuedMessage()方法中取出了Uri.parse("content://sms/queued")的待发送数据,构建了SmsMessageSender的子类SmsSingleRecipientSender并调用其的sendMessage方法发送消息。sendMessage方法主要是使用SmsManager对短信进行长短信拆分并一个个发送。
发送成功或者失败都要走SmsReceiverService的handleSmsSent(intent, error);方法。
framework流程:
在SmsManagger的sendMultipartTextMessage方法中判断messages的size,等于1为短信,大于1为长短信,分别走不同流程。
短信:
在GsmSMSDispatcher的sendText方法里调用了
长短信与短信流程基本差不多。
sms表:
type : ALL=0;INBOX=1;SENT=2;DRAFT=3;OUTBOX=4;FAILED=5;QUEUED=6; 6表示等待发送。
status : 32表示启动了发送报告。
二、彩信MMS(ComposeMessageActivity、WorkingMessage、MmsMessageSender、TransactionService)
调用了
接着查询彩信发件箱,所有发件箱内彩信的m_size字段的相加和如果大于4*300*1024,则unDiscard()使得mDiscarded为false,并调用mStatusListener.onMaxPendingMessagesReached()存草稿。
如果待发送的彩信没超出限制,则
获取uri后构建发送类,接着发送(sender.sendMessage(threadId))
TransactionService.class服务中用hander处理消息
判断了网络状态noNetwork,intent.getAction()得到的值是null,所以走if流程,以时间为条件获取pending_msgs表中所有时间(due_time)小于或等于当前时间并且err_type字段值小于等于10的数据。如果没网络,则给出提示、stopSelf(serviceId)并返回。
已发送。
发送彩信采用的是http的方式,sendPdu一直到最后调用了
对于发送前判断的网络没准备好而保存的数据,在onCreate中注册了广播接收者,当网络恢复时接收广播,最后调用
在processPendingTransaction方法中取出未发送的数据,继续走processTransaction流程。
彩信发送结果:
在SendTransaction中发送完彩信后返回结果数组 byte[] response ,解析返回值后更新mms数据,最后调用notifyObservers()方法,而在此类构建时
把observer类 RetryScheduler注册到此类中,最后在RetryScheduler的update方法中对返回结果处理(弹Toast)。
短信发送结果:
在SmsSingleRecipientSender中发送后会以action为SmsReceiverService.MESSAGE_SENT_ACTION启动SmsReceiverService,最后在handleSmsSent方法里处理结果值,如果没插卡,mResultCode == SmsManager.RESULT_ERROR_NO_SERVICE会把短信状态切回type ==6.
pending_msgs表: 等待下载或发送的信息
proto_type:0代表sms,1代表mms。
msg_id :代表pdu表或sms表的id
msg_type : 128代表等待发送的信息,130代表失败后等待重发的信息。在发送时这个筛选掉了已发送的信息。
err_type :0代表没异常。
点击发送按钮触发发送,短信是个ImageButton,彩信是个带图片的TextView
@Override public void onClick(View v) { if ((v == mSendButtonSms || v == mSendButtonMms) && isPreparedForSending()) { confirmSendMessageIfNeeded(); } else if ((v == mRecipientsPicker)) { launchMultiplePhonePicker(); } }在confirmSendMessageIfNeeded方法中,粗略的判断了联系人号码合法性,有数字就是合法的。合法就调用了sendMessage(true)方法,在sendMessage方法中调用了mWorkingMessage.send(mDebugRecipients),在send方法中对短彩信发送做了区分。
一、短信SMS
调用了preSendSmsWorker(conv, msgText, recipientsInUI);方法,在此方法中调用了sendSmsWorker(msgText, semiSepRecipients, threadId);方法。
private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId) { String[] dests = TextUtils.split(semiSepRecipients, ";"); if (LogTag.VERBOSE || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.d(LogTag.TRANSACTION, "sendSmsWorker sending message: recipients=" + semiSepRecipients + ", threadId=" + threadId); } 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(); MmsWidgetProvider.notifyDatasetChanged(mActivity); }
接着调用了SmsMessageSender.java类的sendMessage方法发送信息,SmsMessageSender.java在构造时通过getOutgoingServiceCenter(mThreadId)方法试图从收件箱中获取服务中心号码,留给子类所用。sendMessage方法调用了queueMessage(token)方法,在此方法中把短信存到sms数据库中,每一个联系人存一条,type=0。接着发广播到SmsReceiver.class中,收到广播后启动SmsReceiverService服务。
SmsReceiverService中调用hander处理信息,发短信的Action为ACTION_SEND_MESSAGE,调用了handleSendMessage()方法,接着sendFirstQueuedMessage()被调用,在sendFirstQueuedMessage()方法中取出了Uri.parse("content://sms/queued")的待发送数据,构建了SmsMessageSender的子类SmsSingleRecipientSender并调用其的sendMessage方法发送消息。sendMessage方法主要是使用SmsManager对短信进行长短信拆分并一个个发送。
smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);
发送成功或者失败都要走SmsReceiverService的handleSmsSent(intent, error);方法。
framework流程:
在SmsManagger的sendMultipartTextMessage方法中判断messages的size,等于1为短信,大于1为长短信,分别走不同流程。
短信:
sendTextMessage(destinationAddress, scAddress, parts.get(0), sentIntent, deliveryIntent);在此方法中调用
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); if (iccISms != null) { iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent); }通过远程调用,被调用的类为IccSmsInterfaceManagerProxy.java,实际处理的类为IccSmsInterfaceManager.java。在IccSmsInterfaceManager的senText方法中调用了
mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent);其中mDispatcher为类SMSDispatcher的对象。用移动卡发了个短信测试后发现此处SMSDispatcher为子类GsmSMSDispatcher,IccSmsInterfaceManager为子类SimSmsInterfaceManager。
在GsmSMSDispatcher的sendText方法里调用了
sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent, destAddr);接着调用了sendSms(tracker)方法,最后调到了
mCm.sendSMS(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply);mCm是CommandsInterface接口的对象,在GsmSMSDispatcher构造时传进来了PhoneBase对象,PhoneBase对象构造时传进去了CommandsInterface对象。PhoneBase对象里的CommandsInterface接口其实就是Ril.java所实现的接口。也就是说Ril.java里的sendSMS方法最后会被调到,之后就是RIL层的事了。
长短信与短信流程基本差不多。
sms表:
type : ALL=0;INBOX=1;SENT=2;DRAFT=3;OUTBOX=4;FAILED=5;QUEUED=6; 6表示等待发送。
status : 32表示启动了发送报告。
二、彩信MMS(ComposeMessageActivity、WorkingMessage、MmsMessageSender、TransactionService)
调用了
sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, textOnly);发送彩信,主要流程为:把一些基本信息存到发件箱内
newMessage = mmsUri == null; if (newMessage) { // Write something in the database so the new message will appear as sending ContentValues values = new ContentValues(); values.put(Mms.MESSAGE_BOX, Mms.MESSAGE_BOX_OUTBOX); values.put(Mms.THREAD_ID, threadId); values.put(Mms.MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ); if (textOnly) { values.put(Mms.TEXT_ONLY, 1); } mmsUri = SqliteWrapper.insert(mActivity, mContentResolver, Mms.Outbox.CONTENT_URI, values); }
接着查询彩信发件箱,所有发件箱内彩信的m_size字段的相加和如果大于4*300*1024,则unDiscard()使得mDiscarded为false,并调用mStatusListener.onMaxPendingMessagesReached()存草稿。
如果待发送的彩信没超出限制,则
mmsUri = createDraftMmsMessage(persister, sendReq, slideshow, mmsUri, mActivity, null);获取uri,如果传进去的uri有id,则不变,否则返回带id的uri,主要通过
Uri res = persister.persist(sendReq, preUri == null ? Mms.Draft.CONTENT_URI : preUri, true, MessagingPreferenceActivity.getIsGroupMmsEnabled(context), preOpenedFiles);得到uri,persist方法把这个带id的uri进行数据更新,如果是不带id的uri,则是插入返回带id的uri。
获取uri后构建发送类,接着发送(sender.sendMessage(threadId))
MessageSender sender = new MmsMessageSender(mActivity, mmsUri, slideshow.getCurrentMessageSize());在sendMessage方法里存了一条数据到pending_msgs数据表内。接着以id为键thread_id为值存到SendingProgressTokenManager中,然后启动TransactionService.class服务。如果发送的彩信是从草稿箱里去的,则通过触发器更新pending_msgs。
TransactionService.class服务中用hander处理消息
switch (msg.what) { case EVENT_NEW_INTENT: onNewIntent((Intent)msg.obj, msg.arg1);在onNewIntent方法里
判断了网络状态noNetwork,intent.getAction()得到的值是null,所以走if流程,以时间为条件获取pending_msgs表中所有时间(due_time)小于或等于当前时间并且err_type字段值小于等于10的数据。如果没网络,则给出提示、stopSelf(serviceId)并返回。
while (cursor.moveToNext()) { int msgType = cursor.getInt(columnIndexOfMsgType); int transactionType = getTransactionType(msgType); if (noNetwork) { onNetworkUnavailable(serviceId, transactionType); return; } switch (transactionType) {如果网络正常则构建TransactionBundle对象,此对象存储以msg_id与mms构成的uri及msg_type变换后的int值。调用launchTransaction(serviceId, transactionBundle, false);方法。接着又调用了hander的处理,key为EVENT_TRANSACTION_REQUEST。接着根据msg_type不同构建不同类型的Transaction子类对象。
if (!processTransaction(transaction)) {开始发送彩信,先排除掉短信正在发送或者已发送的情况后再判断网络,如果网络良好则往下走,否则保存要发送的信息返回
int connectivityResult = beginMmsConnectivity(); if (connectivityResult == PhoneConstants.APN_REQUEST_STARTED) { mPending.add(transaction); if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "processTransaction: connResult=APN_REQUEST_STARTED, " + "defer transaction pending MMS connectivity"); } return true; }如果没返回最后会走到开始发送:
transaction.attach(TransactionService.this); transaction.process();正式开始处理发送,process()方法里启动一个线程,在线的run方法里构建了SendReq对象,调用
byte[] response = sendPdu(SendingProgressTokenManager.get(tokenKey), new PduComposer(mContext, sendReq).make());发送信息,每次发送不管成功与否都会更新data字段,根据response更新resp_st字段,如果发送成功了更新m_id(信息中心的?)字段,最后
// Move M-Send.req from Outbox into Sent. Uri uri = persister.move(mSendReqURI, Sent.CONTENT_URI);把信息由发件箱移到
已发送。
发送彩信采用的是http的方式,sendPdu一直到最后调用了
protected static byte[] httpConnection(Context context, long token, String url, byte[] pdu, int method, boolean isProxySet, String proxyHost, int proxyPort) throws IOException {发送。
对于发送前判断的网络没准备好而保存的数据,在onCreate中注册了广播接收者,当网络恢复时接收广播,最后调用
renewMmsConnectivity(); mServiceHandler.processPendingTransaction(null, settings);
在processPendingTransaction方法中取出未发送的数据,继续走processTransaction流程。
彩信发送结果:
在SendTransaction中发送完彩信后返回结果数组 byte[] response ,解析返回值后更新mms数据,最后调用notifyObservers()方法,而在此类构建时
attach(RetryScheduler.getInstance(context))
把observer类 RetryScheduler注册到此类中,最后在RetryScheduler的update方法中对返回结果处理(弹Toast)。
短信发送结果:
在SmsSingleRecipientSender中发送后会以action为SmsReceiverService.MESSAGE_SENT_ACTION启动SmsReceiverService,最后在handleSmsSent方法里处理结果值,如果没插卡,mResultCode == SmsManager.RESULT_ERROR_NO_SERVICE会把短信状态切回type ==6.
相关文章推荐
- SMS-MMS的草稿箱
- NYOJ 会场安排问题
- 通过JDBC 连接MySQL问题
- JAVA开发环境配置
- 树结点,与度=边
- python ipython notebook教程
- 欢迎使用CSDN-markdown编辑器
- Ubuntu装完之后要……_(:з」∠)_
- 课后作业1
- [转载] Java字符串格式化
- SMS注册与接收短信
- POJ3630 Phone List 题解&代码
- ZOJ Paint the Grid Reloaded
- [HDU 2896] - 病毒侵袭 ac 自动机
- 一次多进程的小尝试
- hadoop搭建完毕后启动hadoop弹出ssh警告提示的解决办法
- ser2net和socat
- python入门
- 关于学科的疑惑
- [BZOJ1036][ZJOI2008]树的统计Count(树链剖分)