当前位置: 编程技术>移动开发
本页文章导读:
▪彩信发送 彩信发送。
这篇写彩信发送过程。 我想追踪的内容是:用户按下发送之后,彩信的图片阿数据阿文件阿,是怎么包装起来,最后发送出去。按我看源码的先后顺序来写了。 写完可能最后.........
▪ 计算两点的距离 经典网页以及失去内存信息 计算两点的距离 经典网页以及得到内存信息
http://www.movable-type.co.uk/scripts/latlong.html 这个网站可以计算两点距离 也可以自动生成距离相当好
ActivityManager activityManager = = (ActivityManager) getSystem.........
▪ wap 的selected 有关问题 wap 的selected 问题
用ivalue="1";<select name="store_id" id="store_id" ivalue="1"><option value="1" >全部</option><% for(int i=0; i< rsos.getRowCount(); i++){ %><option value="<%=rsos.getString(i,"id")%>.........
[1]彩信发送
来源: 互联网 发布时间: 2014-02-18
彩信发送。
这篇写彩信发送过程。
我想追踪的内容是:用户按下发送之后,彩信的图片阿数据阿文件阿,是怎么包装起来,最后发送出去。
按我看源码的先后顺序来写了。 写完可能最后整理下。
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的源码
粗浅的解说一下,
(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
依旧是粗浅的解说:
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。
我最先想要追踪的发送流程也在这里了。贴一些代码
解说:
现从PduPersister那里拿数据,包括需要拼装的发送报头和需要发送的数据信息。
然后把要发送的信息相关数据从数据库的draft那里转移到send,表示已经发送。
最后起一个TransactionService服务,这个服务也是从PduPersister里找,找到需要发送的数据,并通过不同的用户网络送出去。
这块我猜一般人都没有改的需求。。
4.
createDraftMmsMessage(persister, sendReq, slideshow); 和
updateDraftMmsMessage(mmsUri, persister, slideshow, sendReq); 这两个函数
刨掉 try catch , createDraftMmsMessage 函数大概有这么几句:
updateDraftMmsMessage 函数大概有这么几句:
两个函数从本质上讲是一样的:把附件的东西以pdubody的形式存下来,另外就是更新uri。
什么叫PduBody呢? 厉害了。就是n个PduPart。什么叫PduPart呢?厉害了,就是数据库里的那个Part! 那个part是什么?
那个最厉害了。数据库里的PART_1234455这种数据,文件名代表创建时间(在mediaModel产生时就进系统了),导出来就是源文件,比如图片文件,改个jpg就可以看了。
sync函数不怎么动,无责任解说:把每个slide里面每个媒体跟真实文件位置对应上。
slideshow.toPduBody();里面,用SMILDocument mDocumentCache;
调用到SlideshowModel.java的
好了,齐活儿了
顺序有点乱。抱歉。。。
这篇写彩信发送过程。
我想追踪的内容是:用户按下发送之后,彩信的图片阿数据阿文件阿,是怎么包装起来,最后发送出去。
按我看源码的先后顺序来写了。 写完可能最后整理下。
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; }
粗浅的解说一下,
(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
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(); }
依旧是粗浅的解说:
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。
我最先想要追踪的发送流程也在这里了。贴一些代码
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; }
解说:
现从PduPersister那里拿数据,包括需要拼装的发送报头和需要发送的数据信息。
然后把要发送的信息相关数据从数据库的draft那里转移到send,表示已经发送。
最后起一个TransactionService服务,这个服务也是从PduPersister里找,找到需要发送的数据,并通过不同的用户网络送出去。
这块我猜一般人都没有改的需求。。
4.
createDraftMmsMessage(persister, sendReq, slideshow); 和
updateDraftMmsMessage(mmsUri, persister, slideshow, sendReq); 这两个函数
刨掉 try catch , createDraftMmsMessage 函数大概有这么几句:
PduBody pb = slideshow.toPduBody(); sendReq.setBody(pb); Uri res = persister.persist(sendReq, Mms.Draft.CONTENT_URI); slideshow.sync(pb);
updateDraftMmsMessage 函数大概有这么几句:
persister.updateHeaders(uri, sendReq); final PduBody pb = slideshow.toPduBody(); persister.updateParts(uri, pb); slideshow.sync(pb);
两个函数从本质上讲是一样的:把附件的东西以pdubody的形式存下来,另外就是更新uri。
什么叫PduBody呢? 厉害了。就是n个PduPart。什么叫PduPart呢?厉害了,就是数据库里的那个Part! 那个part是什么?
那个最厉害了。数据库里的PART_1234455这种数据,文件名代表创建时间(在mediaModel产生时就进系统了),导出来就是源文件,比如图片文件,改个jpg就可以看了。
sync函数不怎么动,无责任解说:把每个slide里面每个媒体跟真实文件位置对应上。
slideshow.toPduBody();里面,用SMILDocument mDocumentCache;
调用到SlideshowModel.java的
//其中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; }
好了,齐活儿了
顺序有点乱。抱歉。。。
1 楼
sjl599
2010-04-28
有没有彩信接收的说明啊
2 楼
atmus
2011-07-07
横竖看不懂
3 楼
suifeng0211
2011-07-10
如果想不调用系统彩信界面,直接从后台发送,就比较麻烦了。
但确定肯定是可以实现的,网上找到下面这个地址,就实现了,有兴趣的同学可以研究一下
http://www.huake-tech.com/MmsSend.html
但确定肯定是可以实现的,网上找到下面这个地址,就实现了,有兴趣的同学可以研究一下
http://www.huake-tech.com/MmsSend.html
[2] 计算两点的距离 经典网页以及失去内存信息
来源: 互联网 发布时间: 2014-02-18
计算两点的距离 经典网页以及得到内存信息
http://www.movable-type.co.uk/scripts/latlong.html 这个网站可以计算两点距离 也可以自动生成距离相当好
ActivityManager activityManager = = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
Log.i("memory free", "" + mi.availMem);
[3] wap 的selected 有关问题
来源: 互联网 发布时间: 2014-02-18
wap 的selected 问题
用ivalue="1";
<select name="store_id" id="store_id" ivalue="1">
<option value="1" >全部</option>
<% for(int i=0; i< rsos.getRowCount(); i++){ %>
<option value="<%=rsos.getString(i,"id")%>"><%=rsos.getString(i,"sort_name") %></option>
<%} %>
</select>
用ivalue="1";
<select name="store_id" id="store_id" ivalue="1">
<option value="1" >全部</option>
<% for(int i=0; i< rsos.getRowCount(); i++){ %>
<option value="<%=rsos.getString(i,"id")%>"><%=rsos.getString(i,"sort_name") %></option>
<%} %>
</select>
最新技术文章: