MMS發(fā)送流程 1. 點擊發(fā)送按鈕Src/com/android/mms/ui/ComposeMessageActivity.java public void onClick(View v) { if ((v == mSendButton) && isPreparedForSending()) { confirmSendMessageIfNeeded(); //確認是否需要發(fā)送短信—-》 } }
2.src/com/android/mms/ui/ComposeMessageActivity.java private void confirmSendMessageIfNeeded() { if (!isRecipientsEditorVisible()) { //編輯聯(lián)系人不可見時,也就是給已存在會話的聯(lián)系人發(fā)送短信時 sendMessage(true); return; }
boolean isMms = mWorkingMessage.requiresMms(); //是否需要以彩信形式發(fā)送 if (mRecipientsEditor.hasInvalidRecipient(isMms)) {//是否含有不合法的收件人 if (mRecipientsEditor.hasValidRecipient(isMms)) {//有合法的和不合法的,彈出嘗試發(fā)送對話框 String title = getResourcesString(R.string.has_invalid_recipient, mRecipientsEditor.formatInvalidNumbers(isMms)); new AlertDialog.Builder(this) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle(title) .setMessage(R.string.invalid_recipient_message) .setPositiveButton(R.string.try_to_send, newSendIgnoreInvalidRecipientListener()) .setNegativeButton(R.string.no, new CancelSendingListener()) .show(); } else {//如果全是不合法的聯(lián)系人,提示不能發(fā)送信息 new AlertDialog.Builder(this) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle(R.string.cannot_send_message) .setMessage(R.string.cannot_send_message_reason) .setPositiveButton(R.string.yes, new CancelSendingListener()) .show(); } } else {//判斷收件人沒有問題,接著發(fā)送信息 --》 sendMessage(true); } }
3. src/com/android/mms/ui/ComposeMessageActivity.java private void sendMessage(boolean bCheckEcmMode) { Log.v(TAG, "sendMessage"); if (bCheckEcmMode) { // TODO: expose this in telephony layer for SDK build String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE); //判斷電話是否處于緊急撥號模式,得到的inEcm一般為空 Log.v(TAG, "inEcm = " + inEcm); if (Boolean.parseBoolean(inEcm)) { try { startActivityForResult( new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS,null), REQUEST_CODE_ECM_EXIT_DIALOG); return; } catch (ActivityNotFoundException e) { // continue to send message Log.e(TAG, "Cannot find EmergencyCallbackModeExitDialog", e); } } }
if (!mSendingMessage) { // send can change the recipients. Make sure we remove the listeners firstand then add // them back once the recipient list has settled. removeRecipientsListeners(); //取消對收件人的監(jiān)聽 mWorkingMessage.send(); //發(fā)送信息—-》 mSentMessage = true; mSendingMessage = true; addRecipientsListeners(); //重新添加收件人監(jiān)聽 } // But bail out if we are supposed to exit after the message is sent. if (mExitOnSent) {//如果mExitOnSent為true,信息發(fā)送完成后退出Activity finish(); } }
4. src/com/android/mms/data/WorkingMessage.java /** * Send this message over the network. Will call back with onMessageSent() once * it has been dispatched to the telephonystack. This WorkingMessage object is * no longer useful after this method hasbeen called. */ public void send() { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { LogTag.debug("send"); }
// Get ready to write to disk. prepareForSave(true /* notify */);//主要做一下同步收件人和WorkingMessage,彩信時在準備其他一些東西
// We need the recipient list for both SMS and MMS. final Conversation conv = mConversation; String msgTxt = mText.toString(); Log.v(TAG, "msgText = " + msgTxt); if (requiresMms()|| addressContainsEmailToMms(conv, msgTxt)) { // 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; //如果第一次發(fā)送,此時mmsUri為null,如果是重發(fā),則是草稿箱的地址 mMessageUri =content://mms/drafts/1 final PduPersister persister = PduPersister.getPduPersister(mContext);
final SlideshowModel slideshow = mSlideshow; final SendReq sendReq = makeSendReq(conv,mSubject);
// Do the dirty work of sending the message off of the main UI thread. new Thread(new Runnable() { public void run() { // 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); } }).start(); }else { // Same rules apply as above. final String msgText = mText.toString();//取出短消息 Log.v(TAG, "msgText = " + msgText); new Thread(new Runnable() { public void run() { preSendSmsWorker(conv, msgText);//發(fā)送信息--》 } }).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; }
5. src/com/android/mms/data/WorkingMessage.java private void sendMmsWorker(Conversation conv, Uri mmsUri, PduPersisterpersister, SlideshowModel slideshow, SendReq sendReq) { Log.v(TAG, "sendMmsWorker"); // If user tries to send the message, it's a signal the inputtedtext is what they wanted. UserHappinessSignals.userAcceptedImeText(mContext);
// First make sure we don't have too many outstanding unsent message. Cursor cursor = null; try { cursor = SqliteWrapper.query(mContext, mContentResolver, Mms.Outbox.CONTENT_URI,MMS_OUTBOX_PROJECTION, null, null, null); if (cursor != null) {//如果MMS_OUTBOX里有未發(fā)送的彩信,并且總的大小已經(jīng)超過了彩信的最大限制,則取消此次發(fā)送,并存入草稿箱 Log.v(TAG, "query Mms.Outbox.CONTENT_URI is not empty"); long maxMessageSize = MmsConfig.getMaxSizeScaleForPendingMmsAllowed()* MmsConfig.getMaxMessageSize(); Log.v(TAG, "MmsConfig.getMaxSizeScaleForPendingMmsAllowed() =" + MmsConfig.getMaxSizeScaleForPendingMmsAllowed()); Log.v(TAG, "MmsConfig.getMaxMessageSize()() = " + MmsConfig.getMaxMessageSize());
long totalPendingSize = 0; while (cursor.moveToNext()) { totalPendingSize +=cursor.getLong(MMS_MESSAGE_SIZE_INDEX); Log.v(TAG, "totalPendingSize = " + totalPendingSize); } if (totalPendingSize >= maxMessageSize) { unDiscard(); // itwasn't successfully sent. Allow it to be saved as a draft. mStatusListener.onMaxPendingMessagesReached(); return; } }else{ Log.v(TAG, "query Mms.Outbox.CONTENT_URI is empty"); } } finally { if (cursor != null) { cursor.close(); } } mStatusListener.onPreMessageSent();
// Make sure we are still using the correct thread ID for our // recipient set. long threadId = conv.ensureThreadId();
if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { LogTag.debug("sendMmsWorker: update draft MMS message " + mmsUri); }
if (mmsUri == null) {//如果是首次發(fā)送,先把彩信保存入草稿箱 // Create a new MMS message if one hasn't been made yet. Log.v(TAG, "mmsUri == null and startcreateDraftMmsMessage"); mmsUri = createDraftMmsMessage(persister,sendReq, slideshow); } else { // Otherwise, sync the MMS message in progress to disk. Log.v(TAG, "mmsUri = " + mmsUri); Log.v(TAG, "updateDraftMmsMessage"); updateDraftMmsMessage(mmsUri,persister, slideshow, sendReq); }
// Be paranoid and clean any draft SMS up. deleteDraftSmsMessage(threadId);
// 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; }
MessageSender sender = new MmsMessageSender(mContext, mmsUri, slideshow.getCurrentMessageSize()); 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(mContext, mContentResolver, mmsUri, null, null); }
// Make sure this thread isn't over the limits in message count Recycler.getMmsRecycler().deleteOldMessagesByThreadId(mContext, threadId); } catch (Exception e) { Log.e(TAG, "Failed to send message: " + mmsUri + ",threadId=" + threadId, e); }
mStatusListener.onMessageSent(); }
6.src/com/android/mms/transaction/MmsMessageSender.java public boolean sendMessage(long token) throws MmsException { // Load the MMS from the message uri 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);
// Move the message into MMS Outbox p.move(mMessageUri, Mms.Outbox.CONTENT_URI);
// Start MMS transaction service SendingProgressTokenManager.put(ContentUris.parseId(mMessageUri), token); mContext.startService(new Intent(mContext, TransactionService.class));
return true; }
7.src/com/android/mms/transaction/TransactionService.java @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.v(TAG, "onStartCommand"); if (intent == null) { return Service.START_NOT_STICKY; } mConnMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); boolean noNetwork =!isNetworkAvailable();
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "onStart: #" + startId + ": " + intent.getExtras() + " intent=" + intent); Log.v(TAG, " networkAvailable=" + !noNetwork); } Log.v(TAG, "getAction is " + intent.getAction()); if (ACTION_ONALARM.equals(intent.getAction())|| (intent.getExtras() == null)) { Log.v(TAG, "ACTION_ONALARM.equals(intent.getAction()) ||(intent.getExtras() == null)"); // Scan database to find all pending operations. Cursor cursor = PduPersister.getPduPersister(this).getPendingMessages( System.currentTimeMillis()); if (cursor != null) { try { int count = cursor.getCount();
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "onStart: cursor.count=" + count); }
if (count == 0) { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "onStart: no pending messages. Stoppingservice."); } RetryScheduler.setRetryAlarm(this); stopSelfIfIdle(startId); return Service.START_NOT_STICKY; }
int columnIndexOfMsgId =cursor.getColumnIndexOrThrow(PendingMessages.MSG_ID); int columnIndexOfMsgType =cursor.getColumnIndexOrThrow( PendingMessages.MSG_TYPE);
if (noNetwork) { // Make sure we register for connection state changes. if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "onStart: registerForConnectionStateChanges"); } MmsSystemEventReceiver.registerForConnectionStateChanges( getApplicationContext()); }
while (cursor.moveToNext()) { int msgType =cursor.getInt(columnIndexOfMsgType); int transactionType =getTransactionType(msgType); Log.v(TAG, "msgType = " + msgType); Log.v(TAG, "transactionType = " + transactionType); if (noNetwork) { onNetworkUnavailable(startId, transactionType); return Service.START_NOT_STICKY; }
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. int failureType =cursor.getInt( cursor.getColumnIndexOrThrow( PendingMessages.ERROR_TYPE)); if (!isTransientFailure(failureType)){ break; } // fall-through default: Uri uri =ContentUris.withAppendedId( Mms.CONTENT_URI, cursor.getLong(columnIndexOfMsgId)); TransactionBundle args = new TransactionBundle( transactionType, uri.toString()); // FIXME: We use the same startId for all MMs. launchTransaction(startId, args, false); break; } } } finally { cursor.close(); } } else { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "onStart: no pending messages. Stoppingservice."); } RetryScheduler.setRetryAlarm(this); stopSelfIfIdle(startId); } } else { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "onStart: launch transaction..."); } // For launching NotificationTransaction and test purpose. TransactionBundle args = newTransactionBundle(intent.getExtras()); launchTransaction(startId, args,noNetwork); } return Service.START_NOT_STICKY; }
8. src/com/android/mms/transaction/TransactionService.java private void launchTransaction(int serviceId,TransactionBundle txnBundle, boolean noNetwork) { Log.v(TAG, "launchTransaction"); if (noNetwork) { Log.w(TAG, "launchTransaction: no network error!"); onNetworkUnavailable(serviceId,txnBundle.getTransactionType()); return; } Message msg = mServiceHandler.obtainMessage(EVENT_TRANSACTION_REQUEST); msg.arg1 = serviceId; msg.obj = txnBundle;
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "launchTransaction: sending message " + msg); } mServiceHandler.sendMessage(msg); }
9. src/com/android/mms/transaction/TransactionService.java private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); }
/** * Handle incoming transactionrequests. * The incoming requests are initiatedby the MMSC Server or by the * MMS Client itself. */ @Override public void handleMessage(Messagemsg) { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "Handling incoming message: " + msg); }
Transaction transaction = null;
switch (msg.what) { case EVENT_QUIT: getLooper().quit(); return;
case EVENT_CONTINUE_MMS_CONNECTIVITY: synchronized (mProcessing) { if (mProcessing.isEmpty()) { return; } }
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "handle EVENT_CONTINUE_MMS_CONNECTIVITYevent..."); }
try { int result =beginMmsConnectivity(); if (result != Phone.APN_ALREADY_ACTIVE){ Log.v(TAG, "Extending MMS connectivity returned " + result + " instead of APN_ALREADY_ACTIVE"); // Just wait for connectivity startup without // any newrequest of APN switch. return; } } catch (IOException e) { Log.w(TAG, "Attempt to extend use of MMS connectivityfailed"); return; }
// Restart timer sendMessageDelayed(obtainMessage(EVENT_CONTINUE_MMS_CONNECTIVITY), APN_EXTENSION_WAIT); return;
case EVENT_DATA_STATE_CHANGED: /* * If we are being informedthat connectivity has been established * to allow MMS traffic,then proceed with processing the pending * transaction, if any. */ if (mConnectivityListener == null) { return; }
NetworkInfo info = mConnectivityListener.getNetworkInfo(); if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "Handle DATA_STATE_CHANGED event: " + info); }
// Check availability of the mobile network. if ((info == null) || (info.getType() != ConnectivityManager.TYPE_MOBILE_MMS)) { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, " type isnot TYPE_MOBILE_MMS, bail"); } return; }
if (!info.isConnected()) { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, " TYPE_MOBILE_MMS not connected, bail"); } return; }
TransactionSettings settings = newTransactionSettings( TransactionService.this,info.getExtraInfo());
// If this APN doesn't have an MMSC, wait for one that does. if (TextUtils.isEmpty(settings.getMmscUrl())){ if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, " empty MMSCurl, bail"); } return; }
// Set a timer to keep renewing our "lease" on the MMSconnection sendMessageDelayed(obtainMessage(EVENT_CONTINUE_MMS_CONNECTIVITY), APN_EXTENSION_WAIT); processPendingTransaction(transaction, settings); return;
case EVENT_TRANSACTION_REQUEST://響應請求 Log.v(TAG, "EVENT_TRANSACTION_REQUEST"); int serviceId = msg.arg1; try { TransactionBundle args= (TransactionBundle) msg.obj; TransactionSettingstransactionSettings;
// Set the connection settings for this transaction. // If these have not been set in args, load thedefault settings. String mmsc =args.getMmscUrl(); if (mmsc != null) { transactionSettings= new TransactionSettings( mmsc,args.getProxyAddress(), args.getProxyPort()); } else { transactionSettings= new TransactionSettings( TransactionService.this, null); }
int transactionType =args.getTransactionType(); Log.v(TAG, "transactionType = " + transactionType); if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "handle EVENT_TRANSACTION_REQUEST:transactionType=" + transactionType); }
// Create appropriate transaction switch (transactionType){ case Transaction.NOTIFICATION_TRANSACTION: String uri =args.getUri(); if (uri != null) { transaction= new NotificationTransaction( TransactionService.this, serviceId, transactionSettings, uri); } else { // Now it's only used for test purpose. byte[] pushData =args.getPushData(); PduParserparser = new PduParser(pushData); GenericPdu ind= parser.parse();
int type = PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND; if ((ind != null) &&(ind.getMessageType() == type)) { transaction = newNotificationTransaction( TransactionService.this, serviceId, transactionSettings, (NotificationInd) ind); } else { Log.e(TAG, "Invalid PUSH data."); transaction = null; return; } } break; case Transaction.RETRIEVE_TRANSACTION: transaction = newRetrieveTransaction( TransactionService.this, serviceId, transactionSettings, args.getUri()); break; case Transaction.SEND_TRANSACTION://根據(jù)transactiontype響應發(fā)送彩信 Log.v(TAG, "Transaction.SEND_TRANSACTION"); transaction = new SendTransaction( TransactionService.this, serviceId, transactionSettings, args.getUri()); break; case Transaction.READREC_TRANSACTION: transaction = newReadRecTransaction( TransactionService.this, serviceId, transactionSettings, args.getUri()); break; default: Log.w(TAG, "Invalidtransaction type: " + serviceId); transaction = null; return; }
if (!processTransaction(transaction)) { transaction = null; return; }
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "Started processing of incoming message: " + msg); } } catch (Exception ex) { Log.w(TAG, "Exception occurred while handling message: " + msg, ex);
if (transaction != null) { try { transaction.detach(TransactionService.this); if (mProcessing.contains(transaction)){ synchronized (mProcessing) { mProcessing.remove(transaction); } } } catch (Throwable t) { Log.e(TAG, "Unexpected Throwable.", t); } finally { // Set transaction to null to allow stopping the // transaction service. transaction = null; } } } finally { if (transaction == null) { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "Transaction was null. Stopping self: " + serviceId); } endMmsConnectivity(); stopSelf(serviceId); } } return; case EVENT_HANDLE_NEXT_PENDING_TRANSACTION: processPendingTransaction(transaction, (TransactionSettings) msg.obj); return; default: Log.w(TAG, "what=" + msg.what); return; } }
10. src/com/android/mms/transaction/TransactionService.java /** * Internal method to begin processinga transaction. * @param transaction the transaction. Must not http://www.qqstock.cn/mailto:be%7B@code null}. * @return http://www.qqstock.cn/mailto:%7B@code true} if process hasbegun or will begin. http://www.qqstock.cn/mailto:%7B@code false} * if the transaction should bediscarded. * @throws IOException if connectivityfor MMS traffic could not be * established. */ private boolean processTransaction(Transaction transaction) throws IOException { // Check if transaction already processing Log.v(TAG, "processTransaction"); synchronized (mProcessing) { for (Transaction t : mPending) { if (t.isEquivalent(transaction)) { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "Transaction already pending: " + transaction.getServiceId()); } return true; } } for (Transaction t : mProcessing) { if (t.isEquivalent(transaction)) { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "Duplicated transaction: " + transaction.getServiceId()); } return true; } }
/* * Make sure that the networkconnectivity necessary * for MMS traffic is enabled.If it is not, we need * to defer processing thetransaction until * connectivity is established. */ if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "processTransaction: callbeginMmsConnectivity..."); } int connectivityResult = beginMmsConnectivity(); if (connectivityResult == Phone.APN_REQUEST_STARTED){ mPending.add(transaction); if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "processTransaction: connResult=APN_REQUEST_STARTED," + "defer transaction pending MMS connectivity"); } return true; }
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "Adding transaction to 'mProcessing' list: " + transaction); } mProcessing.add(transaction); }
// Set a timer to keep renewing our "lease" on the MMSconnection sendMessageDelayed(obtainMessage(EVENT_CONTINUE_MMS_CONNECTIVITY), APN_EXTENSION_WAIT);
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "processTransaction: starting transaction " + transaction); }
// Attach to transaction and process it transaction.attach(TransactionService.this); transaction.process(); return true; }
11.src/com/android/mms/transaction/SendTransaction.java @Override public void process() { Log.v(TAG, "process"); mThread = new Thread(this); mThread.start(); }
12. src/com/android/mms/transaction/SendTransaction.java public void run() { Log.v(TAG, "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(); 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); byte[] response = sendPdu(SendingProgressTokenManager.get(tokenKey), new PduComposer(mContext,sendReq).make());//發(fā)送彩信 SendingProgressTokenManager.remove(tokenKey);
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { String respStr = new String(response); Log.d(TAG, "[SendTransaction] run: send mms msg (" + mId + "),resp=" + respStr); }
SendConf conf = (SendConf)new PduParser(response).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 { if (mTransactionState.getState() != TransactionState.SUCCESS) { mTransactionState.setState(TransactionState.FAILED); mTransactionState.setContentUri(mSendReqURI); Log.e(TAG, "Delivery failed."); } notifyObservers(); } }
13.src/com/android/mms/transaction/Transaction.java /** * A common method to send a PDU to MMSC. * * @param token The token to identify the sendingprogress. * @param pdu A byte array which contains the dataof the PDU. * @return A byte array which containsthe response data. * If an HTTP error code is returned, an IOException will be thrown. * @throws IOException if any erroroccurred on network interface or * an HTTP error code(>=400) returned from the server. */ protected byte[] sendPdu(long token, byte[]pdu) throws IOException { return sendPdu(token, pdu, mTransactionSettings.getMmscUrl()); }
14. src/com/android/mms/transaction/Transaction.java protected byte[] sendPdu(long token, byte[] pdu, StringmmscUrl) throws IOException { ensureRouteToHost(mmscUrl, mTransactionSettings); return HttpUtils.httpConnection( mContext, token, mmscUrl, pdu, HttpUtils.HTTP_POST_METHOD, mTransactionSettings.isProxySet(), mTransactionSettings.getProxyAddress(), mTransactionSettings.getProxyPort());//通過網(wǎng)絡發(fā)送彩信,AP層的最后實現(xiàn) |
|