彩信发送。
这篇写彩信发送过程。
我想追踪的内容是:用户按下发送之后,彩信的图片阿数据阿文件阿,是怎么包装起来,最后发送出去。
按我看源码的先后顺序来写了。 写完可能最后整理下。
1. com.android.mms.data.WorkingMessage.java 类
send()函数。 注释如下:
/**
* Send this message over the network. Will call back with onMessageSent()
* once it has been dispatched to the telephony stack. This WorkingMessage
* object is no longer useful after this method has been called.
*/
这个是2.1的源码
public void send() { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { LogTag.debug("send"); } // Get ready to write to disk. prepareForSave(true /* notify */); // We need the recipient list for both SMS and MMS. final Conversation conv = mConversation; String msgTxt = mText.toString(); 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; final PduPersister persister = PduPersister .getPduPersister(mContext); final SlideshowModel slideshow = mSlideshow; final SendReq sendReq = makeSendReq(conv, mSubject); // Make sure the text in slide 0 is no longer holding onto a // reference to the text // in the message text box. slideshow.prepareForSend(); // Do the dirty work of sending the message off of the main UI // thread. new Thread(new Runnable() { public void run() { sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq); } }).start(); } else { // Same rules apply as above. final String msgText = mText.toString(); new Thread(new Runnable() { public void run() { sendSmsWorker(conv, msgText); } }).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; }
private void sendMmsWorker(Conversation conv, Uri mmsUri, PduPersister persister, SlideshowModel slideshow, SendReq sendReq) { // First make sure we don't have too many outstanding unsent message. Cursor cursor = null; try { Log.d("GN@@@","mContext: "+mContext.toString()); Log.d("GN@@@","mContentResolver: "+mContentResolver.toString()); Log.d("GN@@@","Mms.Outbox.CONTENT_URI: "+Mms.Outbox.CONTENT_URI.toString()); cursor = SqliteWrapper.query(mContext, 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(); return; } } } 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) { // Create a new MMS message if one hasn't been made yet. mmsUri = createDraftMmsMessage(persister, sendReq, slideshow); } else { // Otherwise, sync the MMS message in progress to disk. updateDraftMmsMessage(mmsUri, persister, slideshow, sendReq); } // Be paranoid and clean any draft SMS up. deleteDraftSmsMessage(threadId); 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(); }
public MmsMessageSender(Context context, Uri location, long messageSize) { mContext = context; mMessageUri = location; mMessageSize = messageSize; if (mMessageUri == null) { throw new IllegalArgumentException("Null message URI."); } }
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; }
PduBody pb = slideshow.toPduBody(); sendReq.setBody(pb); Uri res = persister.persist(sendReq, Mms.Draft.CONTENT_URI); slideshow.sync(pb);
persister.updateHeaders(uri, sendReq); final PduBody pb = slideshow.toPduBody(); persister.updateParts(uri, pb); slideshow.sync(pb);
//其中context=null。 isMakingCopy=false。 document=mDocumentCache private PduBody makePduBody(Context context, SMILDocument document, boolean isMakingCopy) { PduBody pb = new PduBody(); boolean hasForwardLock = false; for (SlideModel slide : mSlides) { for (MediaModel media : slide) { if (isMakingCopy) { if (media.isDrmProtected() && !media.isAllowedToForward()) { hasForwardLock = true; continue; } } PduPart part = new PduPart(); if (media.isText()) { TextModel text = (TextModel) media; // Don't create empty text part. if (TextUtils.isEmpty(text.getText())) { continue; } // Set Charset if it's a text media. part.setCharset(text.getCharset()); } // Set Content-Type. part.setContentType(media.getContentType().getBytes()); String src = media.getSrc(); String location; boolean startWithContentId = src.startsWith("cid:"); if (startWithContentId) { location = src.substring("cid:".length()); } else { location = src; } // Set Content-Location. part.setContentLocation(location.getBytes()); // Set Content-Id. if (startWithContentId) { // Keep the original Content-Id. part.setContentId(location.getBytes()); } else { int index = location.lastIndexOf("."); String contentId = (index == -1) ? location : location .substring(0, index); part.setContentId(contentId.getBytes()); } if (media.isDrmProtected()) { DrmWrapper wrapper = media.getDrmObject(); part.setDataUri(wrapper.getOriginalUri()); part.setData(wrapper.getOriginalData()); } else if (media.isText()) { part.setData(((TextModel) media).getText().getBytes()); } else if (media.isImage() || media.isVideo() || media.isAudio()) { part.setDataUri(media.getUri()); } else { Log.w(TAG, "Unsupport media: " + media); } pb.addPart(part); } } if (hasForwardLock && isMakingCopy && context != null) { Toast.makeText(context, context.getString(R.string.cannot_forward_drm_obj), Toast.LENGTH_LONG).show(); document = SmilHelper.getDocument(pb); } // Create and insert SMIL part(as the first part) into the PduBody. ByteArrayOutputStream out = new ByteArrayOutputStream(); SmilXmlSerializer.serialize(document, out); PduPart smilPart = new PduPart(); smilPart.setContentId("smil".getBytes()); smilPart.setContentLocation("smil.xml".getBytes()); smilPart.setContentType(ContentType.APP_SMIL.getBytes()); smilPart.setData(out.toByteArray()); pb.addPart(0, smilPart); return pb; }