为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

51CTO下载-Android彩信发送介绍

2011-11-13 10页 doc 83KB 23阅读

用户头像

is_506237

暂无简介

举报
51CTO下载-Android彩信发送介绍Android彩信发送介绍   编辑文档 这篇写彩信发送过程。 我想追踪的内容是:用户按下发送之后,彩信的图片阿数据阿文件阿,是怎么包装起来,最后发送出去。 按我看源码的先后顺序来写了。 写完可能最后整理下。 1. com.Android.mms.data.WorkingMessage.Java 类 send()函数。 注释如下:     /**      * Send this message over the network. Will call back with onMessageSent(...
51CTO下载-Android彩信发送介绍
Android彩信发送介绍   编辑文档 这篇写彩信发送过程。 我想追踪的是:用户按下发送之后,彩信的图片阿数据阿文件阿,是怎么包装起来,最后发送出去。 按我看源码的先后顺序来写了。 写完可能最后整理下。 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的源码 Java代码 复制到剪贴板  Java代码 1. public void send() {      2.     if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {      3.         LogTag.debug("send");      4.     }      5.       6.     // Get ready to write to disk.      7.     prepareForSave(true /* notify */);      8.       9.     // We need the recipient list for both SMS and MMS.      10.     final Conversation conv = mConversation;      11.     String msgTxt = mText.toString();      12.       13.     if (requiresMms() || addressContainsEmailToMms(conv, msgTxt)) {      14.         // Make local copies of the bits we need for sending a message,      15.         // because we will be doing it off of the main thread, which will      16.         // immediately continue on to resetting some of this state.      17.         final Uri mmsUri = mMessageUri;      18.         final PduPersister persister = PduPersister      19.                 .getPduPersister(mContext);      20.       21.         final SlideshowModel slideshow = mSlideshow;      22.         final SendReq sendReq = makeSendReq(conv, mSubject);      23.       24.         // Make sure the text in slide 0 is no longer holding onto a      25.         // reference to the text      26.         // in the message text box.      27.         slideshow.prepareForSend();      28.       29.         // Do the dirty work of sending the message off of the main UI      30.         // thread.      31.         new Thread(new Runnable() {      32.             public void run() {      33.                 sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq);      34.             }      35.         }).start();      36.     } else {      37.         // Same rules apply as above.      38.         final String msgText = mText.toString();      39.         new Thread(new Runnable() {      40.             public void run() {      41.                 sendSmsWorker(conv, msgText);      42.             }      43.         }).start();      44.     }      45.       46.     // update the Recipient cache with the new to address, if it's different      47.     RecipientIdCache      48.             .updateNumbers(conv.getThreadId(), conv.getRecipients());      49.       50.     // Mark the message as discarded because it is "off the market" after      51.     // being sent.      52.     mDiscarded = true;      53. }      粗浅的解说一下, (1) prapareForSave. 先确保有slidshow,也就是实质内容。 确保文字已拷贝。确保标题。 (2a) 根据消息分类,如果是短信直接起一个线程,跑sendSmsWorker函数,发送短信 (2b) 如果是彩信,先跑这么个函数,确保文本信息             // Make sure the text in slide 0 is no longer holding onto a  // reference to the text      // in the message text box.             slideshow.prepareForSend(); TheCranberriers(卡百利)的歌真好听。 然后起一个线程,单独跑sendMmsWorker函数,后文有介绍。 彩信比sms麻烦很多。从sendMmsWorker函数的参数就可以看出来:(conv, mmsUri, persister, slideshow, sendReq) 上下文,uri,PduPersister(彩信是用pdu的),slideshow包含了所有的彩信信息,sendreq包含了mime封装mms时的headers(在我的剥壳彩信2里面有提到)。包括了 ContentType("application/vnd.wap.multipart.related" ,from,to等信息 。 (3)。 不管是短信还是彩信,起了那俩个worker函数之一就算发送信息成功了。 最后修改Recipient cache, 重置标志位,过程就结束了。 2。函数 sendMmsWorker  Java代码 复制到剪贴板  Java代码 1. private void sendMmsWorker(Conversation conv, Uri mmsUri,      2.         PduPersister persister, SlideshowModel slideshow, SendReq sendReq) {      3.     // First make sure we don't have too many outstanding unsent message.      4.     Cursor cursor = null;      5.     try {      6.         Log.d("GN@@@","mContext:  "+mContext.toString());      7.         Log.d("GN@@@","mContentResolver:  "+mContentResolver.toString());      8.         Log.d("GN@@@","Mms.Outbox.CONTENT_URI:  "+Mms.Outbox.CONTENT_URI.toString());      9.               10.         cursor = SqliteWrapper.query(mContext, mContentResolver,      11.                 Mms.Outbox.CONTENT_URI, MMS_OUTBOX_PROJECTION, null, null,      12.                 null);      13.         if (cursor != null) {      14.             long maxMessageSize = MmsConfig      15.                     .getMaxSizeScaleForPendingMmsAllowed()      16.                     * MmsConfig.getMaxMessageSize();      17.             long totalPendingSize = 0;      18.             while (cursor.moveToNext()) {      19.                 totalPendingSize += cursor.getLong(MMS_MESSAGE_SIZE_INDEX);      20.             }      21.             if (totalPendingSize >= maxMessageSize) {      22.                 unDiscard(); // it wasn't successfully sent. Allow it to be      23.                              // saved as a draft.      24.                 mStatusListener.onMaxPendingMessagesReached();      25.                 return;      26.             }      27.         }      28.     } finally {      29.         if (cursor != null) {      30.             cursor.close();      31.         }      32.     }      33.     mStatusListener.onPreMessageSent();      34.       35.     // Make sure we are still using the correct thread ID for our      36.     // recipient set.      37.     long threadId = conv.ensureThreadId();      38.       39.     if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {      40.         LogTag.debug("sendMmsWorker: update draft MMS message " + mmsUri);      41.     }      42.       43.     if (mmsUri == null) {      44.         // Create a new MMS message if one hasn't been made yet.      45.         mmsUri = createDraftMmsMessage(persister, sendReq, slideshow);      46.     } else {      47.         // Otherwise, sync the MMS message in progress to disk.      48.         updateDraftMmsMessage(mmsUri, persister, slideshow, sendReq);      49.     }      50.       51.     // Be paranoid and clean any draft SMS up.      52.     deleteDraftSmsMessage(threadId);      53.       54.     MessageSender sender = new MmsMessageSender(mContext, mmsUri, slideshow      55.             .getCurrentMessageSize());      56.     try {      57.         if (!sender.sendMessage(threadId)) {      58.             // The message was sent through SMS protocol, we should      59.             // delete the copy which was previously saved in MMS drafts.      60.             SqliteWrapper.delete(mContext, mContentResolver, mmsUri, null,      61.                     null);      62.         }      63.       64.         // Make sure this thread isn't over the limits in message count      65.         Recycler.getMmsRecycler().deleteOldMessagesByThreadId(mContext,      66.                 threadId);      67.     } catch (Exception e) {      68.         Log.e(TAG, "Failed to send message: " + mmsUri + ", threadId="      69.                 + threadId, e);      70.     }      71.       72.     mStatusListener.onMessageSent();      73. }      依旧是粗浅的解说: a )前面挺长一段代码,检查这个对话(conversation)之前还有没有未发送的信息,uri是Mms.Outbox.CONTENT_URI。 这里需要提到一下MessageStatusListener,这个Interface接口实现在WorkingMessage.java里,而短信类的主题ComposeMessageActivity.java实现了这个接口,所以前者在一些状态改变的时候可以很方便的调用后者的一些函数,作相应的改动。主要是:onProtocolChanged彩信短信互切换,onAttachmentChanged福建改变,onPreMessageSent发消息前,onMessageSent发消息后。 b) 当然,这里调用了onPreMessageSent这个监听函数, 然后ComposeMessageActivity 就会调用resetMessage函数 ,这个函数会调整显示,focus,软键盘等等。 c) 然后检查mmsUri。如果这个uri是空的话,直接造一个新的uri继续发送。这个真是让我叫亚灭爹。因为一开始不知道 这个createDraftMmsMessage(persister, sendReq, slideshow);函数可以包含所有发送需要的信息,以为这么发出去太可怕了。 如果uri不为空。 调用的是updateDraftMmsMessage(mmsUri, persister, slideshow, sendReq); 总之功能是,把这个将发送的mms,存disk了,也就是存draft了。为什么要发送还要存draft呢,后面另会说,因为这个是我写这个文章前想要找的东西。。。这个过程还有一些信息写道mmsUri了。所以之后mmsUri就可以代表将发送的mms的全部信息。 d)deleteDraftSmsMessage 删除草稿 e)创建一个MmsMessageSender,用这个sender来调用sendMessage函数 可以猜到的,Sms那边是SmsMessageSender,同样调用sendMessage函数 通过这里之后,短信已经真的发掉了。 这个类后面有介绍。 f)这里这个if相当搞笑,按正常下来,按理这里本来这里是一个彩信的发送,然后有一些数据在draft数据库,会在上面的流程中被移到send数据库。 但是搞笑的地方来了:因为忽然发现函数返回值表示刚刚发送出去的其实是一个短信sms,而已。于是要把数据库里存着的draft删掉。 我也不知道这个if里面的情况会不会发生,反正源码是这么写的,我只管不负责任直译。。。 g)调用onMessageSent这个监听函数。调用ComposeMessageActivity的onMessageSent,这个函数功能是重新显示conversation list。 3 MmsMessageSender.java类。在mms/transaction下面。实现了MessageSender接口。这个接口只有一个事儿,就是sendMessage并返回boolean的值。弱发送的是mms,返回true。若发送的是sms,返回false。出错返回啥?exception。 我最先想要追踪的发送流程也在这里了。贴一些代码 Java代码 复制到剪贴板  Java代码 1. public MmsMessageSender(Context context, Uri location, long messageSize) {      2.     mContext = context;      3.     mMessageUri = location;      4.     mMessageSize = messageSize;      5.           6.     if (mMessageUri == null) {      7.         throw new IllegalArgumentException("Null message URI.");      8.     }      9. }      10.    11.    12. Java代码     13. public boolean sendMessage(long token) throws MmsException {      14.     // Load the MMS from the message uri      15.     PduPersister p = PduPersister.getPduPersister(mContext);      16.     GenericPdu pdu = p.load(mMessageUri);      17.       18.     if (pdu.getMessageType() != PduHeaders.MESSAGE_TYPE_SEND_REQ) {      19.         throw new MmsException("Invalid message: " + pdu.getMessageType());      20.     }      21.       22.     SendReq sendReq = (SendReq) pdu;      23.       24.     // Update headers.      25.     updatePreferencesHeaders(sendReq);      26.       27.     // MessageClass.      28.     sendReq.setMessageClass(DEFAULT_MESSAGE_CLASS.getBytes());      29.       30.     // Update the 'date' field of the message before sending it.      31.     sendReq.setDate(System.currentTimeMillis() / 1000L);      32.       33.     sendReq.setMessageSize(mMessageSize);      34.       35.     p.updateHeaders(mMessageUri, sendReq);      36.       37.     // Move the message into MMS Outbox      38.     p.move(mMessageUri, Mms.Outbox.CONTENT_URI);      39.       40.     // Start MMS transaction service      41.     SendingProgressTokenManager      42.             .put(ContentUris.parseId(mMessageUri), token);      43.     mContext.startService(new Intent(mContext, TransactionService.class));      44.       45.     return true;      46. }      47.    解说: 现从PduPersister那里拿数据,包括需要拼装的发送报头和需要发送的数据信息。 然后把要发送的信息相关数据从数据库的draft那里转移到send,表示已经发送。 最后起一个TransactionService服务,这个服务也是从PduPersister里找,找到需要发送的数据,并通过不同的用户网络送出去。 这块我猜一般人都没有改的需求。。 4.   createDraftMmsMessage(persister, sendReq, slideshow); 和 updateDraftMmsMessage(mmsUri, persister, slideshow, sendReq); 这两个函数 刨掉 try catch , createDraftMmsMessage 函数大概有这么几句: 复制到剪贴板  Java代码 1. Java代码     2. PduBody pb = slideshow.toPduBody();      3. sendReq.setBody(pb);      4. Uri res = persister.persist(sendReq, Mms.Draft.CONTENT_URI);      5. slideshow.sync(pb);      6.    7. updateDraftMmsMessage 函数大概有这么几句:     8. Java代码     9. persister.updateHeaders(uri, sendReq);      10. final PduBody pb = slideshow.toPduBody();      11. persister.updateParts(uri, pb);      12. slideshow.sync(pb);      13.    两个函数从本质上讲是一样的:把附件的东西以pdubody的形式存下来,另外就是更新uri。 什么叫PduBody呢? 厉害了。就是n个PduPart。什么叫PduPart呢?厉害了,就是数据库里的那个Part! 那个part是什么? 那个最厉害了。数据库里的PART_1234455这种数据,文件名代表创建时间(在mediaModel产生时就进系统了),导出来就是源文件,比如图片文件,改个jpg就可以看了。 sync函数不怎么动,无责任解说:把每个slide里面每个媒体跟真实文件位置对应上。 slideshow.toPduBody();里面,用SMILDocument mDocumentCache; 调用到SlideshowModel.java的 Java代码 复制到剪贴板  Java代码 1. //其中context=null。 isMakingCopy=false。 document=mDocumentCache      2.     private PduBody makePduBody(Context context, SMILDocument document,      3.             boolean isMakingCopy) {      4.         PduBody pb = new PduBody();      5.       6.         boolean hasForwardLock = false;      7.         for (SlideModel slide : mSlides) {      8.             for (MediaModel media : slide) {      9.                 if (isMakingCopy) {      10.                     if (media.isDrmProtected() && !media.isAllowedToForward()) {      11.                         hasForwardLock = true;      12.                         continue;      13.                     }      14.                 }      15.       16.                 PduPart part = new PduPart();      17.       18.                 if (media.isText()) {      19.                     TextModel text = (TextModel) media;      20.                     // Don't create empty text part.      21.                     if (TextUtils.isEmpty(text.getText())) {      22.                         continue;      23.                     }      24.                     // Set Charset if it's a text media.      25.                     part.setCharset(text.getCharset());      26.                 }      27.       28.                 // Set Content-Type.      29.                 part.setContentType(media.getContentType().getBytes());      30.       31.                 String src = media.getSrc();      32.                 String location;      33.                 boolean startWithContentId = src.startsWith("cid:");      34.                 if (startWithContentId) {      35.                     location = src.substring("cid:".length());      36.                 } else {      37.                     location = src;      38.                 }      39.       40.                 // Set Content-Location.      41.                 part.setContentLocation(location.getBytes());      42.       43.                 // Set Content-Id.      44.                 if (startWithContentId) {      45.                     // Keep the original Content-Id.      46.                     part.setContentId(location.getBytes());      47.                 } else {      48.                     int index = location.lastIndexOf(".");      49.                     String contentId = (index == -1) ? location : location      50.                             .substring(0, index);      51.                     part.setContentId(contentId.getBytes());      52.                 }      53.       54.                 if (media.isDrmProtected()) {      55.                     DrmWrapper wrapper = media.getDrmObject();      56.                     part.setDataUri(wrapper.getOriginalUri());      57.                     part.setData(wrapper.getOriginalData());      58.                 } else if (media.isText()) {      59.                     part.setData(((TextModel) media).getText().getBytes());      60.                 } else if (media.isImage() || media.isVideo()      61.                         || media.isAudio()) {      62.                     part.setDataUri(media.getUri());      63.                 } else {      64.                     Log.w(TAG, "Unsupport media: " + media);      65.                 }      66.       67.                 pb.addPart(part);      68.             }      69.         }      70.       71.         if (hasForwardLock && isMakingCopy && context != null) {      72.             Toast.makeText(context,      73.                     context.getString(R.string.cannot_forward_drm_obj),      74.                     Toast.LENGTH_LONG).show();      75.             document = SmilHelper.getDocument(pb);      76.         }      77.       78.         // Create and insert SMIL part(as the first part) into the PduBody.      79.         ByteArrayOutputStream out = new ByteArrayOutputStream();      80.         SmilXmlSerializer.serialize(document, out);      81.         PduPart smilPart = new PduPart();      82.         smilPart.setContentId("smil".getBytes());      83.         smilPart.setContentLocation("smil.xml".getBytes());      84.         smilPart.setContentType(ContentType.APP_SMIL.getBytes());      85.         smilPart.setData(out.toByteArray());      86.         pb.addPart(0, smilPart);      87.       88.         return pb;      89.     }     
/
本文档为【51CTO下载-Android彩信发送介绍】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索