Android短信开发 发送彩信 ' 高通源码 ' (彩信发送过程1)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35427437/article/details/88673812

Android彩信发送有下面几个类:


 一个一个类看  :

      1 . ComposeMessageActivity.java   详情页面

      2 . WoringMessage.java                  处理一些发送短信-或-彩信方法

      3.  MmsMessageSender.java           彩信入本地数据库

      4.  TransactionService.java              开启服务进行发送或下载操作实现功能

      5. SendTransaction.java                  主要功能他是一个线程,在线程里面访问他的父类Transaction里面的SendPdu()方法

      6. Transaction.java                           主要功能通过他的子类传递值,去调用HttpUtils里面的网络发送下载方法

      7. HttpUtils.java                                  主要进行网络访问httpConnection.java
 



ComposeMessageActivity.java

主要作用是send()方法  ,建议先看   , 普通短信发送过程     <普通短信发送过程>


WoringMessage.java 

send()方法里面主要看   

new Thread(new Runnable() { }   //这里面调用了
sendMmsWorker()  方法
 public void send(final String recipientsInUI) {
        long origThreadId = mConversation.getThreadId();

        LogTag.debugD("send origThreadId: " + origThreadId);

        removeSubjectIfEmpty(true /* notify */);

        // Get ready to write to disk.
        prepareForSave(true /* notify */);

        // Make sure the mConversation has Recipients
        checkConversationHasRecipients(recipientsInUI);

        // We need the recipient list for both SMS and MMS.
        final Conversation conv = mConversation;
        String msgTxt = mText.toString();
        if (requiresMms() || addressContainsEmailToMms(conv, msgTxt)) {
            // uaProfUrl setting in mms_config.xml must be present to send an MMS.
            // However, SMS service will still work in the absence of a uaProfUrl address.
            if (MmsConfig.getUaProfUrl() == null) {
                String err = "WorkingMessage.send MMS sending failure. mms_config.xml is " +
                        "missing uaProfUrl setting.  uaProfUrl is required for MMS service, " +
                        "but can be absent for SMS.";
                RuntimeException ex = new NullPointerException(err);
                Log.e(TAG, err, ex);
                // now, let's just crash.
                throw ex;
            }

            // Make local copies of the bits we need for sending a message,
            // because we will be doing it off of the main thread, which will
            // immediately continue on to resetting some of this state.
            final Uri mmsUri = mMessageUri;
            final PduPersister persister = PduPersister.getPduPersister(mActivity);

            final SlideshowModel slideshow = mSlideshow;
            final CharSequence subject = mSubject;
            final boolean textOnly = mAttachmentType == TEXT;

            LogTag.debugD("Send mmsUri: " + mmsUri);

            // Do the dirty work of sending the message off of the main UI thread.
            new Thread(new Runnable() {  //发送信息调用
                @Override
                public void run() {
                    final SendReq sendReq = makeSendReq(conv, subject);

                    // Make sure the text in slide 0 is no longer holding onto a reference to
                    // the text in the message text box.
                    slideshow.prepareForSend();
                    sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, textOnly);

                    updateSendStats(conv);
                }
            }, "WorkingMessage.send MMS").start();
        } else {
            // Same rules apply as above.
            // Add user's signature first if this feature is enabled.
            String text = mText.toString();
            LogTag.debugD("mText="+text);
            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mActivity);
            if (sp.getBoolean("pref_key_enable_signature", false)) {
                String signature = (sp.getString("pref_key_edit_signature", "")).trim();
                if (signature.length() > 0) {
                    String sigBlock = "\n" + signature;
                    if (!text.endsWith(sigBlock)) {
                        // Signature should be written behind the text in a
                        // newline while the signature has changed.
                        text += sigBlock;
                    }
                }
            }
            final String msgText = text;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    preSendSmsWorker(conv, msgText, recipientsInUI);

                    updateSendStats(conv);
                }
            }, "WorkingMessage.send SMS").start();
        }

        // update the Recipient cache with the new to address, if it's different
        RecipientIdCache.updateNumbers(conv.getThreadId(), conv.getRecipients());

        // Mark the message as discarded because it is "off the market" after being sent.
        mDiscarded = true;
    }

-------------------------sendMmsWorker方法

  private void sendMmsWorker(Conversation conv, Uri mmsUri, PduPersister persister,
            SlideshowModel slideshow, SendReq sendReq, boolean textOnly) {
        long threadId = 0;
        Cursor cursor = null;
        boolean newMessage = false;
        boolean forwardMessage = conv.getHasMmsForward();
        boolean sameRecipient = false;
        ContactList contactList = conv.getRecipients();
//        int phoneCount = MessageUtils.getPhoneCount();
        if (contactList != null) {
            String[] numbers = contactList.getNumbers();
            String[] forward = conv.getForwardRecipientNumber();
            if (numbers != null && forward != null
                    && (numbers.length == forward.length)) {
                List<String> currentNumberList = Arrays.asList(numbers);
                List<String> forwardNumberList = Arrays.asList(forward);
                Collections.sort(currentNumberList);
                Collections.sort(forwardNumberList);
                if (currentNumberList.equals(forwardNumberList)) {
                    sameRecipient = true;
                }
            }
        }
        try {
            // Put a placeholder message in the database first
            DraftCache.getInstance().setSavingDraft(true);
            mStatusListener.onPreMessageSent();

            // Make sure we are still using the correct thread ID for our
            // recipient set.
            threadId = conv.ensureThreadId();
            if (forwardMessage && sameRecipient) {
                MessageUtils.sSameRecipientList.add(threadId);
            }

            if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
                LogTag.debug("sendMmsWorker: update draft MMS message " + mmsUri +
                        " threadId: " + threadId);
            }

            // One last check to verify the address of the recipient.
            String[] dests = conv.getRecipients().getNumbers(true /* scrub for MMS address */);
            if (dests.length == 1) {
                // verify the single address matches what's in the database. If we get a different
                // address back, jam the new value back into the SendReq.
                String newAddress =
                    Conversation.verifySingleRecipient(mActivity, conv.getThreadId(), dests[0]);

                if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
                    LogTag.debug("sendMmsWorker: newAddress " + newAddress +
                            " dests[0]: " + dests[0]);
                }

                if (!newAddress.equals(dests[0])) {
                    dests[0] = newAddress;
                    EncodedStringValue[] encodedNumbers = EncodedStringValue.encodeStrings(dests);
                    if (encodedNumbers != null) {
                        if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
                            LogTag.debug("sendMmsWorker: REPLACING number!!!");
                        }
                        sendReq.setTo(encodedNumbers);
                    }
                }
                MessageUtils.markAsNotificationThreadIfNeed(mActivity, threadId, newAddress);
            }
            newMessage = mmsUri == null;
            if (newMessage) {
                // Write something in the database so the new message will appear as sending
                ContentValues values = new ContentValues();
                values.put(Mms.MESSAGE_BOX, Mms.MESSAGE_BOX_OUTBOX);
                values.put(Mms.THREAD_ID, threadId);
                values.put(Mms.MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ);
                if (textOnly) {
                    values.put(Mms.TEXT_ONLY, 1);
                }
                if (MessageUtils.isMsimIccCardActive()) {
                    values.put(Mms.SUBSCRIPTION_ID, mCurrentConvSubId);
                    Log.i(LogTag.ljsTest, "多卡··发送彩信 = " + mCurrentConvSubId);

                } else {
                    values.put(Mms.SUBSCRIPTION_ID,
                            SubscriptionManager.getDefaultDataSubscriptionId());
                    Log.i(LogTag.ljsTest, "单卡··发送彩信 = " + mCurrentConvSubId);

                }
                mmsUri = SqliteWrapper.insert(mActivity, mContentResolver, Mms.Outbox.CONTENT_URI,
                        values);
            }
            mStatusListener.onMessageSent();

            // If user tries to send the message, it's a signal the inputted text is
            // what they wanted.
            UserHappinessSignals.userAcceptedImeText(mActivity);

            // First make sure we don't have too many outstanding unsent message.
            cursor = SqliteWrapper.query(mActivity, mContentResolver,
                    Mms.Outbox.CONTENT_URI, MMS_OUTBOX_PROJECTION, null, null, null);
            if (cursor != null) {
                long maxMessageSize = MmsConfig.getMaxSizeScaleForPendingMmsAllowed() *
                MmsConfig.getMaxMessageSize();
                long totalPendingSize = 0;
                while (cursor.moveToNext()) {
                    totalPendingSize += cursor.getLong(MMS_MESSAGE_SIZE_INDEX);
                }
                if (totalPendingSize >= maxMessageSize) {
                    unDiscard();    // it wasn't successfully sent. Allow it to be saved as a draft.
                    mStatusListener.onMaxPendingMessagesReached();
                    markMmsMessageWithError(mmsUri);
                    return;
                }
            }
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }

        try {
            if (newMessage) {
                // Create a new MMS message if one hasn't been made yet.
                mmsUri = createDraftMmsMessage(persister, sendReq, slideshow, mmsUri,
                        mActivity, null);
            } else {
                // Otherwise, sync the MMS message in progress to disk.
                updateDraftMmsMessage(mmsUri, persister, slideshow, sendReq, null);
            }

            // Be paranoid and clean any draft SMS up.
            deleteDraftSmsMessage(threadId);
        } finally {
            DraftCache.getInstance().setSavingDraft(false);
        }

        // Resize all the resizeable attachments (e.g. pictures) to fit
        // in the remaining space in the slideshow.
        int error = 0;
        try {
            slideshow.finalResize(mmsUri);
        } catch (ExceedMessageSizeException e1) {
            error = MESSAGE_SIZE_EXCEEDED;
        } catch (MmsException e1) {
            error = UNKNOWN_ERROR;
        }
        if (error != 0) {
            markMmsMessageWithError(mmsUri);
            mStatusListener.onAttachmentError(error);
            return;
        }

        ContentValues values = new ContentValues(1);
        if (MessageUtils.isMsimIccCardActive()) {
            values.put(Mms.SUBSCRIPTION_ID, mCurrentConvSubId);
            Log.i(LogTag.ljsTest, "多卡··发送彩信完 存数据 = " + mCurrentConvSubId);

        } else {
            values.put(Mms.SUBSCRIPTION_ID, SubscriptionManager.getDefaultDataSubscriptionId());
            Log.i(LogTag.ljsTest, "单卡··发送彩信完 存数据 = " + mCurrentConvSubId);
        }
        SqliteWrapper.update(mActivity, mContentResolver, mmsUri, values, null, null);

        MessageSender sender = new MmsMessageSender(mActivity, mmsUri,
                slideshow.getCurrentMessageSize(), mCurrentConvSubId);
        try {
            if (!sender.sendMessage(threadId)) {
                // The message was sent through SMS protocol, we should
                // delete the copy which was previously saved in MMS drafts.
                SqliteWrapper.delete(mActivity, mContentResolver, mmsUri, null, null);
            }

            // Make sure this thread isn't over the limits in message count
            Recycler.getMmsRecycler().deleteOldMessagesByThreadId(mActivity, threadId);
        } catch (Exception e) {
            Log.e(TAG, "Failed to send message: " + mmsUri + ", threadId=" + threadId, e);
        }
        if (forwardMessage && sameRecipient) {
            MessageUtils.sSameRecipientList.remove(threadId);
        }
        MmsWidgetProvider.notifyDatasetChanged(mActivity);
        MessageUtils.updateThreadAttachTypeByThreadId(mActivity, threadId);
    }

---------------------------sendMmsWorker----------------------------

sendMmsWorker方法主要调用   MmsMessageSender里面的sendMessage方法进行数据库插入

在主要操作sender

 MessageSender sender = new MmsMessageSender(mActivity, mmsUri,
                slideshow.getCurrentMessageSize(), mCurrentConvSubId);
        try {
            if (!sender.sendMessage(threadId)) {
                // The message was sent through SMS protocol, we should
                // delete the copy which was previously saved in MMS drafts.
                SqliteWrapper.delete(mActivity, mContentResolver, mmsUri, null, null);
            }

            // Make sure this thread isn't over the limits in message count
            Recycler.getMmsRecycler().deleteOldMessagesByThreadId(mActivity, threadId);
        } catch (Exception e) {
            Log.e(TAG, "Failed to send message: " + mmsUri + ", threadId=" + threadId, e);
        }
        if (forwardMessage && sameRecipient) {
            MessageUtils.sSameRecipientList.remove(threadId);
        }


MmsMessageSender.java    主要也sendMessage()方法为主

 public boolean sendMessage(long token) throws MmsException {
        // Load the MMS from the message uri
        if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
            LogTag.debug("sendMessage uri: " + mMessageUri);
        }
        PduPersister p = PduPersister.getPduPersister(mContext);
        GenericPdu pdu = p.load(mMessageUri);

        if (pdu.getMessageType() != PduHeaders.MESSAGE_TYPE_SEND_REQ) {
            throw new MmsException("Invalid message: " + pdu.getMessageType());
        }

        SendReq sendReq = (SendReq) pdu;

        // Update headers.
        updatePreferencesHeaders(sendReq);

        // MessageClass.
        sendReq.setMessageClass(DEFAULT_MESSAGE_CLASS.getBytes());

        // Update the 'date' field of the message before sending it.
        sendReq.setDate(System.currentTimeMillis() / 1000L);

        sendReq.setMessageSize(mMessageSize);

        p.updateHeaders(mMessageUri, sendReq);

        long messageId = ContentUris.parseId(mMessageUri);

        // Move the message into MMS Outbox.
        if (!mMessageUri.toString().startsWith(Mms.Draft.CONTENT_URI.toString())) {
            // If the message is already in the outbox (most likely because we created a "primed"
            // message in the outbox when the user hit send), then we have to manually put an
            // entry in the pending_msgs table which is where TransacationService looks for
            // messages to send. Normally, the entry in pending_msgs is created by the trigger:
            // insert_mms_pending_on_update, when a message is moved from drafts to the outbox.
            ContentValues values = new ContentValues(7);

            values.put(PendingMessages.PROTO_TYPE, MmsSms.MMS_PROTO);
            values.put(PendingMessages.MSG_ID, messageId);
            values.put(PendingMessages.MSG_TYPE, pdu.getMessageType());
            values.put(PendingMessages.ERROR_TYPE, 0);
            values.put(PendingMessages.ERROR_CODE, 0);
            values.put(PendingMessages.RETRY_INDEX, 0);
            values.put(PendingMessages.DUE_TIME, 0);

            SqliteWrapper.insert(mContext, mContext.getContentResolver(),
                    PendingMessages.CONTENT_URI, values);
        } else {
            p.move(mMessageUri, Mms.Outbox.CONTENT_URI);
        }

        // Start MMS transaction service
        SendingProgressTokenManager.put(messageId, token);
        Intent intent = new Intent(mContext, TransactionService.class);
        intent.putExtra(Mms.SUBSCRIPTION_ID, mSubId);
        mContext.startService(intent);

        return true;
    }

----SqliteWrapper.insert()插入数据库

  SqliteWrapper.insert(mContext, mContext.getContentResolver(),
                    PendingMessages.CONTENT_URI, values);

插入成功后开启服务  TransactionService 

 Intent intent = new Intent(mContext, TransactionService.class);
        intent.putExtra(Mms.SUBSCRIPTION_ID, mSubId);
        mContext.startService(intent);


TransactionService .java 

这个类主要是进行图片上传和下载

主要看Handerl里面

  /**
         * Handle incoming transaction requests.
         * The incoming requests are initiated by the MMSC Server or by the
         * MMS Client itself.
         */
        @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:   //通知彩信接收  liwangjiang
                    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();

                        LogTag.debugD("handle EVENT_TRANSACTION_REQUEST: transactionType=" +
                                transactionType + " " + decodeTransactionType(transactionType));

                        // Create appropriate transaction
                        switch (transactionType) {
                            case Transaction.NOTIFICATION_TRANSACTION:
                                String uri = args.getUri();
                                //用户通知  liwangjiang
                                if (uri!=null){
                                    long threadId = MessagingNotification.getThreadId(
                                            getApplicationContext(), Uri.parse(uri));
                                    MessagingNotification.blockingUpdateNewMessageIndicator(getApplicationContext(),
                                            threadId,
                                            false);
                                    MessagingNotification.updateDownloadFailedNotification(getApplicationContext());
                                    MessageUtils.updateThreadAttachTypeByThreadId(getApplicationContext(), threadId);

                                }

                                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,
                                            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:
                    Log.w(TAG, "what=" + msg.what);
                    return;
            }
        }

handler    msg.what   会传入一个  5 就是     EVENT_NEW_INTENT  调用了   onNewIntent()方法

public void onNewIntent(Intent intent, int serviceId) {
        if (!MmsConfig.isSmsEnabled(getApplicationContext())) {
            LogTag.debugD("TransactionService: is not the default sms app");
            stopSelf(serviceId);
            return;
        }
        mConnMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        if (mConnMgr == null || !MmsConfig.isSmsEnabled(getApplicationContext())) {
            endMmsConnectivity();
            stopSelfIfIdle(serviceId);
            return;
        }
        boolean noNetwork = false;

        LogTag.debugD("onNewIntent: serviceId: " + serviceId + ": " + intent.getExtras() +
                " intent=" + intent);

        Bundle extras = intent.getExtras();
        String action = intent.getAction();

        DownloadManager downloadManager = DownloadManager.getInstance();

        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());
            LogTag.debugD("Cursor= " + DatabaseUtils.dumpCursorToString(cursor));
            if (cursor != null) {
                try {
                    int count = cursor.getCount();

                    LogTag.debugD("onNewIntent: cursor.count=" + count + " action=" + action);
                    //判断是否有未发送的如果没有就    停止服务
                    if (count == 0) {
                        LogTag.debugD("onNewIntent: no pending messages. Stopping service.");
                        RetryScheduler.setRetryAlarm(this);
                        stopSelfIfIdle(serviceId);
                        return;uricolumnIndexOfMsgId = cursor.getColumnIndexOrThrow(PendingMessages.MSG_ID);
                    int columnIndexOfMsgType = cursor.getColumnIndexOrThrow(
                            PendingMessages.MSG_TYPE);
                    int columnIndexOfRetryIndex = cursor.getColumnIndexOrThrow(
                            PendingMessages.RETRY_INDEX);

                    int inActiveSubCount = 0;
                    while (cursor.moveToNext()) {
                        int msgType = cursor.getInt(columnIndexOfMsgType);

                        int transactionType = getTransactionType(msgType);
                        if (transactionType==Transaction.RETRIEVE_TRANSACTION){
                            //如果是下载就跳出循环      transactionType=1就表示自动去再次请求下载   liwangjiang
                            continue;
                        }
                        LogTag.debugD("onNewIntent: msgType=" + msgType + " transactionType=" +
                                transactionType);
                        Uri uri = ContentUris.withAppendedId(
                                Mms.CONTENT_URI,
                                cursor.getLong(columnIndexOfMsgId));
                        boolean inRetry = cursor.getInt(columnIndexOfRetryIndex) > 0;
                        if (noNetwork) {
                            // Because there is a MMS queue list including
                            // unsent and undownload MMS in database while data
                            // network unenabled. Anyway we should give user the
                            // information about the last MMS in the queue list.
                            // While there is no data network, we will give
                            // a prompt to user about the last MMS failed in
                            // database, so we need to fetch the information of
                            // last pending MMS in the queue list, just make the
                            // cursor move to the end of the queue list, and
                            // give the corresponding prompt to user.
                            cursor.moveToLast();
                            //
                            transactionType = getTransactionType(cursor
                                    .getInt(columnIndexOfMsgType));
                            onNetworkUnavailable(serviceId, transactionType, uri, inRetry);
                            return;
                        }
                        switch (transactionType) {
                            case -1:
                                break;
                            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));
                                boolean autoDownload = downloadManager.isAuto();
                                LogTag.debugD("onNewIntent: failureType=" + failureType +
                                        " action=" + action + " isTransientFailure:" +
                                        isTransientFailure(failureType) + " autoDownload=" +
                                        autoDownload);
                                if (!autoDownload && !inRetry) {
                                    // If autodownload is turned off and not in retry peroid,
                                    // don't process the transaction.
                                    LogTag.debugD("onNewIntent: skipping - autodownload off");
                                    break;
                                }
                                // If retry always is enabled, need mark state to downloading.
                                if (getResources().getBoolean(R.bool.config_retry_always)) {
                                    downloadManager.markState(
                                            uri, DownloadManager.STATE_DOWNLOADING);

                                }
                                // 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))) {
                                    LogTag.debugD("onNewIntent: skipping - permanent error");
                                    break;
                                }
                                LogTag.debugD( "onNewIntent: falling through and processing");
                               // fall-through
                            default:

                                int subId = getSubIdFromDb(uri);

                                Log.d(TAG, "destination Sub Id = " + subId);
                                if (subId < 0) {
                                    Log.d(TAG, "Subscriptions are not yet ready.");
                                    int defSmsSubId = getDefaultSmsSubscriptionId();
                                    // We dont have enough info about subId. We dont know if the
                                    // subId as persent in DB actually would match the subId of
                                    // defaultSmsSubId. We can not also ignore this transaction
                                    // since no retry would be scheduled if we return from here. The
                                    // only option is to do best effort try on current default sms
                                    // subId, if it failed then a retry would be scheduled and while
                                    // processing that retry attempt we would be able to get correct
                                    // subId from subscription manager.
                                    Log.d(TAG, "Override with default Sms subId = " + defSmsSubId);
                                    subId = defSmsSubId;
                                }
                                if ((!isMmsAllowed())
                                        && !getResources().getBoolean(R.bool.config_retry_always)) {
                                    Log.d(TAG, "mobileData off or no mms apn or APM, Abort");
                                    if (transactionType == Transaction.RETRIEVE_TRANSACTION) {
                                        downloadManager.markState(uri,
                                                DownloadManager.STATE_TRANSIENT_FAILURE);
                                    }
                                    onNetworkUnavailable(serviceId, transactionType, uri, inRetry);
                                    break;
                                }

                                if (!SubscriptionManager.from(getApplicationContext())
                                        .isActiveSubId(subId)) {
                                    LogTag.debugD("SubId is not active:" + subId);
                                    inActiveSubCount ++;
                                    if (inActiveSubCount == count) {
                                        LogTag.debugD("No active SubId found, stop self: " + count);
                                        stopSelfIfIdle(serviceId);
                                    }
                                    break;
                                }

                                TransactionBundle args = new TransactionBundle(transactionType,
                                        uri.toString(), subId);
                                // FIXME: We use the same startId for all MMs.
                                LogTag.debugD("onNewIntent: launchTransaction uri=" + uri);
                                // FIXME: We use the same serviceId for all MMs.
                                launchTransaction(serviceId, args, false);
                                break;
                        }
                    }
                } finally {
                    cursor.close();
                }
            } else {
                LogTag.debugD("onNewIntent: no pending messages. Stopping service.");
                RetryScheduler.setRetryAlarm(this);
                stopSelfIfIdle(serviceId);
            }
        } 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 {
            LogTag.debugD("onNewIntent: launch transaction...");

            String uriStr = intent.getStringExtra("uri");
            Uri uri = Uri.parse(uriStr);

            int subId = getSubIdFromDb(uri);
            Log.d(TAG, "destination Sub Id = " + subId);
            if (subId < 0) {
               int defSmsSubId = getDefaultSmsSubscriptionId();
                Log.d(TAG, "Override with default Sms subId = " + defSmsSubId);
                subId = defSmsSubId;
            }

            if ((!isMmsAllowed()) && !getResources().getBoolean(R.bool.config_retry_always)) {
                Log.d(TAG, "Either mobile data is off or apn not present, Abort");

                downloadManager.markState(uri, DownloadManager.STATE_TRANSIENT_FAILURE);

                boolean isRetry = getRetryIndex(uri.getLastPathSegment()) > 0;
                int type = intent.getIntExtra(TransactionBundle.TRANSACTION_TYPE,
                        Transaction.NOTIFICATION_TRANSACTION);
                onNetworkUnavailable(serviceId, type, uri, isRetry);
                return;
            }

            if (!SubscriptionManager.from(getApplicationContext()).isActiveSubId(subId)) {
                LogTag.debugD("SubId is not active:" + subId);
                stopSelfIfIdle(serviceId);
                return;
            }

            Bundle bundle = intent.getExtras();
            bundle.putInt(ConstantsWrapper.Phone.SUBSCRIPTION_KEY, subId);
            // For launching NotificationTransaction and test purpose.
            TransactionBundle args = new TransactionBundle(bundle);
            launchTransaction(serviceId, args, noNetwork);
        }
    }

   onNewIntent主要查询数据库对彩信进行一些操作,在底层,还没有研究

onNewIntent发送一个信息到Handelr里面进行操作

    private void launchTransaction(int serviceId, TransactionBundle txnBundle, boolean noNetwork) {
        if (noNetwork) {
            Log.w(TAG, "launchTransaction: no network error!");
            onNetworkUnavailable(serviceId, txnBundle.getTransactionType(),
                    Uri.parse(txnBundle.getUri()), false);
            return;
        }
        //设置手动现在数据
        Message msg = mServiceHandler.obtainMessage(EVENT_TRANSACTION_REQUEST);//接收开始发送给NotificationTransation去接收短信
       // Message msg = mServiceHandler.obtainMessage(Transaction.RETRIEVE_TRANSACTION);//接收开始发送给NotificationTransation去接收短信
        msg.arg1 = serviceId;
        msg.obj = txnBundle;

        LogTag.debugD("launchTransaction: sending message " + msg);
        mServiceHandler.sendMessage(msg);
    }

在Handler里面启动   SendTransaction.java线程



SendTransaction.java主要操作进行调用父类的Transaction   ,我就全部复制了这个类很简单

/*
 * Copyright (C) 2007-2008 Esmertec AG.
 * Copyright (C) 2007-2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.mms.transaction;

import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SqliteWrapper;
import android.net.Uri;
import android.provider.Telephony.Mms;
import android.provider.Telephony.Mms.Sent;
import android.text.TextUtils;
import android.telephony.SubscriptionManager;
import android.util.Log;

import com.android.mms.LogTag;
import com.android.mms.MmsApp;
import com.android.mms.ui.MessageUtils;
import com.android.mms.util.RateController;
import com.android.mms.util.SendingProgressTokenManager;
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.SendConf;
import com.google.android.mms.pdu.SendReq;

import java.util.Arrays;

/**
 * The SendTransaction is responsible for sending multimedia messages
 * (M-Send.req) to the MMSC server.  It:
 *
 * <ul>
 * <li>Loads the multimedia message from storage (Outbox).
 * <li>Packs M-Send.req and sends it.
 * <li>Retrieves confirmation data from the server  (M-Send.conf).
 * <li>Parses confirmation message and handles it.
 * <li>Moves sent multimedia message from Outbox to Sent.
 * <li>Notifies the TransactionService about successful completion.
 * </ul>
 */
public class SendTransaction extends Transaction implements Runnable {
    private static final String TAG = LogTag.TAG;

    private Thread mThread;
    public final Uri mSendReqURI;

    public SendTransaction(Context context,
            int transId, TransactionSettings connectionSettings, String uri) {
        super(context, transId, connectionSettings);
        mSendReqURI = Uri.parse(uri);
        mId = uri;

        // Attach the transaction to the instance of RetryScheduler.
        attach(RetryScheduler.getInstance(context));
    }

    /*
     * (non-Javadoc)
     * @see com.android.mms.Transaction#process()
     */
    @Override
    public void process() {
        mThread = new Thread(this, "SendTransaction");
        mThread.start();
    }

    public void run() {
        try {
            RateController rateCtlr = RateController.getInstance();
            if (rateCtlr.isLimitSurpassed() && !rateCtlr.isAllowedByUser()) {
                Log.e(TAG, "Sending rate limit surpassed.");
                return;
            }

            // Load M-Send.req from outbox
            PduPersister persister = PduPersister.getPduPersister(mContext);
            SendReq sendReq = (SendReq) persister.load(mSendReqURI);
            // Update the 'date' field of the PDU right before sending it.
            long date = System.currentTimeMillis() / 1000L;
            sendReq.setDate(date);
            // Persist the new date value into database.
            ContentValues values = new ContentValues(1);
            values.put(Mms.DATE, date);
            SqliteWrapper.update(mContext, mContext.getContentResolver(),
                                 mSendReqURI, values, null, null);

            // fix bug 2100169: insert the 'from' address per spec
            String lineNumber = MessageUtils.getLocalNumber(mSubId);
            Log.d(TAG, "lineNumber " + lineNumber);
            if (!TextUtils.isEmpty(lineNumber)) {
                sendReq.setFrom(new EncodedStringValue(lineNumber));
            }

            // Pack M-Send.req, send it, retrieve confirmation data, and parse it
            long tokenKey = ContentUris.parseId(mSendReqURI);
            //sendReq  流在这个方法里面  liwangjiang
            PduComposer pdu = new PduComposer(mContext, sendReq);
            Log.v("jiangwanglisend","发送中。。。。。。。。");
            byte[] response = sendPdu(SendingProgressTokenManager.get(tokenKey), pdu.make(),mSendReqURI);
            Log.v("jiangwanglisend","已发送。。。。。。。。");
            SendingProgressTokenManager.remove(tokenKey);

            String respStr = new String(response);
            LogTag.debugD("[SendTransaction] run: send mms msg (" + mId + "), resp=" + respStr);

            SendConf conf = (SendConf) new PduParser(response,
                   PduParserUtil.shouldParseContentDisposition()).parse();
            if (conf == null) {
                Log.e(TAG, "No M-Send.conf received.");
            }

            // Check whether the responding Transaction-ID is consistent
            // with the sent one.
            byte[] reqId = sendReq.getTransactionId();
            byte[] confId = conf.getTransactionId();
            if (!Arrays.equals(reqId, confId)) {
                Log.e(TAG, "Inconsistent Transaction-ID: req="
                        + new String(reqId) + ", conf=" + new String(confId));
                return;
            }

            // From now on, we won't save the whole M-Send.conf into
            // our database. Instead, we just save some interesting fields
            // into the related M-Send.req.
            values = new ContentValues(2);
            int respStatus = conf.getResponseStatus();
            values.put(Mms.RESPONSE_STATUS, respStatus);

            if (respStatus != PduHeaders.RESPONSE_STATUS_OK) {
                SqliteWrapper.update(mContext, mContext.getContentResolver(),
                                     mSendReqURI, values, null, null);
                Log.e(TAG, "Server returned an error code: " + respStatus);
                return;
            }

            String messageId = PduPersister.toIsoString(conf.getMessageId());
            values.put(Mms.MESSAGE_ID, messageId);
            SqliteWrapper.update(mContext, mContext.getContentResolver(),
                                 mSendReqURI, values, null, null);

            // Move M-Send.req from Outbox into Sent.
            Uri uri = persister.move(mSendReqURI, Sent.CONTENT_URI);

            mTransactionState.setState(TransactionState.SUCCESS);
            mTransactionState.setContentUri(uri);
        } catch (Throwable t) {
            Log.e(TAG, Log.getStackTraceString(t));
        } finally {
            LogTag.debugD("[SendTransaction]remove cache:" + mSendReqURI);
            MmsApp.getApplication().getPduLoaderManager().removePdu(mSendReqURI);
            if (mTransactionState.getState() != TransactionState.SUCCESS) {
                mTransactionState.setState(TransactionState.FAILED);
                mTransactionState.setContentUri(mSendReqURI);
                Log.e(TAG, "Delivery failed.");
            }
            notifyObservers();
        }
    }

    @Override
    public void abort() {
        Log.d(TAG, "markFailed = " + this);
        mTransactionState.setState(TransactionState.FAILED);
        mTransactionState.setContentUri(mSendReqURI);
        mFailReason = FAIL_REASON_CAN_NOT_SETUP_DATA_CALL;

        notifyObservers();
    }

    @Override
    public int getType() {
        return SEND_TRANSACTION;
    }
}


内容太多发布失败,分开发布    点击继续   彩信发送过程第二篇

猜你喜欢

转载自blog.csdn.net/qq_35427437/article/details/88673812