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 RecipientscheckConversationHasRecipients(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() {  //发送信息调用@Overridepublic 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() {@Overridepublic void run() {preSendSmsWorker(conv, msgText, recipientsInUI);updateSendStats(conv);}}, "WorkingMessage.send SMS").start();}// update the Recipient cache with the new to address, if it's differentRecipientIdCache.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 firstDraftCache.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 sendingContentValues 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 countRecycler.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 countRecycler.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 uriif (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 serviceSendingProgressTokenManager.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.*/@Overridepublic 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();LogTag.debugD("handle EVENT_TRANSACTION_REQUEST: transactionType=" +transactionType + " " + decodeTransactionType(transactionType));// Create appropriate transactionswitch (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);}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就表示自动去再次请求下载 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-throughdefault: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()*/@Overridepublic 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 outboxPduPersister 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 specString 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 itlong tokenKey = ContentUris.parseId(mSendReqURI);//sendReq  流在这个方法里面PduComposer pdu = new PduComposer(mContext, sendReq);byte[] response = sendPdu(SendingProgressTokenManager.get(tokenKey), pdu.make(),mSendReqURI);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();}}@Overridepublic void abort() {Log.d(TAG, "markFailed = " + this);mTransactionState.setState(TransactionState.FAILED);mTransactionState.setContentUri(mSendReqURI);mFailReason = FAIL_REASON_CAN_NOT_SETUP_DATA_CALL;notifyObservers();}@Overridepublic int getType() {return SEND_TRANSACTION;}
}


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

Android短信开发 发送彩信 ‘ 高通源码 ‘ (彩信发送过程1)相关推荐

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

    上一篇内容太多发布失败,分开发布    点击继续   彩信发送过程第一篇 Transaction.java 这个类主要是sendPdu方法   也挺简单的 /** Copyright (C) 2007 ...

  2. Android 短信开发学习

    2019独角兽企业重金招聘Python工程师标准>>> 短信 sms  文件 /data/data/com.android.providers.telephony/databases ...

  3. 高通源码编译提示错误

    从网上直接下载的高通源代码,全部编译. 提示错误如下: ninja: Entering directory `.' [  0% 5/27986] target SharedLib: libc (out ...

  4. 2023最新匿名短信【时光送信】H5源码V3.0版+后端管理

    如果把这个做成副业那将大大增加你每天的收益像这种看似简单,非常冷漠小众的项目,往往可以带给你超高收益,而且每条短信成本1毛都不到 在微信上搜索"时光送信",点击下方公众号 进入平台 ...

  5. Python数据挖掘处理通话数据、短信以及上网记录完整项目+源码+源码解释

    对通话.短信以及上网记录的数据来预测风险用户 本文代码全部采用jupyter运行 先导入相关的包 # -*- coding: UTF-8 -*- import pandas as pd import ...

  6. 手写代码详解Android Hook入门demo,android应用案例开发大全第四版源码

    2. 实用价值 3. 前置技能 4. hook通用思路 5. 案例实战 6. 效果展示 正文 == 1. hook的定义 hook,钩子.勾住系统的程序逻辑. 在某段SDK源码逻辑执行的过程中,通过代 ...

  7. Android移动应用开发课程设计(含源码)

    这是一个较为简单理解的Android项目,是一个关于医学小知识的APP,运用了Fragment控件和RecyclerView控件,使用Android自带的MySQLite数据库实现数据存储(也可以通过 ...

  8. Android Studio中配置及使用OpenCV示例(一),android应用案例开发大全第四版源码

    OK!先看看OpenCVActivity中是如何写的: public class OpenCVActivity extends Activity{ private Button btn; privat ...

  9. 基于ASP.NET开发的企信通源码 短信管理平台源码

    ASP.NET企信通源码 短信平台源码 源码免费分享,需要学习可私信. 技术特点: 1 .先进的应用开发平台与开发环境 2 .高开发速度与低总体拥有成本(TCO,Total Cost of Owner ...

最新文章

  1. CoordinatorLayout 的jar包位置
  2. Python图像处理:形态学操作
  3. 【深度学习入门到精通系列】nnU-Net论文解析
  4. 【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 )
  5. boost::log::dynamic_type_dispatcher用法的测试程序
  6. SQL Server,Oracle,DB2索引建立语句的对比
  7. Linux | 进程概念、进程状态(僵尸进程、孤儿进程、守护进程)、进程地址空间
  8. Ribbon负载均衡原理,Feign是如何整合Ribbon的?
  9. java判断路径是否存在_科学网—Java判断文件目录以及文件是否存在 - 林清莹的博文...
  10. GPS经纬度的表示方法及换算
  11. word转pdf时图片模糊+文字版权的有效处理方式——Microsoft Print to PDF(YYDS)
  12. 重点人员动态管控系统开发方案,情指勤一体化平台建设
  13. 大数据平台核心架构图鉴,建议收藏
  14. 苹果电脑怎么登录邮件服务器,Mac系统中的邮箱怎么创建126邮箱帐户?
  15. 容器镜像仓库Harbor安装部署及简单使用
  16. Linux私房菜--第三章 主机规划和磁盘分区
  17. Bootstrap - 前端框架
  18. 新墨斯智能鞋让你成为健康达人
  19. 国产Linux系统再添一员猛将,颜值完全不输苹果!
  20. 成为软件工程师之前,你必须了解这些

热门文章

  1. Dell R730服务器inter 500系列网卡与光模块不兼容**
  2. CarSim软件介绍(一)——界面介绍
  3. 【Notepad++】Notepad++格式化JSON数据
  4. 用PHOTOSHOP给图片打马赛克
  5. 4ARM-PEG-OH 四臂PEG羟基
  6. 压缩包 zip RAR 7z 密码破解常用的几种方法
  7. ORACEL R12 总账和子账的关系
  8. 为了下一代,抖音真的该关了---读<<我观察到的牛人有这三个特质>>有感
  9. 使用pyqt弹出消息提示框
  10. 一卡通(M1卡)破解过程记录——理论篇