彩信已留置送达是什么意思已读的意思吗

经验7620 米
在线时间1362 小时
版本5.9.16
机型小米手机4i
签到次数221
MIUI版本5.9.16
[症状表现]
卡是邢台的&&人在青岛&&前段时间沒有此问题
[重现步骤]
[备注说明]
& && && && &
分享到微信朋友圈
打开微信,点击底部的“发现”,使用 “扫一扫” 即可将网页分享到我的朋友圈。
经验1984 米
在线时间220 小时
版本MIUI-5.1.8-internal
机型小米手机3/4 WCDMA版
签到次数31
MIUI版本MIUI-5.1.8-internal
欠费会发生这种情况,也可能是APN设置有问题。
抓取LOG的方法:
1、在发生故障后,开启拨号程序,拨打*#*#284#*#*
2、1分钟之后,系统会弹一个小窗告诉你已经抓取完成
3、去sd卡的MIUI\debug_log目录抓取最新的zip包传上来
经验7620 米
在线时间1362 小时
版本5.9.16
机型小米手机4i
签到次数221
MIUI版本5.9.16
没修改过apn
原则重要,沟通更重要!
经验7620 米
在线时间1362 小时
版本5.9.16
机型小米手机4i
签到次数221
MIUI版本5.9.16
接收彩信正常
原则重要,沟通更重要!
经验1984 米
在线时间220 小时
版本MIUI-5.1.8-internal
机型小米手机3/4 WCDMA版
签到次数31
MIUI版本MIUI-5.1.8-internal
本帖最后由 Prometheus 于
11:08 编辑
已拒绝这种答复一般是运营商对彩信发回来的明确回执,比如彩信大小过大,或者格式有问题,或者剩余资费不够发本条彩信。也可能是目前运营商无法处理彩信发送。
小米手机1终身荣誉勋章
小米手机1终身荣誉勋章
MIUI 3000万
MIUI 3000万发烧友纪念勋章
MIUI 2000万
MIUI 2000万发烧友纪念勋章
MIUI三周年
MIUI三周年纪念勋章
已关注微信
1000万用户纪念勋章
MIUI1000万用户纪念勋章
关注腾讯微博
已关注腾讯微博
关注新浪微博
已关注新浪微博
MIUI 100周
100周发布纪念勋章
小米手机元器件合体活动勋章
小米求合体勋章
一周年纪念勋章
一周年纪念勋章
Copyright (C) 2015 MIUI
京ICP备号 | 京公网安备5号 | 京ICP证110507号彩信的接收简介:
&&&&&&&&&&&&&&&&主要是由应用程序负责从彩信服务中心(MMSC Multimedia Messaging Service Center)下载彩信信息。大致的流程是Frameworks会先发出一条短信,告知应用程序有一个彩信,短信中含有一些信息比如过期日期,发送者手机号码,彩信的URL等,然后应用程序自行通过HTTP取回URL所指的彩信内容。具体的流程为:
Telephony Frameworks会先发出一个Intent:android.provider.Telephony.Intents.WAP_PUSH_RECEIVED_ACTION=”android.provider.Telephony.WAP_PUSH_RECEIVED”告知上层应用有一个彩信来了。这个Intent中会含有一个”data”byte数组(通过byte[] data = intent.getByteArrayExtra(“data”)来获取),这个Byte数组是关于这个彩信的一些信息的描述,它是一个NotificationInd,里面含有彩信的一些信息,比如发送者手机号码,彩信的ContentLocation(URL)。之后是由应用程序来决定如何做下一步的处理。
在Mms中是由transaction.PushReceiver.java来接收WAP_PUSH_RECEIVED_ACTION,接收到彩信通知Intent后,它会做一些预处理,把data字段取出来,用Pdu的工具解析成为GenericPdu,然后转化为NotificationInd,并把它写入数据库,然后会启动TransactionService来做进一步的NOTIFICATION_TRANSACTION处理,同时把这个NotificationInd的Uri也传过去。
TransactionService被唤起,在其onStartCommand中会处理一下把PushReceiver所传来的Intent放入自己的MessageQueue中,然后在Handler.handleMessage()中处理TRANSACTION_REQUEST时处理NOTIFICATION_TRANSACTION。先是加载默认的一些彩信相关的配置信息,主要是MMSC,Proxy和Port,这些都是与运营商相关的信息,可以通过APN的设置来更改。TransactionService用PushReciver传来的NotificationInd的Uri和加载的配置信息TransactionSettings构建一个NotificationTransaction对象。之后,TransactionService检查其内的二个队列,或是加入Pending队列,或是直接处理(加入到正在处理队列),处理也是直接调用NotificationTransaction.process()。
NotificationTransaction的process()方法是继承自父类Transaction的方法,它只是简单的开启一个新的线程,然后返回,这样就可以让Service去处理其他的Transaction Request了。
在线程中,首先从DownloadManager和TelephonyManager中加载一些配置信息,是否彩信设置为自动获取(auto retrieve),以及Telephony是否设置为数据延迟(DATA_SUSPEND),然后会采取不同的措施,再从NotificationInd中取出彩信的过期日期。如果配置为不取数据(更确切的说,是不现在取数据),那么就先给DownloadManager的状态标记为STATE_UNSTARTED,再给MMSC发送一个Notify
Response Indication,之后结束处理,函数返回,彩信的通知处理流程到此为止。用户可以通过操作UI,用其他方法手动下载彩信,这个会在后面详细讨论。
如果设置为自动获取或者数据传输是畅通的,那么就把DownloadManager状态标记为START_DOWNLOADING并开始下载彩信数据。彩信的获取是通过HTTP到彩信的ContentLocation(URL)取得数据。先是调用父类方法getPdu(),传入彩信的URL,最终调用HttpUtils的httpConnection方法发送HTTP GET请求,MMSC会把彩信数据返回,作为getPdu()的返回值返回。拿到的是一个byte数组,需要用Pdu的工具解析成为GenericPdu,然后用PduPersister把其写入数据库,再把彩信的大小更新到数据库,到这里一个彩信的接收就算完成了。剩下的就是,因为已经获得了彩信的数据,所以要把先前的通知信息(NotificationInd)删除掉,然后更新一下相关的状态,给MMSC返回Notify
Response Indication,结束处理。
如前所述,如果彩信配置设置为不自动获取,那么UI刷新了后就会显示彩信通知:到期日期,彩信大小等,并提供一个”Download”按扭。用户可以点击按扭来下载彩信内容,点击按扭后,会启动TransactionService,把彩信通知的Uri,和RETRIEVE_TRANSACTION request打包进一个Intent传给TransactionService。TransactionService,像处理其他的Transaction一样,都是放进自己的MessageQueue,然后加载默认的TransactionSettings,构建RetrieveTransaction对象,然后处理调用RetrieveTransaction.process()。
RetrieveTransaction也是继承自Transaction,其process()也是创建一个线程,然后返回。在线程中,首先它用Pdu工具根据Uri从数据库中加载出彩信通知(NotificationInd),从NotificationInd中取得彩信的过期日期,检查过期日期,如果彩信已经过期,那么给MMSC发送Notify Response Indication。把DownloadManager状态标记为开始下载,然后如果彩信已过期,标记Transaction状态为Failed,然后返回,结束处理流程。如果一切正常,会用getPdu()从彩信的ContentLocation(URL)上面获取彩信内容,它会用HttpUtils.httpConnection()通过HTTP来获取,返回一个byte数组。用Pdu工具解析byte数组,得到GenericPdu,检查一下是否是新信息,是否是重复的信息,如果重复,标记状为失败,然后返回,结束处理。如果是新信息,先把GenericPdu用PduPersister写入数据库中,更新信息大小和ContentLocation(URL)到数据库中,到这里一个彩信其实已经全部获取完了。接下来就是发送收到确认信息给MMSC,标记处理状态为成功,结束处理。这时UI应该监听到数据库变化,并刷新,新信息应该会显示给用户。
&&&&&&&&&&&&&&&& 在分析代码之前,也是首先与大家分享一下在网络上很流行的两张顺序图,本人也受到了很大的启发。
&&&&&&&&&&&&&&&& android的彩信接收应用层部分从PushReceiver类开始。当onReceive被调用后,让屏幕亮5秒(&wl.acquire(5000);),然后创建一个ReceivePushTask并使用它的execute方法。ReceivePushTask(内部类)是一个AsyncTask,实现了doInBackground()方法。根据消息类型做出相应的处理。
&&&&&&&&&&&&&&& 调用PushReceiver.java类中的doInBackground()方法,部分代码如下:《TAG 2-1》
&&&&&&&&&&&&&&&&&&&&&&& case MESSAGE_TYPE_NOTIFICATION_IND: {
&&&&&&&&&&&&&&&&&&&&&&& NotificationInd nInd = (NotificationInd)
&&&&&&&&&&&&&&&&&&&&&&& if (MmsConfig.getTransIdEnabled()) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& byte [] contentLocation = nInd.getContentLocation();
&&&&&&&&&&&&&&&&&&&&&&&&&&& if ('=' == contentLocation[contentLocation.length - 1]) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& byte [] transactionId = nInd.getTransactionId();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& byte [] contentLocationWithId = new byte [contentLocation.length
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& + transactionId.length];
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& System.arraycopy(contentLocation, 0, contentLocationWithId,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 0, contentLocation.length);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& System.arraycopy(transactionId, 0, contentLocationWithId,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& contentLocation.length, transactionId.length);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& nInd.setContentLocation(contentLocationWithId);
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& if (!isDuplicateNotification(mContext, nInd)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& int subId = intent.getIntExtra(MSimConstants.SUBSCRIPTION_KEY, 0);
&&&&&&&&&&&&&&&&&&&&&&&&&&& ContentValues values = new ContentValues(1);
&&&&&&&&&&&&&&&&&&&&&&&&&&& values.put(Mms.SUB_ID, subId);
&&&&&&&&&&&&&&&&&&&&&&&&&&& Uri uri = p.persist(pdu, Inbox.CONTENT_URI,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& true,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& MessagingPreferenceActivity.getIsGroupMmsEnabled(mContext),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& null);
&&&&&&&&&&&&&&&&&&&&&&&&&&& SqliteWrapper.update(mContext, cr, uri, values, null, null);
&&&&&&&&&&&&&&&&&&&&&&&&&&& if (MessageUtils.isMobileDataDisabled(mContext) &&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& !MessageUtils.CAN_SETUP_MMS_DATA) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& MessagingNotification.nonBlockingUpdateNewMessageIndicator(mContext,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& MessagingNotification.THREAD_ALL, false);
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&& // Start service to finish the notification transaction.
&&&&&&&&&&&&&&&&&&&&&&&&&&& Intent svc = new Intent(mContext, TransactionService.class);
&&&&&&&&&&&&&&&&&&&&&&&&&&& svc.putExtra(TransactionBundle.URI, uri.toString());
&&&&&&&&&&&&&&&&&&&&&&&&&&& svc.putExtra(TransactionBundle.TRANSACTION_TYPE,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Transaction.NOTIFICATION_TRANSACTION);
&&&&&&&&&&&&&&&&&&&&&&&&&&& svc.putExtra(Mms.SUB_ID, subId); //destination sub id
&&&&&&&&&&&&&&&&&&&&&&&&&&& svc.putExtra(MultiSimUtility.ORIGIN_SUB_ID,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& MultiSimUtility.getCurrentDataSubscription(mContext));
&&&&&&&&&&&&&&&&&&&&&&&&&&& if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& boolean isSilent = //default, silent enabled.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if (&prompt&.equals(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& SystemProperties.get(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TelephonyProperties.PROPERTY_MMS_TRANSACTION))) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& isSilent =
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if (isSilent) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &MMS silent transaction&);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Intent silentIntent = new Intent(mContext,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& com.android.mms.ui.SelectMmsSubscription.class);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& silentIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& silentIntent.putExtras(svc); //copy all extras
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& mContext.startService(silentIntent);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& } else {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &MMS prompt transaction&);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& triggerPendingOperation(svc, subId);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&& } else {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& mContext.startService(svc);
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& } else if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &Skip downloading duplicate message: &
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& + new String(nInd.getContentLocation()));
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&& doInBackground中将其中的数据转成GenericPdu,并根据其消息类型做出不同的操作。如果是发送报告或已读报告,将其存入数据库。如果是彩信通知,若已存在,则不处理。否则将其存入数据库。启动TransactionService进行处理。TransactionService中的处理主要是调用mServiceHandler,大体过程与发送彩信时相同,只是此处创建的是NotificationTransaction。如果不支持自动下载或数据传输没打开,仅通知mmsc。否则,下载相应彩信,删除彩信通知,通知mmsc,删除超过容量限制的彩信,通知TransactionService处理其余待发送的彩信。
&&&&&&&&&&&& 我们接着进入TransactionService.java类中进行分析,启动服务后,在onStartCommand()方法中接收Intent并进行封装并放入自己的MessageQueue中,在Handler的handleMessgae中进行处理:
&&& @Override
&&& public int onStartCommand(Intent intent, int flags, int startId) {
&&&&&&& if (intent != null) {
&&&&&&&&&&& Log.d(TAG, &onStartCommand(): E&);
&&&&&&&&&&& incRefCount();
&&&&&&&&&&& Message msg = mServiceHandler.obtainMessage(EVENT_NEW_INTENT);
&&&&&&&&&&& msg.arg1 = startId;
&&&&&&&&&&& msg.obj =
&&&&&&&&&&& mServiceHandler.sendMessage(msg);
&&&&&&& return Service.START_NOT_STICKY;
首先调用handleMessage()方法;
&@Override
&&&&&&& public void handleMessage(Message msg) {
&&&&&&&&&&& Log.d(TAG, &Handling incoming message: & + msg + & = & + decodeMessage(msg));
&&&&&&&&&&& Transaction transaction =
&&&&&&&&&&& switch (msg.what) {
&&&&&&&&&&&&&&& case EVENT_NEW_INTENT:
&&&&&&&&&&&&&&&&&&& onNewIntent((Intent)msg.obj, msg.arg1);
&&&&&&&&&&&&&&&&&&&
接着调用onNewIntent()方法;
public void onNewIntent(Intent intent, int serviceId) {
&&&&&&& mConnMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
&&&&&&& /*AddBy:yabin.huang BugID:SWBUG Date:*/
&&&&&&& if (mConnMgr == null) {
&&&&&&&&&&& endMmsConnectivity();
&&&&&&&&&&& decRefCount();
&&&&&&&&&&&
&&&&&&& NetworkInfo ni = mConnMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_MMS);
&&&&&&& boolean noNetwork = ni == null || !ni.isAvailable();
&&&&&&& Log.d(TAG, &onNewIntent: serviceId: & + serviceId + &: & + intent.getExtras() +
&&&&&&&&&&&&&&& & intent=& + intent);
&&&&&&& Log.d(TAG, &&&& networkAvailable=& + !noNetwork);
&&&&&&& Bundle extras = intent.getExtras();
&&&&&&& String action = intent.getAction();//这里的action的值为null
&&&&&&& if ((ACTION_ONALARM.equals(action) || ACTION_ENABLE_AUTO_RETRIEVE.equals(action) ||
&&&&&&&&&&&&&&& (extras == null)) || ((extras != null) && !extras.containsKey(&uri&)
&&&&&&&&&&&&&&& && !extras.containsKey(CANCEL_URI))) {
&&&&&&&&&&& //We hit here when either the Retrymanager triggered us or there is
&&&&&&&&&&& //send operation in which case uri is not set. For rest of the
&&&&&&&&&&& //cases(MT MMS) we hit &else& case.
&&&&&&&&&&& // Scan database to find all pending operations.
&&&&&&&&&&& Cursor cursor = PduPersister.getPduPersister(this).getPendingMessages(
&&&&&&&&&&&&&&&&&&& System.currentTimeMillis());
&&&&&&&&&&& Log.d(TAG, &Cursor= &+DatabaseUtils.dumpCursorToString(cursor));
&&&&&&&&&&& if (cursor != null) {
&&&&&&&&&&&&&&& try {
&&&&&&&&&&&&&&&&&&& int count = cursor.getCount();
&&&&&&&&&&&&&&&&&&& //if more than 1 records are present in DB.
&&&&&&&&&&&&&&&&&&& if (count & 1) {
&&&&&&&&&&&&&&&&&&&&&&& incRefCountN(count-1);
&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &onNewIntent() multiple pending items mRef=& + mRef);
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& Log.d(TAG, &onNewIntent: cursor.count=& + count + & action=& + action);
&&&&&&&&&&&&&&&&&&& if (count == 0) {
&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &onNewIntent: no pending messages. Stopping service.&);
&&&&&&&&&&&&&&&&&&&&&&& RetryScheduler.setRetryAlarm(this);
&&&&&&&&&&&&&&&&&&&&&&& cleanUpIfIdle(serviceId);
&&&&&&&&&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& int columnIndexOfMsgId = cursor.getColumnIndexOrThrow(PendingMessages.MSG_ID);
&&&&&&&&&&&&&&&&&&& int columnIndexOfMsgType = cursor.getColumnIndexOrThrow(
&&&&&&&&&&&&&&&&&&&&&&&&&&& PendingMessages.MSG_TYPE);
&&&&&&&&&&&&&&&&&&& while (cursor.moveToNext()) {
&&&&&&&&&&&&&&&&&&&&&&& int msgType = cursor.getInt(columnIndexOfMsgType);
&&&&&&&&&&&&&&&&&&&&&&& int transactionType = getTransactionType(msgType);
&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &onNewIntent: msgType=& + msgType + & transactionType=& +
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transactionType);
&&&&&&&&&&&&&&&&&&&&&&& if (noNetwork) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& onNetworkUnavailable(serviceId, transactionType);
&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &No network during MO or retry operation&);
&&&&&&&&&&&&&&&&&&&&&&&&&&& decRefCountN(count);
&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &Reverted mRef to =& + mRef);
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& switch (transactionType) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& case -1:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&& case Transaction.RETRIEVE_TRANSACTION:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // If it's a transiently failed transaction,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // we should retry it in spite of current
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // downloading mode. If the user just turned on the auto-retrieve
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // option, we also retry those messages that don't have any errors.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& int failureType = cursor.getInt(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& cursor.getColumnIndexOrThrow(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& PendingMessages.ERROR_TYPE));
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& DownloadManager downloadManager = DownloadManager.getInstance();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& boolean autoDownload = downloadManager.isAuto();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& boolean isMobileDataEnabled = mConnMgr.getMobileDataEnabled();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &onNewIntent: failureType=& + failureType +
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& & action=& + action + & isTransientFailure:& +
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& isTransientFailure(failureType) + & autoDownload=& +
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& autoDownload);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if (!autoDownload || MessageUtils.isMmsMemoryFull()
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& || !isMobileDataEnabled) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // If autodownload is turned off, don't process the
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // transaction.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &onNewIntent: skipping - autodownload off&);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // Logic is twisty. If there's no failure or the failure
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // is a non-permanent failure, we want to process the transaction.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // Otherwise, break out and skip processing this transaction.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if (!(failureType == MmsSms.NO_ERROR ||
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& isTransientFailure(failureType))) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &onNewIntent: skipping - permanent error&);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &onNewIntent: falling through and processing&);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // fall-through
&&&&&&&&&&&&&&&&&&&&&&&&&&& default:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Uri uri = ContentUris.withAppendedId(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Mms.CONTENT_URI,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& cursor.getLong(columnIndexOfMsgId));
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& String txnId = getTxnIdFromDb(uri);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& int subId = getSubIdFromDb(uri);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &SubId from DB= &+subId);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if(subId != MultiSimUtility.getCurrentDataSubscription
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (getApplicationContext())) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &This MMS transaction can not be done&+
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &on current sub. Ignore it. uri=&+uri);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& int destSub = intent.getIntExtra(Mms.SUB_ID, -1);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& int originSub = intent.getIntExtra(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& MultiSimUtility.ORIGIN_SUB_ID, -1);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &Destination Sub = &+destSub);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &Origin Sub = &+originSub);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& addUnique(txnId, destSub, originSub);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TransactionBundle args = new TransactionBundle(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transactionType, uri.toString());
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &onNewIntent: launchTransaction uri=& + uri);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // FIXME: We use the same serviceId for all MMs.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& launchTransaction(serviceId, args, false);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& } finally {
&&&&&&&&&&&&&&&&&&& cursor.close();
&&&&&&&&&&&&&&& }
&&&&&&&&&&& } else {
&&&&&&&&&&&&&&& Log.d(TAG, &onNewIntent: no pending messages. Stopping service.&);
&&&&&&&&&&&&&&& RetryScheduler.setRetryAlarm(this);
&&&&&&&&&&&&&&& cleanUpIfIdle(serviceId);
&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&& }
&&&&&&& } else if ((extras != null) && extras.containsKey(CANCEL_URI)) {
&&&&&&&&&&& String uriStr = intent.getStringExtra(CANCEL_URI);
&&&&&&&&&&& Uri mCancelUri = Uri.parse(uriStr);
&&&&&&&&&&& for (Transaction transaction : mProcessing) {
&&&&&&&&&&&&&&& transaction.cancelTransaction(mCancelUri);
&&&&&&&&&&& }
&&&&&&&&&&& for (Transaction transaction : mPending) {
&&&&&&&&&&&&&&& transaction.cancelTransaction(mCancelUri);
&&&&&&&&&&& }
&&&&&&& } else {
&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE) || DEBUG) {
&&&&&&&&&&&&&&& Log.v(TAG, &onNewIntent: launch transaction...&);
&&&&&&&&&&& }
&&&&&&&&&&& String uriStr = intent.getStringExtra(&uri&);
&&&&&&&&&&& int destSub = intent.getIntExtra(Mms.SUB_ID, -1);
&&&&&&&&&&& int originSub = intent.getIntExtra(MultiSimUtility.ORIGIN_SUB_ID, -1);
&&&&&&&&&&& Uri uri = Uri.parse(uriStr);
&&&&&&&&&&& int subId = getSubIdFromDb(uri);
&&&&&&&&&&& String txnId = getTxnIdFromDb(uri);
&&&&&&&&&&& if (txnId == null) {
&&&&&&&&&&&&&&& Log.d(TAG, &Transaction already over.&);
&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&&&&&& Log.d(TAG, &SubId from DB= &+subId);
&&&&&&&&&&& Log.d(TAG, &Destination Sub = &+destSub);
&&&&&&&&&&& Log.d(TAG, &Origin Sub = &+originSub);
&&&&&&&&&&& if (noNetwork) {
&&&&&&&&&&&&&&& synchronized (mRef) {
&&&&&&&&&&&&&&&&&&& Log.e(TAG, &No network during MT operation&);
&&&&&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&&&&&& addUnique(txnId, destSub, originSub);
&&&&&&&&&&& // For launching NotificationTransaction and test purpose.
&&&&&&&&&&& TransactionBundle args = new TransactionBundle(intent.getExtras());
&&&&&&&&&&& launchTransaction(serviceId, args, noNetwork);
这里调用launchTransaction()方法;
&&& private void launchTransaction(int serviceId, TransactionBundle txnBundle, boolean noNetwork) {
&&&&&&& if (noNetwork) {
&&&&&&&&&&& Log.w(TAG, &launchTransaction: no network error!&);
&&&&&&&&&&& onNetworkUnavailable(serviceId, txnBundle.getTransactionType());
&&&&&&&&&&&
&&&&&&& Message msg = mServiceHandler.obtainMessage(EVENT_TRANSACTION_REQUEST);
&&&&&&& msg.arg1 = serviceId;
&&&&&&& msg.obj = txnB
&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.DEBUG)) {
&&&&&&&&&&& Log.v(TAG, &launchTransaction: sending message & + msg);
&&&&&&& mServiceHandler.sendMessage(msg);
&&&&&&&&&&&& 调用mServiceHandler,根据业务类型创建一个NotificationTransaction对象,如下代码:《TAG 2-2》
&&&&&&&&&&&&& &&&&&&&&&&&&&&& case EVENT_TRANSACTION_REQUEST:
&&&&&&&&&&&&&&&&&&& int serviceId = msg.arg1;
&&&&&&&&&&&&&&&&&&& try {
&&&&&&&&&&&&&&&&&&&&&&& TransactionBundle args = (TransactionBundle) msg.
&&&&&&&&&&&&&&&&&&&&&&& TransactionSettings transactionS
&&&&&&&&&&&&&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &EVENT_TRANSACTION_REQUEST MmscUrl=& +
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& args.getMmscUrl() + & proxy port: & + args.getProxyAddress());
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& // Set the connection settings for this transaction.
&&&&&&&&&&&&&&&&&&&&&&& // If these have not been set in args, load the default settings.
&&&&&&&&&&&&&&&&&&&&&&& String mmsc = args.getMmscUrl();
&&&&&&&&&&&&&&&&&&&&&&& if (mmsc != null) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& transactionSettings = new TransactionSettings(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& mmsc, args.getProxyAddress(), args.getProxyPort());
&&&&&&&&&&&&&&&&&&&&&&& } else {
&&&&&&&&&&&&&&&&&&&&&&&&&&& transactionSettings = new TransactionSettings(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TransactionService.this, null);
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& int transactionType = args.getTransactionType();
&&&&&&&&&&&&&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.DEBUG)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &handle EVENT_TRANSACTION_REQUEST: transactionType=& +
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transactionType + & & + decodeTransactionType(transactionType));
&&&&&&&&&&&&&&&&&&&&&&&&&&& if (transactionSettings != null) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &mmsc=& + transactionSettings.getMmscUrl()
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& + &, address=& + transactionSettings.getProxyAddress()
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& + &, port=& + transactionSettings.getProxyPort());
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& // Create appropriate transaction
&&&&&&&&&&&&&&&&&&&&&&& switch (transactionType) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& case Transaction.NOTIFICATION_TRANSACTION:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& String uri = args.getUri();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if (uri != null) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction = new NotificationTransaction(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TransactionService.this, serviceId,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transactionSettings, uri);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& } else {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // Now it's only used for test purpose.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& byte[] pushData = args.getPushData();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& PduParser parser = new PduParser(pushData);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& GenericPdu ind = parser.parse();
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& int type = PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND;
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if ((ind != null) && (ind.getMessageType() == type)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction = new NotificationTransaction(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TransactionService.this, serviceId,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transactionSettings, (NotificationInd) ind);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& } else {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.e(TAG, &Invalid PUSH data.&);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction =
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&& case Transaction.RETRIEVE_TRANSACTION://这里当用户在界面中点击下载,会调用MessageListItem.java方法中的startDownloadAttachment()方法,随后会走这里。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction = new RetrieveTransaction(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TransactionService.this, serviceId,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transactionSettings, args.getUri());
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&& case Transaction.SEND_TRANSACTION:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction = new SendTransaction(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TransactionService.this, serviceId,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transactionSettings, args.getUri());
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&& case Transaction.READREC_TRANSACTION:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction = new ReadRecTransaction(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TransactionService.this, serviceId,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transactionSettings, args.getUri());
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&& default:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.w(TAG, &Invalid transaction type: & + serviceId);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction =
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& if (!processTransaction(transaction)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction =
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE) || DEBUG) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &Started processing of incoming message: & + msg);
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& } catch (Exception ex) {
&&&&&&&&&&&&&&&&&&&&&&& Log.w(TAG, &Exception occurred while handling message: & + msg, ex);
&&&&&&&&&&&&&&&&&&&&&&& if (transaction != null) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& try {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction.detach(TransactionService.this);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if (mProcessing.contains(transaction)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& synchronized (mProcessing) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& mProcessing.remove(transaction);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&& } catch (Throwable t) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.e(TAG, &Unexpected Throwable.&, t);
&&&&&&&&&&&&&&&&&&&&&&&&&&& } finally {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // Set transaction to null to allow stopping the
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // transaction service.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction =
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& } finally {
&&&&&&&&&&&&&&&&&&&&&&& if (transaction == null) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &Transaction was null. Stopping self: & + serviceId);
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&& launchRetryAttempt++;
&&&&&&&&&&&&&&&&&&&&&&&&&&& if (launchRetryAttempt &= maxLaunchRetryAttempts) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &launchTransaction retry attempt - &
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& + launchRetryAttempt);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TransactionBundle args = (TransactionBundle) msg.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& sleep(5*1000);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& launchTransaction(serviceId, args, false);
&&&&&&&&&&&&&&&&&&&&&&&&&&& } else {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.e(TAG, &Multiple launchTransaction retries failed&);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& launchRetryAttempt = 0;
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&& 这里接着调用processTransaction()方法;
&&&&&&&& */
&&&&&&& private boolean processTransaction(Transaction transaction) throws IOException {
&&&&&&&&&&& // Check if transaction already processing
&&&&&&&&&&& synchronized (mProcessing) {
&&&&&&&&&&&&&&& for (Transaction t : mPending) {
&&&&&&&&&&&&&&&&&&& if (t.isEquivalent(transaction)) {
&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &Transaction already pending: & +
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& transaction.getServiceId());
&&&&&&&&&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& for (Transaction t : mProcessing) {
&&&&&&&&&&&&&&&&&&& if (t.isEquivalent(transaction)) {
&&&&&&&&&&&&&&&&&&&&&&& Log.d(TAG, &Duplicated transaction: & + transaction.getServiceId());
&&&&&&&&&&&&&&&&&&&&&&& decRefCount();
&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& /*
&&&&&&&&&&&&&&& * Make sure that the network connectivity necessary
&&&&&&&&&&&&&&& * for MMS traffic is enabled. If it is not, we need
&&&&&&&&&&&&&&& * to defer processing the transaction until
&&&&&&&&&&&&&&& * connectivity is established.
&&&&&&&&&&&&&&& */
&&&&&&&&&&&&&&& Log.d(TAG, &processTransaction: call beginMmsConnectivity...&);
&&&&&&&&&&&&&&& int connectivityResult = beginMmsConnectivity();
&&&&&&&&&&&&&&& if (connectivityResult == PhoneConstants.APN_REQUEST_STARTED) {
&&&&&&&&&&&&&&&&&&& mPending.add(transaction);
&&&&&&&&&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.DEBUG)) {
&&&&&&&&&&&&&&&&&&&&&&& Log.v(TAG, &processTransaction: connResult=APN_REQUEST_STARTED, & +
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &defer transaction pending MMS connectivity&);
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& Log.d(TAG, &Adding transaction to 'mProcessing' list: & + transaction);
&&&&&&&&&&&&&&& mProcessing.add(transaction);
&&&&&&&&&&& }
&&&&&&&&&&& // Set a timer to keep renewing our &lease& on the MMS connection
&&&&&&&&&&& sendMessageDelayed(obtainMessage(EVENT_CONTINUE_MMS_CONNECTIVITY),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& APN_EXTENSION_WAIT);
&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.DEBUG) || DEBUG) {
&&&&&&&&&&&&&&& Log.v(TAG, &processTransaction: starting transaction & + transaction);
&&&&&&&&&&& }
&&&&&&&&&&& // Attach to transaction and process it
&&&&&&&&&&& transaction.attach(TransactionService.this);
&&&&&&&&&&& transaction.process();
&&&&&&&&&&&
创建调用NotificationTransaction.java类中的Process()方法。
&&& public void process() {
&&&&&&& new Thread(this, &NotificationTransaction&).start();
调用NotificationTransaction.java类中的run()方法,获得彩信数据(!这里需要注意的是,这里所指的下载是指的自动下载,而如果是点击下载按钮进行下载则调用的是RetrieveTransaction.java中的run()方法,或者一定时间内没有自动下载,也没有去点击下载彩信的按钮,也会走RetrieveTransaction.java中的run()方法)《TAG:2-3》
&&& public void run() {
&&&&&&& DownloadManager downloadManager = DownloadManager.getInstance();
&&&&&&& boolean autoDownload = allowAutoDownload();
&&&&&&& boolean isMemoryFull = MessageUtils.isMmsMemoryFull();
&&&&&&& boolean isTooLarge = isMmsSizeTooLarge(mNotificationInd);
&&&&&&& boolean isMobileDataDisabled= MessageUtils.isMobileDataDisabled(mContext);
&&&&&&& try {
&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&& Log.v(TAG, &Notification transaction launched: & + this);
&&&&&&&&&&& }
&&&&&&&&&&& // By default, we set status to STATUS_DEFERRED because we
&&&&&&&&&&& // should response MMSC with STATUS_DEFERRED when we cannot
&&&&&&&&&&& // download a MM immediately.
&&&&&&&&&&& int status = STATUS_DEFERRED;
&&&&&&&&&&& // Don't try to download when data is suspended, as it will fail, so defer download
&&&&&&&&&&& if (!autoDownload || isMobileDataDisabled) {
&&&&&&&&&&&&&&& downloadManager.markState(mUri, DownloadManager.STATE_UNSTARTED);
&&&&&&&&&&&&&&& sendNotifyRespInd(status);
&&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&&&&&& if (isMemoryFull || isTooLarge) {
&&&&&&&&&&&&&&& downloadManager.markState(mUri, DownloadManager.STATE_TRANSIENT_FAILURE);
&&&&&&&&&&&&&&& sendNotifyRespInd(status);
&&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&&&&&& downloadManager.markState(mUri, DownloadManager.STATE_DOWNLOADING);
&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&& Log.v(TAG, &Content-Location: & + mContentLocation);
&&&&&&&&&&& }
&&&&&&&&&&& byte[] retrieveConfData =
&&&&&&&&&&& // We should catch exceptions here to response MMSC
&&&&&&&&&&& // with STATUS_DEFERRED.
&&&&&&&&&&& try {
&&&&&&&&&&&&&&& retrieveConfData = getPdu(mContentLocation);
&&&&&&&&&&& } catch (IOException e) {
&&&&&&&&&&&&&&& mTransactionState.setState(FAILED);
&&&&&&&&&&& }
&&&&&&&&&&& if (retrieveConfData != null) {
&&&&&&&&&&&&&&& if (Log.isLoggable(LogTag.TRANSACTION, Log.DEBUG)) {
&&&&&&&&&&&&&&&&&&& Log.v(TAG, &NotificationTransaction: retrieve data=& +
&&&&&&&&&&&&&&&&&&&&&&&&&&& HexDump.dumpHexString(retrieveConfData));
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& GenericPdu pdu = new PduParser(retrieveConfData).parse();
&&&&&&&&&&&&&&& if ((pdu == null) || (pdu.getMessageType() != MESSAGE_TYPE_RETRIEVE_CONF)) {
&&&&&&&&&&&&&&&&&&& Log.e(TAG, &Invalid M-RETRIEVE.CONF PDU. & +
&&&&&&&&&&&&&&&&&&&&&&&&&&& (pdu != null ? &message type: & + pdu.getMessageType() : &null pdu&));
&&&&&&&&&&&&&&&&&&& mTransactionState.setState(FAILED);
&&&&&&&&&&&&&&&&&&& status = STATUS_UNRECOGNIZED;
&&&&&&&&&&&&&&& } else {
&&&&&&&&&&&&&&&&&&& // Save the received PDU (must be a M-RETRIEVE.CONF).
&&&&&&&&&&&&&&&&&&& PduPersister p = PduPersister.getPduPersister(mContext);
&&&&&&&&&&&&&&&&&&& Uri uri = p.persist(pdu, Inbox.CONTENT_URI, true,
&&&&&&&&&&&&&&&&&&&&&&&&&&& MessagingPreferenceActivity.getIsGroupMmsEnabled(mContext), null);
&&&&&&&&&&&&&&&&&&& // Use local time instead of PDU time
&&&&&&&&&&&&&&&&&&& ContentValues values = new ContentValues(2);
&&&&&&&&&&&&&&&&&&& values.put(Mms.DATE, System.currentTimeMillis() / 1000L);
&&&&&&&&&&&&&&&&&&& Cursor c = mContext.getContentResolver().query(mUri,
&&&&&&&&&&&&&&&&&&&&&&&&&&& null, null, null, null);
&&&&&&&&&&&&&&&&&&& if (c != null) {
&&&&&&&&&&&&&&&&&&&&&&& try {
&&&&&&&&&&&&&&&&&&&&&&&&&&& if (c.moveToFirst()) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& int subId = c.getInt(c.getColumnIndex(Mms.SUB_ID));
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& values.put(Mms.SUB_ID, subId);
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& } catch (Exception ex) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& Log.e(TAG, &Exception:& + ex);
&&&&&&&&&&&&&&&&&&&&&&& } finally {
&&&&&&&&&&&&&&&&&&&&&&&&&&& c.close();
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& SqliteWrapper.update(mContext, mContext.getContentResolver(),
&&&&&&&&&&&&&&&&&&&&&&&&&&& uri, values, null, null);
&&&&&&&&&&&&&&&&&&& // We have successfully downloaded the new MM. Delete the
&&&&&&&&&&&&&&&&&&& // M-NotifyResp.ind from Inbox.
&&&&&&&&&&&&&&&&&&& SqliteWrapper.delete(mContext, mContext.getContentResolver(),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& mUri, null, null);
&&&&&&&&&&&&&&&&&&& Log.v(TAG, &NotificationTransaction received new mms message: & + uri);
&&&&&&&&&&&&&&&&&&& // Delete obsolete threads
&&&&&&&&&&&&&&&&&&& SqliteWrapper.delete(mContext, mContext.getContentResolver(),
&&&&&&&&&&&&&&&&&&&&&&&&&&& Threads.OBSOLETE_THREADS_URI, null, null);
&&&&&&&&&&&&&&&&&&& // Notify observers with newly received MM.
&&&&&&&&&&&&&&&&&&& mUri =
&&&&&&&&&&&&&&&&&&& status = STATUS_RETRIEVED;
&&&&&&&&&&&&&&& }
&&&&&&&&&&& }
&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&& Log.v(TAG, &status=0x& + Integer.toHexString(status));
&&&&&&&&&&& }
&&&&&&&&&&& // Check the status and update the result state of this Transaction.
&&&&&&&&&&& switch (status) {
&&&&&&&&&&&&&&& case STATUS_RETRIEVED:
&&&&&&&&&&&&&&&&&&& mTransactionState.setState(SUCCESS);
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&& case STATUS_DEFERRED:
&&&&&&&&&&&&&&&&&&& // STATUS_DEFERRED, may be a failed immediate retrieval.
&&&&&&&&&&&&&&&&&&& if (mTransactionState.getState() == INITIALIZED) {
&&&&&&&&&&&&&&&&&&&&&&& mTransactionState.setState(SUCCESS);
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&&&&&& sendNotifyRespInd(status);
&&&&&&&&&&& // Make sure this thread isn't over the limits in message count.
&&&&&&&&&&& Recycler.getMmsRecycler().deleteOldMessagesInSameThreadAsMessage(mContext, mUri);
&&&&&&&&&&& MmsWidgetProvider.notifyDatasetChanged(mContext);
&&&&&&& } catch (Throwable t) {
&&&&&&&&&&& Log.e(TAG, Log.getStackTraceString(t));
&&&&&&& } finally {
&&&&&&&&&&& mTransactionState.setContentUri(mUri);
&&&&&&&&&&& if (!autoDownload || isMemoryFull || isTooLarge || isMobileDataDisabled) {
&&&&&&&&&&&&&&& // Always mark the transaction successful for deferred
&&&&&&&&&&&&&&& // download since any error here doesn't make sense.
&&&&&&&&&&&&&&& mTransactionState.setState(SUCCESS);
&&&&&&&&&&& }
&&&&&&&&&&& if (mTransactionState.getState() != SUCCESS) {
&&&&&&&&&&&&&&& mTransactionState.setState(FAILED);
&&&&&&&&&&&&&&& Log.e(TAG, &NotificationTransaction failed.&);
&&&&&&&&&&& }
&&&&&&&&&&& notifyObservers();
&&&&&&&&&&&& 上述代码《TAG:2-3》中,调用Transaction.java类中的getPdu()方法下载彩信数据:
&&& protected byte[] getPdu(String url) throws IOException {
&&&&&&& ensureRouteToHost(url, mTransactionSettings);
&&&&&&& return HttpUtils.httpConnection(
&&&&&&&&&&&&&&& mContext, SendingProgressTokenManager.NO_TOKEN,
&&&&&&&&&&&&&&& url, null, HttpUtils.HTTP_GET_METHOD,
&&&&&&&&&&&&&&& mTransactionSettings.isProxySet(),
&&&&&&&&&&&&&&& mTransactionSettings.getProxyAddress(),
&&&&&&&&&&&&&&& mTransactionSettings.getProxyPort());
上述代码《TAG:2-3》中,调用PduParser.java类中的parse()方法解析彩信数据,PduParser类是用于把PDU字节流解析成为Android可识别的GenericPdu:《TAG:2-4》
&public PduParser(byte[] pduDataStream) {
&&&&&&& mPduDataStream = new ByteArrayInputStream(pduDataStream);
&&&& * Parse the pdu.
&&&& * @return the pdu structure if parsing successfully.
&&&& *&&&&&&&& null if parsing error happened or mandatory fields are not set.
&&& public GenericPdu parse(){
&&&&&&& & if (mPduDataStream == null) {
&&&&&&&&&&&
&&&&&&& /* parse headers */
&&&&&&& mHeaders = parseHeaders(mPduDataStream);
&&&&&&& if (null == mHeaders) {
&&&&&&&&&&& // Parse headers failed.
&&&&&&&&&&&
&&&&&&& /* get the message type */
&&&&&&& int messageType = mHeaders.getOctet(PduHeaders.MESSAGE_TYPE);
&&&&&&& /* check mandatory header fields */
&&&&&&& if (false == checkMandatoryHeader(mHeaders)) {
&&&&&&&&&&& log(&check mandatory headers failed!&);
&&&&&&&&&&&
&&&&&&& if ((PduHeaders.MESSAGE_TYPE_SEND_REQ == messageType) ||
&&&&&&&&&&&&&&& (PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF == messageType)) {
&&&&&&&&&&& /* need to parse the parts */
&&&&&&&&&&& mBody = parseParts(mPduDataStream);
&&&&&&&&&&& if (null == mBody) {
&&&&&&&&&&&&&&& // Parse parts failed.
&&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&& switch (messageType) {
&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_SEND_REQ:
&&&&&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&& Log.v(LOG_TAG, &parse: MESSAGE_TYPE_SEND_REQ&);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& SendReq sendReq = new SendReq(mHeaders, mBody);
&&&&&&&&&&&&&&& return sendR
&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_SEND_CONF:
&&&&&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&& Log.v(LOG_TAG, &parse: MESSAGE_TYPE_SEND_CONF&);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& SendConf sendConf = new SendConf(mHeaders);
&&&&&&&&&&&&&&& return sendC
&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
&&&&&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&& Log.v(LOG_TAG, &parse: MESSAGE_TYPE_NOTIFICATION_IND&);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& NotificationInd notificationInd =
&&&&&&&&&&&&&&&&&&& new NotificationInd(mHeaders);
&&&&&&&&&&&&&&& return notificationI
&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND:
&&&&&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&& Log.v(LOG_TAG, &parse: MESSAGE_TYPE_NOTIFYRESP_IND&);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& NotifyRespInd notifyRespInd =
&&&&&&&&&&&&&&&&&&& new NotifyRespInd(mHeaders);
&&&&&&&&&&&&&&& return notifyRespI
&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
&&&&&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&& Log.v(LOG_TAG, &parse: MESSAGE_TYPE_RETRIEVE_CONF&);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& RetrieveConf retrieveConf =
&&&&&&&&&&&&&&&&&&& new RetrieveConf(mHeaders, mBody);
&&&&&&&&&&&&&&& byte[] contentType = retrieveConf.getContentType();
&&&&&&&&&&&&&&& if (null == contentType) {
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& String ctTypeStr = new String(contentType);
&&&&&&&&&&&&&&& if (ctTypeStr.equals(ContentType.MULTIPART_MIXED)
&&&&&&&&&&&&&&&&&&&&&&& || ctTypeStr.equals(ContentType.MULTIPART_RELATED)
&&&&&&&&&&&&&&&&&&&&&&& || ctTypeStr.equals(ContentType.MULTIPART_ALTERNATIVE)) {
&&&&&&&&&&&&&&&&&&& // The MMS content type must be &application/vnd.wap.multipart.mixed&
&&&&&&&&&&&&&&&&&&& // or &application/vnd.wap.multipart.related&
&&&&&&&&&&&&&&&&&&& // or &application/vnd.wap.multipart.alternative&
&&&&&&&&&&&&&&&&&&& return retrieveC
&&&&&&&&&&&&&&& } else if (ctTypeStr.equals(ContentType.MULTIPART_ALTERNATIVE)) {
&&&&&&&&&&&&&&&&&&& // &application/vnd.wap.multipart.alternative&
&&&&&&&&&&&&&&&&&&& // should take only the first part.
&&&&&&&&&&&&&&&&&&& PduPart firstPart = mBody.getPart(0);
&&&&&&&&&&&&&&&&&&& mBody.removeAll();
&&&&&&&&&&&&&&&&&&& mBody.addPart(0, firstPart);
&&&&&&&&&&&&&&&&&&& return retrieveC
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&
&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_DELIVERY_IND:
&&&&&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&& Log.v(LOG_TAG, &parse: MESSAGE_TYPE_DELIVERY_IND&);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& DeliveryInd deliveryInd =
&&&&&&&&&&&&&&&&&&& new DeliveryInd(mHeaders);
&&&&&&&&&&&&&&& return deliveryI
&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND:
&&&&&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&& Log.v(LOG_TAG, &parse: MESSAGE_TYPE_ACKNOWLEDGE_IND&);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& AcknowledgeInd acknowledgeInd =
&&&&&&&&&&&&&&&&&&& new AcknowledgeInd(mHeaders);
&&&&&&&&&&&&&&& return acknowledgeI
&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_READ_ORIG_IND:
&&&&&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&& Log.v(LOG_TAG, &parse: MESSAGE_TYPE_READ_ORIG_IND&);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& ReadOrigInd readOrigInd =
&&&&&&&&&&&&&&&&&&& new ReadOrigInd(mHeaders);
&&&&&&&&&&&&&&& return readOrigI
&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_READ_REC_IND:
&&&&&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&& Log.v(LOG_TAG, &parse: MESSAGE_TYPE_READ_REC_IND&);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& ReadRecInd readRecInd =
&&&&&&&&&&&&&&&&&&& new ReadRecInd(mHeaders);
&&&&&&&&&&&&&&& return readRecI
&&&&&&&&&&& default:
&&&&&&&&&&&&&&& log(&Parser doesn't support this message type in this version!&);
&&&&&&&&&&&
上述代码中《TAG2-4》中调用parseParts()方法解析pdupart:
protected static PduBody parseParts(ByteArrayInputStream pduDataStream) {
&&&&&&& if (pduDataStream == null) {
&&&&&&&&&&&
&&&&&&& int count = parseUnsignedInt(pduDataStream); // get the number of parts
&&&&&&& PduBody body = new PduBody();
&&&&&&& for (int i = 0 ; i & i++) {
&&&&&&&&&&& int headerLength = parseUnsignedInt(pduDataStream);
&&&&&&&&&&& int dataLength = parseUnsignedInt(pduDataStream);
&&&&&&&&&&& PduPart part = new PduPart();
&&&&&&&&&&& int startPos = pduDataStream.available();
&&&&&&&&&&& if (startPos &= 0) {
&&&&&&&&&&&&&&& // Invalid part.
&&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&&&&&& /* parse part's content-type */
&&&&&&&&&&& HashMap&Integer, Object& map = new HashMap&Integer, Object&();
&&&&&&&&&&& byte[] contentType = parseContentType(pduDataStream, map);
&&&&&&&&&&& if (null != contentType) {
&&&&&&&&&&&&&&& part.setContentType(contentType);
&&&&&&&&&&& } else {
&&&&&&&&&&&&&&& part.setContentType((PduContentTypes.contentTypes[0]).getBytes()); //&*/*&
&&&&&&&&&&& }
&&&&&&&&&&& /* get name parameter */
&&&&&&&&&&& byte[] name = (byte[]) map.get(PduPart.P_NAME);
&&&&&&&&&&& if (null != name) {
&&&&&&&&&&&&&&& part.setName(name);
&&&&&&&&&&& }
&&&&&&&&&&& /* get charset parameter */
&&&&&&&&&&& Integer charset = (Integer) map.get(PduPart.P_CHARSET);
&&&&&&&&&&& if (null != charset) {
&&&&&&&&&&&&&&& part.setCharset(charset);
&&&&&&&&&&& }
&&&&&&&&&&& /* parse part's headers */
&&&&&&&&&&& int endPos = pduDataStream.available();
&&&&&&&&&&& int partHeaderLen = headerLength - (startPos - endPos);
&&&&&&&&&&& if (partHeaderLen & 0) {
&&&&&&&&&&&&&&& if (false == parsePartHeaders(pduDataStream, part, partHeaderLen)) {
&&&&&&&&&&&&&&&&&&& // Parse part header faild.
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&& }
&&&&&&&&&&& } else if (partHeaderLen & 0) {
&&&&&&&&&&&&&&& // Invalid length of content-type.
&&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&&&&&& /* FIXME: check content-id, name, filename and content location,
&&&&&&&&&&&& * if not set anyone of them, generate a default content-location
&&&&&&&&&&&& */
&&&&&&&&&&& if ((null == part.getContentLocation())
&&&&&&&&&&&&&&&&&&& && (null == part.getName())
&&&&&&&&&&&&&&&&&&& && (null == part.getFilename())
&&&&&&&&&&&&&&&&&&& && (null == part.getContentId())) {
&&&&&&&&&&&&&&& part.setContentLocation(Long.toOctalString(
&&&&&&&&&&&&&&&&&&&&&&& System.currentTimeMillis()).getBytes());
&&&&&&&&&&& }
&&&&&&&&&&& /* get part's data */
&&&&&&&&&&& if (dataLength & 0) {
&&&&&&&&&&&&&&& byte[] partData = new byte[dataLength];
&&&&&&&&&&&&&&& String partContentType = new String(part.getContentType());
&&&&&&&&&&&&&&& pduDataStream.read(partData, 0, dataLength);
&&&&&&&&&&&&&&& if (partContentType.equalsIgnoreCase(ContentType.MULTIPART_ALTERNATIVE)) {
&&&&&&&&&&&&&&&&&&& // parse &multipart/vnd.wap.multipart.alternative&.
&&&&&&&&&&&&&&&&&&& PduBody childBody = parseParts(new ByteArrayInputStream(partData));
&&&&&&&&&&&&&&&&&&& // take the first part of children.
&&&&&&&&&&&&&&&&&&& part = childBody.getPart(0);
&&&&&&&&&&&&&&& } else {
&&&&&&&&&&&&&&&&&&& // Check Content-Transfer-Encoding.
&&&&&&&&&&&&&&&&&&& byte[] partDataEncoding = part.getContentTransferEncoding();
&&&&&&&&&&&&&&&&&&& if (null != partDataEncoding) {
&&&&&&&&&&&&&&&&&&&&&&& String encoding = new String(partDataEncoding);
&&&&&&&&&&&&&&&&&&&&&&& if (encoding.equalsIgnoreCase(PduPart.P_BASE64)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& // Decode &base64& into &binary&.
&&&&&&&&&&&&&&&&&&&&&&&&&&& partData = Base64.decodeBase64(partData);
&&&&&&&&&&&&&&&&&&&&&&& } else if (encoding.equalsIgnoreCase(PduPart.P_QUOTED_PRINTABLE)) {
&&&&&&&&&&&&&&&&&&&&&&&&&&& // Decode &quoted-printable& into &binary&.
&&&&&&&&&&&&&&&&&&&&&&&&&&& partData = QuotedPrintable.decodeQuotedPrintable(partData);
&&&&&&&&&&&&&&&&&&&&&&& } else {
&&&&&&&&&&&&&&&&&&&&&&&&&&& // &binary& is the default encoding.
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& if (null == partData) {
&&&&&&&&&&&&&&&&&&&&&&& log(&Decode part data error!&);
&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& part.setData(partData);
&&&&&&&&&&&&&&& }
&&&&&&&&&&& }
&&&&&&&&&&& /* add this part to body */
&&&&&&&&&&& if (THE_FIRST_PART == checkPartPosition(part)) {
&&&&&&&&&&&&&&& /* this is the first part */
&&&&&&&&&&&&&&& body.addPart(0, part);
&&&&&&&&&&& } else {
&&&&&&&&&&&&&&& /* add the part to the end */
&&&&&&&&&&&&&&& body.addPart(part);
&&&&&&&&&&& }
上述代码《TAG:2-3》中,调用PduPersister.java类中的persist()方法;《TAG:2-5》PduPersister类用于管理PDU存储,为什么会要把PDU的存储也封装成PduPersister呢?因为PDU的存储方式 是放在标准的SQLiteDatabase中,通过TelephonyProvider,而SQLiteDatabase中存储不能以直接的PDU的字节流来存储,必须要把PDU拆解成为可读的字段,因此在存储PDU和从存储加载PDU的过程
中涉及到PDU数据上面的处理,因此封装出来,更方便使用。其中persist(GenericPdu, Uri)方法把一个GenericPdu保存到Uri所指定的数据库中,返回指向新生成数据的Uri;load(Uri)方法从数据库把Uri所指的数据加载出来成一个GenericPdu对象;move(Uri, Uri)方法把Pdu从一个地方移到另一个地方,比如从草稿箱移动到发件箱,当MMS已发送时。
&public Uri persist(GenericPdu pdu, Uri uri, boolean createThreadId, boolean groupMmsEnabled,
&&&&&&&&&&& HashMap&Uri, InputStream& preOpenedFiles)
&&&&&&&&&&& throws MmsException {
&&&&&&& if (uri == null) {
&&&&&&&&&&& throw new MmsException(&Uri may not be null.&);
&&&&&&& long msgId = -1;
&&&&&&& try {
&&&&&&&&&&& msgId = ContentUris.parseId(uri);
&&&&&&& } catch (NumberFormatException e) {
&&&&&&&&&&& // the uri ends with &inbox& or something else like that
&&&&&&& boolean existingUri = msgId != -1;
&&&&&&& if (!existingUri && MESSAGE_BOX_MAP.get(uri) == null) {
&&&&&&&&&&& throw new MmsException(
&&&&&&&&&&&&&&&&&&& &Bad destination, must be one of &
&&&&&&&&&&&&&&&&&&& + &content://mms/inbox, content://mms/sent, &
&&&&&&&&&&&&&&&&&&& + &content://mms/drafts, content://mms/outbox, &
&&&&&&&&&&&&&&&&&&& + &content://mms/temp.&);
&&&&&&& synchronized(PDU_CACHE_INSTANCE) {
&&&&&&&&&&& // If the cache item is getting updated, wait until it's done updating before
&&&&&&&&&&& // purging it.
&&&&&&&&&&& if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
&&&&&&&&&&&&&&& if (LOCAL_LOGV) {
&&&&&&&&&&&&&&&&&&& Log.v(TAG, &persist: & + uri + & blocked by isUpdating()&);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& try {
&&&&&&&&&&&&&&&&&&& PDU_CACHE_INSTANCE.wait();
&&&&&&&&&&&&&&& } catch (InterruptedException e) {
&&&&&&&&&&&&&&&&&&& Log.e(TAG, &persist1: &, e);
&&&&&&&&&&&&&&& }
&&&&&&&&&&& }
&&&&&&& PDU_CACHE_INSTANCE.purge(uri);
&&&&&&& PduHeaders header = pdu.getPduHeaders();
&&&&&&& PduBody body =
&&&&&&& ContentValues values = new ContentValues();
&&&&&&& Set&Entry&Integer, String&&
&&&&&&& set = ENCODED_STRING_COLUMN_NAME_MAP.entrySet();
&&&&&&& for (Entry&Integer, String& e : set) {
&&&&&&&&&&& int field = e.getKey();
&&&&&&&&&&& EncodedStringValue encodedString = header.getEncodedStringValue(field);
&&&&&&&&&&& if (encodedString != null) {
&&&&&&&&&&&&&&& String charsetColumn = CHARSET_COLUMN_NAME_MAP.get(field);
&&&&&&&&&&&&&&& values.put(e.getValue(), toIsoString(encodedString.getTextString()));
&&&&&&&&&&&&&&& values.put(charsetColumn, encodedString.getCharacterSet());
&&&&&&&&&&& }
&&&&&&& set = TEXT_STRING_COLUMN_NAME_MAP.entrySet();
&&&&&&& for (Entry&Integer, String& e : set){
&&&&&&&&&&& byte[] text = header.getTextString(e.getKey());
&&&&&&&&&&& if (text != null) {
&&&&&&&&&&&&&&& values.put(e.getValue(), toIsoString(text));
&&&&&&&&&&& }
&&&&&&& set = OCTET_COLUMN_NAME_MAP.entrySet();
&&&&&&& for (Entry&Integer, String& e : set){
&&&&&&&&&&& int b = header.getOctet(e.getKey());
&&&&&&&&&&& if (b != 0) {
&&&&&&&&&&&&&&& values.put(e.getValue(), b);
&&&&&&&&&&& }
&&&&&&& set = LONG_COLUMN_NAME_MAP.entrySet();
&&&&&&& for (Entry&Integer, String& e : set){
&&&&&&&&&&& long l = header.getLongInteger(e.getKey());
&&&&&&&&&&& if (l != -1L) {
&&&&&&&&&&&&&&& values.put(e.getValue(), l);
&&&&&&&&&&& }
&&&&&&& HashMap&Integer, EncodedStringValue[]& addressMap =
&&&&&&&&&&&&&&& new HashMap&Integer, EncodedStringValue[]&(ADDRESS_FIELDS.length);
&&&&&&& // Save address information.
&&&&&&& for (int addrType : ADDRESS_FIELDS) {
&&&&&&&&&&& EncodedStringValue[] array =
&&&&&&&&&&& if (addrType == PduHeaders.FROM) {
&&&&&&&&&&&&&&& EncodedStringValue v = header.getEncodedStringValue(addrType);
&&&&&&&&&&&&&&& if (v != null) {
&&&&&&&&&&&&&&&&&&& array = new EncodedStringValue[1];
&&&&&&&&&&&&&&&&&&& array[0] =
&&&&&&&&&&&&&&& }
&&&&&&&&&&& } else {
&&&&&&&&&&&&&&& array = header.getEncodedStringValues(addrType);
&&&&&&&&&&& }
&&&&&&&&&&& addressMap.put(addrType, array);
&&&&&&& HashSet&String& recipients = new HashSet&String&();
&&&&&&& int msgType = pdu.getMessageType();
&&&&&&& // Here we only allocate thread ID for M-Notification.ind,
&&&&&&& // M-Retrieve.conf and M-Send.req.
&&&&&&& // Some of other PDU types may be allocated a thread ID outside
&&&&&&& // this scope.
&&&&&&& if ((msgType == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND)
&&&&&&&&&&&&&&& || (msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
&&&&&&&&&&&&&&& || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
&&&&&&&&&&& switch (msgType) {
&&&&&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
&&&&&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
&&&&&&&&&&&&&&&&&&& loadRecipients(PduHeaders.FROM, recipients, addressMap, false);
&&&&&&&&&&&&&&&&&&& // For received messages when group MMS is enabled, we want to associate this
&&&&&&&&&&&&&&&&&&& // message with the thread composed of all the recipients -- all but our own
&&&&&&&&&&&&&&&&&&& // number, that is. This includes the person who sent the
&&&&&&&&&&&&&&&&&&& // message or the FROM field (above) in addition to the other people the message
&&&&&&&&&&&&&&&&&&& // was addressed to or the TO field. Our own number is in that TO field and
&&&&&&&&&&&&&&&&&&& // we have to ignore it in loadRecipients.
&&&&&&&&&&&&&&&&&&& if (groupMmsEnabled) {
&&&&&&&&&&&&&&&&&&&&&&& loadRecipients(PduHeaders.TO, recipients, addressMap, true);
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&& case PduHeaders.MESSAGE_TYPE_SEND_REQ:
&&&&&&&&&&&&&&&&&&& loadRecipients(PduHeaders.TO, recipients, addressMap, false);
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&&&&&& long threadId = 0;
&&&&&&&&&&& if (createThreadId && !recipients.isEmpty()) {
&&&&&&&&&&&&&&& // Given all the recipients associated with this message, find (or create) the
&&&&&&&&&&&&&&& // correct thread.
&&&&&&&&&&&&&&& threadId = Threads.getOrCreateThreadId(mContext, recipients);
&&&&&&&&&&& }
&&&&&&&&&&& values.put(Mms.THREAD_ID, threadId);
&&&&&&& // Save parts first to avoid inconsistent message is loaded
&&&&&&& // while saving the parts.
&&&&&&& long dummyId = System.currentTimeMillis(); // Dummy ID of the msg.
&&&&&&& // Figure out if this PDU is a text-only message
&&&&&&& boolean textOnly =
&&&&&&& // Get body if the PDU is a RetrieveConf or SendReq.
&&&&&&& if (pdu instanceof MultimediaMessagePdu) {
&&&&&&&&&&& body = ((MultimediaMessagePdu) pdu).getBody();
&&&&&&&&&&& // Start saving parts if necessary.
&&&&&&&&&&& if (body != null) {
&&&&&&&&&&&&&&& int partsNum = body.getPartsNum();
&&&&&&&&&&&&&&& if (partsNum & 2) {
&&&&&&&&&&&&&&&&&&& // For a text-only message there will be two parts: 1-the SMIL, 2-the text.
&&&&&&&&&&&&&&&&&&& // Down a few lines below we're checking to make sure we've only got SMIL or
&&&&&&&&&&&&&&&&&&& // text. We also have to check then we don't have more than two parts.
&&&&&&&&&&&&&&&&&&& // Otherwise, a slideshow with two text slides would be marked as textOnly.
&&&&&&&&&&&&&&&&&&& textOnly =
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& for (int i = 0; i & partsN i++) {
&&&&&&&&&&&&&&&&&&& PduPart part = body.getPart(i);
&&&&&&&&&&&&&&&&&&& persistPart(part, dummyId, preOpenedFiles);
&&&&&&&&&&&&&&&&&&& // If we've got anything besides text/plain or SMIL part, then we've got
&&&&&&&&&&&&&&&&&&& // an mms message with some other type of attachment.
&&&&&&&&&&&&&&&&&&& String contentType = getPartContentType(part);
&&&&&&&&&&&&&&&&&&& if (contentType != null && !ContentType.APP_SMIL.equals(contentType)
&&&&&&&&&&&&&&&&&&&&&&&&&&& && !ContentType.TEXT_PLAIN.equals(contentType)) {
&&&&&&&&&&&&&&&&&&&&&&& textOnly =
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& }
&&&&&&&&&&& }
&&&&&&& // Record whether this mms message is a simple plain text or not. This is a hint for the
&&&&&&& // UI.
&&&&&&& values.put(Mms.TEXT_ONLY, textOnly ? 1 : 0);
&&&&&&& Uri res =
&&&&&&& if (existingUri) {
&&&&&&&&&&& res =
&&&&&&&&&&& SqliteWrapper.update(mContext, mContentResolver, res, values, null, null);
&&&&&&& } else {
&&&&&&&&&&& res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
&&&&&&&&&&& if (res == null) {
&&&&&&&&&&&&&&& throw new MmsException(&persist() failed: return null.&);
&&&&&&&&&&& }
&&&&&&&&&&& // Get the real ID of the PDU and update all parts which were
&&&&&&&&&&& // saved with the dummy ID.
&&&&&&&&&&& msgId = ContentUris.parseId(res);
&&&&&&& values = new ContentValues(1);
&&&&&&& values.put(Part.MSG_ID, msgId);
&&&&&&& SqliteWrapper.update(mContext, mContentResolver,
&&&&&&&&&&&&&&&&&&&&&&&&&&&& Uri.parse(&content://mms/& + dummyId + &/part&),
&&&&&&&&&&&&&&&&&&&&&&&&&&&& values, null, null);
&&&&&&& // We should return the longest URI of the persisted PDU, for
&&&&&&& // example, if input URI is &content://mms/inbox& and the _ID of
&&&&&&& // persisted PDU is '8', we should return &content://mms/inbox/8&
&&&&&&& // instead of &content://mms/8&.
&&&&&&& // FIXME: Should the MmsProvider be responsible for this???
&&&&&&& if (!existingUri) {
&&&&&&&&&&& res = Uri.parse(uri + &/& + msgId);
&&&&&&& // Save address information.
&&&&&&& for (int addrType : ADDRESS_FIELDS) {
&&&&&&&&&&& EncodedStringValue[] array = addressMap.get(addrType);
&&&&&&&&&&& if (array != null) {
&&&&&&&&&&&&&&& persistAddress(msgId, addrType, array);
&&&&&&&&&&& }
上述代码《TAG:2-5》中,调用PduPersister.java类中的()方法对彩信进行持久化,该方法中调用SqliteWrapper类的insert方法将数据存入数据库mmssms的part表中:《TAG:2-6》
&public Uri persistPart(PduPart part, long msgId, HashMap&Uri, InputStream& preOpenedFiles)
&&&&&&&&&&& throws MmsException {
&&&&&&& Uri uri = Uri.parse(&content://mms/& + msgId + &/part&);
&&&&&&& ContentValues values = new ContentValues(8);
&&&&&&& int charset = part.getCharset();
&&&&&&& if (charset != 0 ) {
&&&&&&&&&&& values.put(Part.CHARSET, charset);
&&&&&&& String contentType = getPartContentType(part);
&&&&&&& if (contentType != null) {
&&&&&&&&&&& // There is no &image/jpg& in Android (and it's an invalid mimetype).
&&&&&&&&&&& // Change it to &image/jpeg&
&&&&&&&&&&& if (ContentType.IMAGE_JPG.equals(contentType)) {
&&&&&&&&&&&&&&& contentType = ContentType.IMAGE_JPEG;
&&&&&&&&&&& }
&&&&&&&&&&& values.put(Part.CONTENT_TYPE, contentType);
&&&&&&&&&&& // To ensure the SMIL part is always the first part.
&&&&&&&&&&& if (ContentType.APP_SMIL.equals(contentType)) {
&&&&&&&&&&&&&&& values.put(Part.SEQ, -1);
&&&&&&&&&&& }
&&&&&&& } else {
&&&&&&&&&&& throw new MmsException(&MIME type of the part must be set.&);
&&&&&&& if (part.getFilename() != null) {
&&&&&&&&&&& String fileName = new String(part.getFilename());
&&&&&&&&&&& values.put(Part.FILENAME, fileName);
&&&&&&& if (part.getName() != null) {
&&&&&&&&&&& String name = new String(part.getName());
&&&&&&&&&&& values.put(Part.NAME, name);
&&&&&&& String value =
&&&&&&& int encode=-1;
&&&&&&& if (part.getContentDisposition() != null) {
&&&&&&&&&&& value = toIsoString(part.getContentDisposition());
&&&&&&&&&&& values.put(Part.CONTENT_DISPOSITION,value);
&&&&&&& if (part.getContentId() != null) {
&&&&&&&&&&& byte[] byte_cid=part.getContentId();
&&&&&&&&&&& encode=detectEncoding(byte_cid);
&&&&&&&&&&& try{
&&&&&&&&&&&&&&& switch(encode){
&& &&& &&& &case GB2312:
&&&&&&&&&&&&&&&&&&&&&&&&&&&& value=new String(byte_cid,&GB2312&);
&& &&& &&& &
&& &&& &&& &case ASCII:
&&&&&&&&&&&&&&&&&&&&&&&&&&& &
&&&&&&&&&&&&&&&&&&&&&&&&&&&& value=new String(byte_cid,&ASCII&);
&&&&&&&&&&&&&&&&&&&&
&& &&& &&& &case UTF8:
&& &&& &&& &&& &value=new String(byte_cid,&UTF-8&);
&& &&& &&& &
&& &&& &&& &case UNICODE:
&& &&& &&& &&& &value=new String(byte_cid,&Unicode&);
&& &&& &&& &
&& &&& &&& &default:
&&&&&&&&&&&&&&&&&&&&&&&&&&& value = toIsoString(byte_cid);
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&& }
&& &&&&& Log.d(&bill&,&getContentId---&+value);
&&&&&&&&&&& values.put(Part.CONTENT_ID, value);}catch(Exception e){}
&&&&&&& if (part.getContentLocation() != null) {
&&&&&&&&&&& byte[] byte_cl=part.getContentLocation();
&&&&&&&&&&& encode=detectEncoding(byte_cl);
&&&&&&&&&&& try{
&&&&&&&&&&&&&&& switch(encode){
&& &&& &&& &case GB2312:
&&&&&&&&&&&&&&&&&&&&&&&&&&&& value=new String(byte_cl,&GB2312&);
&& &&& &&& &
&& &&& &&& &case ASCII:
&&&&&&&&&&&&&&&&&&&&&&&&&&&& value=new String(byte_cl,&ASCII&);
&&&&&&&&&&&&&&&&&&&&
&& &&& &&& &case UTF8:
&& &&& &&& &&& &value=new String(byte_cl,&UTF-8&);
&& &&& &&& &
&& &&& &&& &case UNICODE:
&& &&& &&& &&& &value=new String(byte_cl,&Unicode&);
&& &&& &&& &
&& &&& &&& &default:
&&&&&&&&&&&&&&&&&&&&&&&&&&& value = toIsoString(byte_cl);
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&& }
&&&&&&&&&&& Log.d(&bill&,&getContentLocation---&+value);
&&&&&&&&&&& values.put(Part.CONTENT_LOCATION,value);}catch(Exception e){}
&&&&&&& Uri res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
&&&&&&& if (res == null) {
&&&&&&&&&&& throw new MmsException(&Failed to persist part, return null.&);
&&&&&&& persistData(part, res, contentType, preOpenedFiles);
&&&&&&& // After successfully store the data, we should update
&&&&&&& // the dataUri of the part.
&&&&&&& part.setDataUri(res);
我们接着分析,持久会存储之后会调用&TAG 2-1&中的PushReceiver.java类中的doInBackground()方法来启动TransactionService服务;
版权声明:本文为博主原创文章,未经博主允许不得转载。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:261589次
积分:4358
积分:4358
排名:第3383名
原创:135篇
转载:77篇
译文:13篇
评论:48条
(1)(9)(1)(3)(2)(13)(11)(9)(6)(8)(8)(6)(5)(14)(28)(89)(6)(1)(2)(2)(1)

我要回帖

更多关于 imessage已送达和已读 的文章

 

随机推荐