Android9.0 Mms (彩信接收步骤,Android9.0版本)
发布日期:2021-06-30 21:23:35 浏览次数:2 分类:技术文章

本文共 43636 字,大约阅读时间需要 145 分钟。

1.彩信接收步骤

我们首先看4个类分别是PDU重要的几个类

PduPersister       用于管理PDU存储
PduParser           用于解析PDU
PduComposer    用于生成PDU

关键的方法:

PduPersister    类
PduPersister  getPduPersister(Context)    Get the object
Uri   persist(GenericPdu, Uri)   把一个GenericPdu保存到Uri所指定的数据库中,返回指向新生成数据的Uri  ,获取的数据也                                                         可以保存到数据库中
GenericPdu  load(Uri)  从数据库把Uri所指的数据加载出来成一个GenericPdu对象
Uri   move(Uri, Uri)   把Pdu从一个地方移到另一个地方,比如从草稿箱移动到发件箱,当MMS已发送时。
   
为什么会要把PDU的存储也封装成PduPersister呢?因为PDU的存储方式 是放在标准的SQLiteDatabase中,通过TelephonyProvider,而SQLiteDatabase中存储不能以直接的PDU的字节流来存储,必须要把PDU拆解成为可读的字段,因此在存储PDU和从存储加载PDU的过程 中涉及到PDU数据上面的处理,因此封装出来,更方便使用。

 

PduParser:用于把PDU字节流解析成为Android可识别的GenericPdu

PduParser    PduParser(byte[])    Construct an object
GenericPdu    parse()    Parse the PDU byte stream into Android PDU GenericPdu

 

PduComposer:把GenericPdu打包生成PDU字节流

Return    Method    Description

PduComposer    PduComposer(Context, GenericPdu)    Construct an object
byte[]    make()    Transfer the GenericPdu into a PDU byte stream

 

 

 

 

开始看代码

首先收到彩信是底层发送一个广播告诉上层的Mms,

PushReceiver.java   这个是一个广播

@Override    public void onReceive(Context context, Intent intent) {        if (!MessageUtils.hasBasicPermissions()){            Log.d(TAG, "PushReceiver do not have basic permissions");            return;        }        mContext=context;        if (intent.getAction().equals(WAP_PUSH_DELIVER_ACTION)                && (ContentType.MMS_MESSAGE.equals(intent.getType())                || WAP_PUSH_TYPE_SIC.equals(intent.getType())                || WAP_PUSH_TYPE_SLC.equals(intent.getType())))  {            if (LOCAL_LOGV) {                Log.v(TAG, "Received PUSH Intent: " + intent);            }            // Hold a wake lock for 5 seconds, enough to give any            // services we start time to take their own wake locks.            PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,                                            "MMS PushReceiver");            wl.acquire(5000);            new ReceivePushTask(context).execute(intent); //开启异步进行下载        }    }

 

主要看收到彩信的一个Intent

收到彩信时 IntentIntent {     act=android.provider.Telephony.WAP_PUSH_DELIVER     typ=application/vnd.wap.mms-message     flg=0x18000010     cmp=com.android.mms/.transaction.PushReceiver     (has extras) }

 

开启异步

private class ReceivePushTask extends AsyncTask
{ private Context mContext; public ReceivePushTask(Context context) { mContext = context; } int hexCharToInt(char c) { if (c >= '0' && c <= '9') return (c - '0'); if (c >= 'A' && c <= 'F') return (c - 'A' + 10); if (c >= 'a' && c <= 'f') return (c - 'a' + 10); } public String bytesToHexString(byte[] bytes) { if (bytes == null) return null; StringBuilder ret = new StringBuilder(2*bytes.length); for (int i = 0 ; i < bytes.length ; i++) { int b; b = 0x0f & (bytes[i] >> 4); ret.append("0123456789abcdef".charAt(b)); b = 0x0f & bytes[i]; ret.append("0123456789abcdef".charAt(b)); } return ret.toString(); } @Override protected Void doInBackground(Intent... intents) { Intent intent = intents[0]; // Get raw PDU push-data from the message and parse it byte[] pushData = intent.getByteArrayExtra("data"); if (DEBUG) { Log.d(TAG, "PushReceive: pushData= " + bytesToHexString(pushData)); } SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); boolean wapPushEnabled = prefs.getBoolean(WAP_PUSH_MESSAGE, true); if (wapPushEnabled && (WAP_PUSH_TYPE_SIC.equals(intent.getType()) || WAP_PUSH_TYPE_SLC.equals(intent.getType()))) { ByteArrayInputStream bais = new ByteArrayInputStream(pushData); try { Class mWapPushHandler = Class.forName("com.qrd.wappush.WapPushHandler"); Object WapPushHandlerObj = mWapPushHandler.newInstance(); Method mHandleWapPush = mWapPushHandler.getDeclaredMethod("handleWapPush", InputStream.class, String.class, Context.class, int.class, String.class); Method mGetThreadID = mWapPushHandler.getDeclaredMethod("getThreadID"); String address = intent.getStringExtra("address"); if (address == null) { address = WAP_PUSH_DEFAULT_ADDRESS; } Uri pushMsgUri = (Uri)mHandleWapPush.invoke(WapPushHandlerObj, bais, intent.getType(), mContext, intent.getIntExtra(ConstantsWrapper.Phone.PHONE_KEY, 0), address + WAP_PUSH); if (pushMsgUri != null) { // Called off of the UI thread so ok to block. Recycler.getSmsRecycler().deleteOldMessagesByThreadId( mContext.getApplicationContext(), (Long)mGetThreadID.invoke(WapPushHandlerObj)); MessagingNotification.blockingUpdateNewMessageIndicator( mContext, (Long)mGetThreadID.invoke(WapPushHandlerObj), false); MmsWidgetProvider.notifyDatasetChanged(mContext); } } catch (Exception e) { Log.e(TAG, "Wap Push Hander Error :" + e); } return null; } PduParser parser = new PduParser(pushData, PduParserUtil.shouldParseContentDisposition()); GenericPdu pdu = parser.parse(); if (null == pdu) { Log.e(TAG, "Invalid PUSH data"); return null; } PduPersister p = PduPersister.getPduPersister(mContext); ContentResolver cr = mContext.getContentResolver(); int type = pdu.getMessageType(); long threadId = -1; try { switch (type) { case MESSAGE_TYPE_DELIVERY_IND://143表示消息已送达,送达报告 case MESSAGE_TYPE_READ_ORIG_IND: { threadId = findThreadId(mContext, pdu, type); if (threadId == -1) { // The associated SendReq isn't found, therefore skip // processing this PDU. break; } Message me = new Message(); me.arg1=type; mHandler.sendMessage(me);//送达报告发送 Uri uri = p.persist(pdu, Inbox.CONTENT_URI, true, MessagingPreferenceActivity.getIsGroupMmsEnabled(mContext), null); // Update thread ID for ReadOrigInd & DeliveryInd. ContentValues values = new ContentValues(1); values.put(Mms.THREAD_ID, threadId); SqliteWrapper.update(mContext, cr, uri, values, null, null); break; } case MESSAGE_TYPE_NOTIFICATION_IND: {//收到消息调用 NotificationInd nInd = (NotificationInd) pdu; 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(ConstantsWrapper.Phone.SUBSCRIPTION_KEY, 0); //Phone ID will be updated in data base Log.d(TAG, "PushReceiver subId : " + subId); ContentValues values = new ContentValues(1); values.put(Mms.SUBSCRIPTION_ID, subId); Uri uri = p.persist(pdu, Inbox.CONTENT_URI, true, MessagingPreferenceActivity.getIsGroupMmsEnabled(mContext), null); SqliteWrapper.update(mContext, cr, uri, values, null, null); String address = pdu.getFrom().getString(); threadId = MessagingNotification.getThreadId(mContext, uri); MessageUtils .markAsNotificationThreadIfNeed(mContext, threadId, address); if (!DownloadManager.getInstance().isAuto() && !MessageUtils.isMobileDataEnabled(mContext, subId)) { MessagingNotification.blockingUpdateNewMessageIndicator(mContext, threadId, false); break; } Intent svc = new Intent(mContext, TransactionService.class); svc.putExtra(TransactionBundle.URI, uri.toString()); svc.putExtra(TransactionBundle.TRANSACTION_TYPE, Transaction.NOTIFICATION_TRANSACTION); svc.putExtra(Mms.SUBSCRIPTION_ID, subId); mContext.startService(svc); } else if (LOCAL_LOGV) { Log.v(TAG, "Skip downloading duplicate message: " + new String(nInd.getContentLocation())); } break; } default: Log.e(TAG, "Received unrecognized PDU."); } } catch (MmsException e) { Log.e(TAG, "Failed to save the data from PUSH: type=" + type, e); } catch (RuntimeException e) { Log.e(TAG, "Unexpected RuntimeException.", e); } if (LOCAL_LOGV) { Log.v(TAG, "PUSH Intent processed."); } return null; } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); } }

 

 

主要看

Uri uri = p.persist(pdu, Inbox.CONTENT_URI,        true,        MessagingPreferenceActivity.getIsGroupMmsEnabled(mContext),        null);

p是一个PduPersister  

p.persist();, 这里的操作是进行插入数据PDU表的数据  pdu里面自带一些协议

PduPersister.java

public Uri persist(GenericPdu pdu, Uri uri, boolean createThreadId, boolean groupMmsEnabled,            HashMap
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 (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 = null; ContentValues values = new ContentValues(); Set
> set; set = ENCODED_STRING_COLUMN_NAME_MAP.entrySet(); for (Entry
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
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
e : set){ int b = header.getOctet(e.getKey()); if (b != 0) { values.put(e.getValue(), b); } } set = LONG_COLUMN_NAME_MAP.entrySet(); for (Entry
e : set){ long l = header.getLongInteger(e.getKey()); if (l != -1L) { values.put(e.getValue(), l); } } HashMap
addressMap = new HashMap
(ADDRESS_FIELDS.length); // Save address information. for (int addrType : ADDRESS_FIELDS) { EncodedStringValue[] array = null; if (addrType == PduHeaders.FROM) { EncodedStringValue v = header.getEncodedStringValue(addrType); if (v != null) { array = new EncodedStringValue[1]; array[0] = v; } } else { array = header.getEncodedStringValues(addrType); } addressMap.put(addrType, array); } HashSet
recipients = new HashSet
(); int msgType = pdu.getMessageType(); 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); if (groupMmsEnabled) { loadRecipients(PduHeaders.TO, recipients, addressMap, true); loadRecipients(PduHeaders.CC, recipients, addressMap, true); } break; case PduHeaders.MESSAGE_TYPE_SEND_REQ: loadRecipients(PduHeaders.TO, recipients, addressMap, false); break; } long threadId = 0; if (createThreadId && !recipients.isEmpty()) { threadId = Threads.getOrCreateThreadId(mContext, recipients); } values.put(Mms.THREAD_ID, threadId); } long dummyId = System.currentTimeMillis(); // Dummy ID of the msg. boolean textOnly = true; int messageSize = 0; if (pdu instanceof MultimediaMessagePdu) { body = ((MultimediaMessagePdu) pdu).getBody(); // Start saving parts if necessary. if (body != null) { int partsNum = body.getPartsNum(); if (partsNum > 2) { textOnly = false; } for (int i = 0; i < partsNum; i++) { PduPart part = body.getPart(i); messageSize += part.getDataLength(); persistPart(part, dummyId, preOpenedFiles); String contentType = getPartContentType(part); if (contentType != null && !ContentType.APP_SMIL.equals(contentType) && !ContentType.TEXT_PLAIN.equals(contentType)) { textOnly = false; } } } } values.put(Mms.TEXT_ONLY, textOnly ? 1 : 0); if (values.getAsInteger(Mms.MESSAGE_SIZE) == null) { values.put(Mms.MESSAGE_SIZE, messageSize); } Uri res = null; if (existingUri) { res = uri; SqliteWrapper.update(mContext, mContentResolver, res, values, null, null); } else { //Uri对应如果是Pdu表就是插入pdu如果是part表就更新part表 res = SqliteWrapper.insert(mContext, mContentResolver, uri, values); //解析Byte数字后进行插入到PDU表或part表 if (res == null) { throw new MmsException("persist() failed: return null."); } 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); 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); } } return res; }

 

mmssms.db中PDU表经过 persister.persist方法PDU是插入了数据的


在这一步进行只是告诉APP有一条彩信等待这去下载


 

 

下载步骤是开启TransactionService.java

PushReceiver.java 

// 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.SUBSCRIPTION_ID, subId);  mContext.startService(svc);

 

TransactionService.java

这里主要看handler

@Override        public void handleMessage(Message msg) {            LogTag.debugD("Handling incoming message: " + msg + " = " + decodeMessage(msg));            Transaction transaction = null;            switch (msg.what) {                case EVENT_NEW_INTENT:                    onNewIntent((Intent)msg.obj, msg.arg1);                    break;                case EVENT_QUIT:                    getLooper().quit();                    return;                case EVENT_TRANSACTION_REQUEST:   //通知彩信接收                    int serviceId = msg.arg1;                    try {                        TransactionBundle args = (TransactionBundle) msg.obj;                        TransactionSettings transactionSettings;                        LogTag.debugD("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,                                                    args.getSubId());                        }                        int transactionType = args.getTransactionType();                        // Create appropriate transaction                        switch (transactionType) {                            case Transaction.NOTIFICATION_TRANSACTION:                                String uri = args.getUri();                                //用户通知                                if (uri!=null){                                long threadId = MessagingNotification.getThreadId(                                        getApplicationContext(), Uri.parse(uri));                                MessagingNotification.blockingUpdateNewMessageIndicator(getApplicationContext(),                                        threadId,                                        false);                                MessagingNotification.updateDownloadFailedNotification(getApplicationContext());                                MessageUtils.updateThreadAttachTypeByThreadId(getApplicationContext(), threadId);                                                            new AsyncHandler(getContentResolver(),threadId).startQuery(0,                                        null,mAllCanonical,mProjection,"_id="+threadId,null,null);                                    if (!SharePreferencesUtils.getBoolean(getApplicationContext(),SMART_CAT_AGREEMENT)) {                                        SharePreferencesUtils.putBoolean(getApplicationContext(),SMART_CAT_AGREEMENT,true);                                    }                                }                                if (uri != null) {                                    //开始解压消息   自动解压彩信                                    transaction = new NotificationTransaction(                                            TransactionService.this, serviceId,                                            transactionSettings, uri                                            );                                }  else {                                    byte[] pushData = args.getPushData();                                    PduParser parser = new PduParser(pushData,                                            PduParserUtil.shouldParseContentDisposition());                                    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 = null;                                        return;                                    }                                }                                break;                            case Transaction.RETRIEVE_TRANSACTION:                                //手动下载短信                                transaction = new RetrieveTransaction(                                        TransactionService.this, serviceId,                                        transactionSettings, args.getUri());                                break;                            case Transaction.SEND_TRANSACTION:                                transaction = new SendTransaction(                                        TransactionService.this, serviceId,                                        transactionSettings, args.getUri());                                break;                            case Transaction.READREC_TRANSACTION:                                transaction = new ReadRecTransaction(                                        TransactionService.this, serviceId,                                        transactionSettings, args.getUri());                                break;                            default:                                Log.w(TAG, "Invalid transaction type: " + serviceId);                                transaction = null;                                return;                        }                        //copy the subId from TransactionBundle to transaction obj.                        transaction.setSubId(args.getSubId());                        //启动线程,进行下载,或发送操作                        if (!processTransaction(transaction)) {                            transaction = null;                            return;                        }                        LogTag.debugD("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 = null;                            }                        }                    } finally {                        if (transaction == null) {                            LogTag.debugD("Transaction was null. Stopping self: " + serviceId);                            endMmsConnectivity();                            stopSelfIfIdle(serviceId);                        }                    }                    return;                case EVENT_HANDLE_NEXT_PENDING_TRANSACTION:                    processPendingTransaction(transaction, (TransactionSettings) msg.obj);                    return;                case EVENT_MMS_CONNECTIVITY_TIMEOUT:                    removeMessages(EVENT_MMS_CONNECTIVITY_TIMEOUT);                    mMmsConnecvivityRetryCount++;                    if (mMmsConnecvivityRetryCount > MMS_CONNECTIVITY_RETRY_TIMES) {                        Log.d(TAG, "MMS_CONNECTIVITY_TIMEOUT");                        mMmsConnecvivityRetryCount = 0;                        return;                    }                    if (!mPending.isEmpty()) {                        try {                            beginMmsConnectivity(SubscriptionManager.getDefaultDataSubscriptionId());                        } catch (IOException e) {                            Log.w(TAG, "Attempt to use of MMS connectivity failed");                            return;                        }                    }                    return;                case EVENT_MMS_PDP_ACTIVATION_TIMEOUT:                    onPDPTimeout((int)msg.obj);                    return;                default:                                      return;            }        }

 

 

看这个方法  

processTransaction(transaction)
private boolean processTransaction(Transaction transaction) throws IOException {            // Check if transaction already processing            synchronized (mProcessing) {                for (Transaction t : mPending) {                    if (t.isEquivalent(transaction)) {                        LogTag.debugD("Transaction already pending: " +                                transaction.getServiceId());                        return true;                    }                }                for (Transaction t : mProcessing) {                    if (t.isEquivalent(transaction)) {                        LogTag.debugD("Duplicated transaction: " + transaction.getServiceId());                        return true;                    }                }                int subId = transaction.getSubId();                int phoneId = SubscriptionManagerWrapper.getPhoneId(subId);                boolean isRequestNetworkQueued = true;                LogTag.debugD("processTransaction :subId="+subId                    + "; phoneId = " + phoneId                    + "; mPhoneCount = "+ mPhoneCount);                for (int id =0; id < mPhoneCount; id++) {                    if ((id != phoneId) && (mMmsNetworkRequest[id] != null)) {                        isRequestNetworkQueued = false;                        break;                    }                }                LogTag.debugD("processTransaction :isRequestNetworkQueued="+isRequestNetworkQueued);                if ((mProcessing.size() > 0) || !isRequestNetworkQueued) {                    LogTag.debugD("Adding transaction to 'mPending' list: " + transaction);                    mPending.add(transaction);                    return true;                } else {                    beginMmsConnectivity(subId);                if (!mIsAvailable[phoneId]) {                    mPending.add(transaction);                    LogTag.debugD("processTransaction: connResult=APN_REQUEST_STARTED, " +                            "defer transaction pending MMS connectivity");                    if (transaction instanceof SendTransaction) {                        LogTag.debugD("remove cache while deferring");                        MmsApp.getApplication().getPduLoaderManager().removePdu(                                ((SendTransaction) transaction).mSendReqURI);                    }                        return true;                    }                    LogTag.debugD("Adding transaction to 'mProcessing' list: " + transaction);                    mProcessing.add(transaction);                }            }            LogTag.debugD("processTransaction: starting transaction " + transaction);            transaction.attach(TransactionService.this);            transaction.process();            return true;        }    }

 

 

在最后启动了  transaction.process();

 

开启了RetrieveTransaction.java

RetrieveTransaction是一个线程类

package com.android.mms.transaction;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SqliteWrapper;import android.net.Uri;import android.provider.Telephony.Mms;import android.provider.Telephony.Mms.Inbox;import android.text.TextUtils;import android.util.Log;import com.android.mms.LogTag;import com.android.mms.MmsConfig;import com.android.mms.R;import com.android.mms.ui.MessageUtils;import com.android.mms.ui.MessagingPreferenceActivity;import com.android.mms.util.DownloadManager;import com.android.mms.util.Recycler;import com.android.mms.widget.MmsWidgetProvider;import com.google.android.mms.MmsException;import com.google.android.mms.pdu.AcknowledgeInd;import com.google.android.mms.pdu.EncodedStringValue;import com.google.android.mms.pdu.PduComposer;import com.google.android.mms.pdu.PduHeaders;import com.google.android.mms.pdu.PduParser;import com.google.android.mms.pdu.PduPersister;import com.google.android.mms.pdu.RetrieveConf;import java.io.IOException;public class RetrieveTransaction extends Transaction implements Runnable {    private static final String TAG = LogTag.TAG;    private static final boolean DEBUG = false;    private static final boolean LOCAL_LOGV = false;    private final Uri mUri;    private final String mContentLocation;    private boolean mLocked;    private boolean isCancelMyself;    static final String[] PROJECTION = new String[] {        Mms.CONTENT_LOCATION,        Mms.LOCKED    };    // The indexes of the columns which must be consistent with above PROJECTION.    static final int COLUMN_CONTENT_LOCATION      = 0;    static final int COLUMN_LOCKED                = 1;    public RetrieveTransaction(Context context, int serviceId,            TransactionSettings connectionSettings, String uri)            throws MmsException {        super(context, serviceId, connectionSettings);        if (uri.startsWith("content://")) {            mUri = Uri.parse(uri); // The Uri of the M-Notification.ind            mId = mContentLocation = getContentLocation(context, mUri);            if (LOCAL_LOGV) {                Log.v(TAG, "X-Mms-Content-Location: " + mContentLocation);            }        } else {            throw new IllegalArgumentException(                    "Initializing from X-Mms-Content-Location is abandoned!");        }        // Attach the transaction to the instance of RetryScheduler.        attach(RetryScheduler.getInstance(context));    }    private String getContentLocation(Context context, Uri uri)            throws MmsException {        Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),                            uri, PROJECTION, null, null, null);        mLocked = false;        if (cursor != null) {            try {                if ((cursor.getCount() == 1) && cursor.moveToFirst()) {                    // Get the locked flag from the M-Notification.ind so it can be transferred                    // to the real message after the download.                    mLocked = cursor.getInt(COLUMN_LOCKED) == 1;                    return cursor.getString(COLUMN_CONTENT_LOCATION);                }            } finally {                cursor.close();            }        }        throw new MmsException("Cannot get X-Mms-Content-Location from: " + uri);    }    /*     * (non-Javadoc)     * @see com.android.mms.transaction.Transaction#process()     */    @Override    public void process() {        new Thread(this, "RetrieveTransaction").start();    }    public void run() {        try {            DownloadManager downloadManager = DownloadManager.getInstance();            //Obtain Message Size from M-Notification.ind for original MMS            int msgSize = downloadManager.getMessageSize(mUri);            // Change the downloading state of the M-Notification.ind.            downloadManager.markState(mUri, DownloadManager.STATE_DOWNLOADING);            if (isCancelMyself) {                DownloadManager.getInstance().markState(mUri,                        DownloadManager.STATE_TRANSIENT_FAILURE);                return;            }            // Send GET request to MMSC and retrieve the response data.   下载彩信            byte[] resp= getPdu(mContentLocation,mUri);            if (isCancelMyself) {                DownloadManager.getInstance().markState(mUri,                        DownloadManager.STATE_TRANSIENT_FAILURE);                return;            }            // Parse M-Retrieve.conf  从网上获取到的byte数字  给PduParser进行解析            RetrieveConf retrieveConf = (RetrieveConf) new PduParser(resp,PduParserUtil.shouldParseContentDisposition()).parse();            if (null == retrieveConf) {                throw new MmsException("Invalid M-Retrieve.conf PDU.");            }            Uri msgUri = null;            if (isDuplicateMessage(mContext, retrieveConf, mContentLocation)) {                // Mark this transaction as failed to prevent duplicate                // notification to user.                if (Log.isLoggable(LogTag.TRANSACTION, Log.DEBUG)) {                    Log.v(TAG, "RetrieveTransaction DuplicateMessage !!");                }                mTransactionState.setState(TransactionState.FAILED);                mTransactionState.setContentUri(mUri);            } else {                // Store M-Retrieve.conf into Inbox//将数据给PduPersister进行解析   插入到Part表中  在retrieveConf中的byte数组包括全部东西,有彩信,文本。。。                PduPersister persister = PduPersister.getPduPersister(mContext);                msgUri = persister.persist(retrieveConf, Inbox.CONTENT_URI, true,                        MessagingPreferenceActivity.getIsGroupMmsEnabled(mContext), null);                // Use local time instead of PDU time                ContentValues values = new ContentValues(3);                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.SUBSCRIPTION_ID));                            Log.d(TAG, "RetrieveTransaction: subId value is " + subId);                            values.put(Mms.SUBSCRIPTION_ID, subId);                        }                    } finally {                        c.close();                    }                }                // Update Message Size for Original MMS.                values.put(Mms.MESSAGE_SIZE, msgSize);                SqliteWrapper.update(mContext, mContext.getContentResolver(),                        msgUri, values, null, null);                // The M-Retrieve.conf has been successfully downloaded.                mTransactionState.setState(TransactionState.SUCCESS);                mTransactionState.setContentUri(msgUri);                // Remember the location the message was downloaded from.                // Since it's not critical, it won't fail the transaction.                // Copy over the locked flag from the M-Notification.ind in case                // the user locked the message before activating the download.                updateContentLocation(mContext, msgUri, mContentLocation, mLocked);            }            // Delete the corresponding M-Notification.ind.            SqliteWrapper.delete(mContext, mContext.getContentResolver(),                                 mUri, null, null);            if (msgUri != null) {                // Have to delete messages over limit *after* the delete above. Otherwise,                // it would be counted as part of the total.                Recycler.getMmsRecycler().deleteOldMessagesInSameThreadAsMessage(mContext, msgUri);                MmsWidgetProvider.notifyDatasetChanged(mContext);            }            // Send ACK to the Proxy-Relay to indicate we have fetched the            // MM successfully.            // Don't mark the transaction as failed if we failed to send it.            sendAcknowledgeInd(retrieveConf);        } catch (Throwable t) {            Log.e(TAG, Log.getStackTraceString(t));        } finally {            if (mTransactionState.getState() != TransactionState.SUCCESS) {                if (isCancelMyself) {                    mTransactionState.setState(TransactionState.CANCELED);                } else {                    mTransactionState.setState(TransactionState.FAILED);                }                mTransactionState.setContentUri(mUri);                Log.e(TAG, "Retrieval failed.");            }            notifyObservers();        }    }    private static boolean isDuplicateMessage(Context context, RetrieveConf rc, String location) {        byte[] rawMessageId = rc.getMessageId();        if (rawMessageId != null) {            String messageId = new String(rawMessageId);            String selection = "(" + Mms.MESSAGE_ID + " = ? AND "                                   + Mms.CONTENT_LOCATION + " = ? AND "                                   + Mms.MESSAGE_TYPE + " = ?)";            String[] selectionArgs = new String[] { messageId, location,                    String.valueOf(PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF) };            Cursor cursor = SqliteWrapper.query(                    context, context.getContentResolver(),                    Mms.CONTENT_URI, new String[] { Mms._ID, Mms.SUBJECT, Mms.SUBJECT_CHARSET },                    selection, selectionArgs, null);            if (cursor != null) {                try {                    if (cursor.getCount() > 0) {                        // A message with identical message ID and type found.                        // Do some additional checks to be sure it's a duplicate.                        return isDuplicateMessageExtra(cursor, rc);                    }                } finally {                    cursor.close();                }            }        }        return false;    }    private static boolean isDuplicateMessageExtra(Cursor cursor, RetrieveConf rc) {        // Compare message subjects, taking encoding into account        EncodedStringValue encodedSubjectReceived = null;        EncodedStringValue encodedSubjectStored = null;        String subjectReceived = null;        String subjectStored = null;        String subject = null;        encodedSubjectReceived = rc.getSubject();        if (encodedSubjectReceived != null) {            subjectReceived = encodedSubjectReceived.getString();        }        for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {            int subjectIdx = cursor.getColumnIndex(Mms.SUBJECT);            int charsetIdx = cursor.getColumnIndex(Mms.SUBJECT_CHARSET);            subject = cursor.getString(subjectIdx);            int charset = cursor.getInt(charsetIdx);            if (subject != null) {                encodedSubjectStored = new EncodedStringValue(charset, PduPersister                        .getBytes(subject));            }            if (encodedSubjectStored == null && encodedSubjectReceived == null) {                // Both encoded subjects are null - return true                return true;            } else if (encodedSubjectStored != null && encodedSubjectReceived != null) {                subjectStored = encodedSubjectStored.getString();                if (!TextUtils.isEmpty(subjectStored) && !TextUtils.isEmpty(subjectReceived)) {                    // Both decoded subjects are non-empty - compare them                    return subjectStored.equals(subjectReceived);                } else if (TextUtils.isEmpty(subjectStored) && TextUtils.isEmpty(subjectReceived)) {                    // Both decoded subjects are "" - return true                    return true;                }            }        }        return false;    }    private void sendAcknowledgeInd(RetrieveConf rc) throws MmsException, IOException {        // Send M-Acknowledge.ind to MMSC if required.        // If the Transaction-ID isn't set in the M-Retrieve.conf, it means        // the MMS proxy-relay doesn't require an ACK.        byte[] tranId = rc.getTransactionId();        if (tranId != null) {            // Create M-Acknowledge.ind            AcknowledgeInd acknowledgeInd = new AcknowledgeInd(                    PduHeaders.CURRENT_MMS_VERSION, tranId);            // insert the 'from' address per spec            String lineNumber = MessageUtils.getLocalNumber();            acknowledgeInd.setFrom(new EncodedStringValue(lineNumber));            if (false){                // Pack M-Acknowledge.ind and send it                if(MmsConfig.getNotifyWapMMSC()) {                    sendPdu(new PduComposer(mContext, acknowledgeInd).make(), mContentLocation);                } else {                    sendPdu(new PduComposer(mContext, acknowledgeInd).make());                }            }        }    }    private static void updateContentLocation(Context context, Uri uri,                                              String contentLocation,                                              boolean locked) {        ContentValues values = new ContentValues(2);        values.put(Mms.CONTENT_LOCATION, contentLocation);        values.put(Mms.LOCKED, locked);     // preserve the state of the M-Notification.ind lock.        SqliteWrapper.update(context, context.getContentResolver(),                             uri, values, null, null);    }    @Override    public void abort() {        Log.d(TAG, "markFailed = " + this);        mTransactionState.setState(TransactionState.FAILED);        mTransactionState.setContentUri(mUri);        mFailReason = FAIL_REASON_CAN_NOT_SETUP_DATA_CALL;        notifyObservers();    }    @Override    public int getType() {        return RETRIEVE_TRANSACTION;    }    @Override    public void cancelTransaction(Uri uri) {        if (mUri.equals(uri)) {            isCancelMyself = true;        }    }}

通过Http进行下载获取到Byte数字

// Send GET request to MMSC and retrieve the response data.   下载彩信byte[] resp= getPdu(mContentLocation,mUri);

getPdu 里面的操作是网络操作,主要是到MMSC服务器中下载数据下载后返回的是一个Byte数组

 

// Parse M-Retrieve.conf  从网上获取到的byte数字  给PduParser进行解析RetrieveConf retrieveConf = (RetrieveConf) new PduParser(resp,PduParserUtil.shouldParseContentDisposition()).parse();
// Store M-Retrieve.conf into Inbox//将数据给PduPersister进行解析   插入到Part表中  在retrieveConf中的byte数组包括全部东西,有彩信,文本。。。PduPersister persister = PduPersister.getPduPersister(mContext);msgUri = persister.persist(retrieveConf, Inbox.CONTENT_URI, true,        MessagingPreferenceActivity.getIsGroupMmsEnabled(mContext), null);

 

这一步part表就有数据了彩信下载成功了

转载地址:https://liwangjiang.blog.csdn.net/article/details/93047580 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android Framework目录解析
下一篇:Android源代码结构

发表评论

最新留言

很好
[***.229.124.182]2024年04月16日 02时36分26秒