Android2.2源码信息模块小结

Android2.2源码信息模块总结
    Android是Google一个开放源代码的手机操作系统,既然是手机,那么不管它有多么智能它最重要的两个功能当然是打电话和发短信了。我用了将近一个月的时间看了信息模块,这是一个庞大的模块,要将其完全弄清楚还是需要很长一段时间。在看源码的过程中我也遇到不少的问题,但是在源码里我学到了很多东西也拓展了我的思维。
拿到源码当然是先编译了,编译也是一个漫长的过程足足等了一个小时。既然要学信息模块,当然要先会玩信息了,于是我在模拟器上熟悉了信息的各个界面,菜单,以及发送接收信息的操作。一切准备工作做好后,就正式开始学习源码了。
   在manifest.xml找这个模块的主Activity也就是进入短信的一个界面。这个Activity叫ConversationList继承自ListActivity。ConversationList的每个列表代表一个会话,这个列表是通过AsyncQueryHandler查询mmssms.db数据库中的threads表的数据用CursorAdapter将数据显示出来。其中有查看联系人,查看会话,删除会话等操作。另外该类中的runOneTimeStorageLimitCheckForLegacyMessages方法用于检测存储空间限制。点击一项ListIte或者是ContextMenu传入threadId通过这个Id来和AsyncQueryHandler来查询数据库中这个会话的所有信息,利用CursorAdapter显示布局到ComposeMessageActivity的message_list_item上。
    ComposeMessageActivity是一个很庞大的类,每个ComposeMessageActivity 录属于一个Conversation或者不属于任何conversation(无收件人草稿);每个converation由独立的threadId来相互区分 ,每个ComposeMessageActivity有一个WorkingMessage是唯一的,表示在这个thread下,用户编辑的短信草稿。ComposeMessageActivity和ConversationList的launch mode都是singleTop,利用Observer监听,一旦有短心到来或者是发送,都将AsyncQueryHandler查询数据库并且将需要的内容显示在界面上。我们来看这个Activity的初始化过程,ComposeMessageActivity的onSaveInstanceState()函数中,会保存一份联系人,同时保存workingMessage的subject标题/body正文/uri草稿在数据库中的位置 :
public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("recipients",getRecipients().serialize());
        mWorkingMessage.writeStateToBundle(outState);
        if (mExitOnSent) {
            outState.putBoolean("exit_on_sent", mExitOnSent);
        }
    }
WorkingMessage中的代码片段:
public void writeStateToBundle(Bundle bundle) {
        if (hasSubject()) {
            bundle.putString("subject", mSubject.toString());
        }
        if (mMessageUri != null) {
            bundle.putParcelable("msg_uri", mMessageUri);
        } else if (hasText()) {
            bundle.putString("sms_body", mText.toString());
        }
    }
这样当我们离开后再回到这个Activity时调用initActivityState,如果我们之前保存了联系人,则会从旧有联系人里面读取出来,联系人相互之间用“;”分割开 。 workingmessage也由之前保存的变量初始化,这个初始化就基本完成了。如果没有保存,则从传入的intent中读取thread_id值,进而得到初始化需要的信息:如果thread_id>0 ;那么mConversation从Conversation的cache中,有thread_id取得;如果thread_id<=0,那么从intent的Data获得uri;再不行,就说明之前没有过这个thread了,可能我们是手写的地址,就从address去产生一个ContactList,从ContactList去Conversation的Cache里匹配得到相应的Conversation,这时如果匹配还没有得到Conversation的话,就会通过getOrCreateThreadId(Context context, ContactList list)来获得一个threadId再通过new Conversation(Context context, long threadId, boolean allowQuery)来创建一个Conversation ,然后Cache偷偷将这个Conversation存放起来,适用于你这个状况;如果联系人也是空的,那么直接产生一个新的Conversation; 这个Conversation是廉价的,因为他没有thread_id,不被放入cache,在使用ensurethreadid之前,他可以创建无数个,可以随意调用创建出来。
有了conversation之后,就可以initMessageList,查询显示出这个thread下面的所有消息。ComposeMessageActivity还继承了MessageStatusListener接口——对信息状态的监听,这个接口中有很多未实现的方法:onProtocolChanged(boolean mms),onAttachmentChanged(),onPreMessageSent(),onMessageSent(),onMaxPendingMessagesReached(),onAttachmentError(int error);这些方法也能从字面含义上判断其作用,尤其是 onProtocolChanged这个它能判断是否为彩信还短信。
    ForwardMessageActivity,它是ComposeMessageActivity的别名,用于转发消息的Activity将一条现有的消息的内容相当于复制到一个新的ComposeMessageActivity中。DeliveryReportActivity,用于报告消息状态的Activity它采用了对话框风格的主题(android:theme="@android:style/Theme.Dialog")。WarnOfStorageLimitsActivity,告知用户关于存储空间限制的设置信息。 ConfirmRateLimitActivity,发送多条彩信时向用户提示确认的界面,在用户超过一段时间未作出响应时自动取消发送的操作。ManageSimMessages,用于管理Sim卡中短消息的界面,它以列表的形式显示了存储在SIM卡中的短消息,并允许用户将信息转存到手机内存中,或者删除消息。 MessagingPreferenceActivity 这是Messaging应用的系统配置界面,其中有针对SMS、MMS、存储限制等配置属性,以及管理存储在SIM卡中的短信消息。该Activity启动时会检查当前是否有SIM,以及是否支持MMS来动态调整配置项列表。SearchActivity,Android通过系统服务Context. SEARCH_SERVICE(即SearchManager类)提供了强大的信息搜索功能。在该应用中通过对联系人(或者电话号码)、主题等信息的匹配来搜索信息,并将结果显示在一个列表中。 SlideshowEditActivity,这个Activity对幻灯片的张数,位置的设定。SlideEditorActivity,用于编辑幻灯片内容的操作界面,它提供了:添加、移除 、预览文本/图片/音乐,以及Slide等功能。SlideshowActivity,用于播放Slide幻灯片的界面,它会在全屏状态下显示幻灯片的内容。EditSlideDurationActivity,用于修改Slide幻灯片持续显示时间的操作界面,默认持续显示时间是5秒。ClassZeroActivity,直接显示用户屏幕上并等待用户操作的0类信息(没见过)。
      包com.android.mms中有个类叫做MmsAPP继承了Application,在其onCreate方法里调用这样一些方法:MmsConfig.init(this);        Contact.init(this);DraftCache.init(this);Conversation.init(this);
DownloadManager.init(this);RateController.init(this);       DrmUtils.cleanupStorage(this); LayoutManager.init(this);       SmileyParser.init(this);MessagingNotification.init(this);这些初始化方法在程序运行的效率上提供了大大的方便。在包com.android.mms.transation中包含短信的接收,发送,状态以及通知等,其中包含很多服务和广播。
   看完这个模块我自己也试着写了ConversationList和ComposeMessageActivity,为了测试这两个界面是否可用,我开始是用了Map和List这两个容器来模拟数据库的信息,
在这个过程还是遇到了不少的问题,比如像Adapter的选用,我选用BaseAdpter,这和CursorAdaptere还是有很大的区别的;还有怎么让Conversation和它包含的信息联系起来。在测试好之后,要将数据变成活的数据,也就是需要读取数据库中的信息。由于在An
droid将某些类屏蔽了,所以读取数据库不能用源码中的SqliteWrapper.query(Context
context, ContentResolver resolver, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder),这就要用到ContentProvider了来实现了getContentResolver().query(Uri,String[], String, String[], String), Uri也要自己从源码中找到最原始的(形如:content://mms/),还有涉及到权限问题android.permission.READ_SMS,当然Adapter也要换成相应的CursorAdapter了。


Mmssms.db中常用表的Uri:
   threads(会话)表:content://mms-sms/conversations
   每个会话中所有的信息:content://mms-sms/conversations/threadId(这个会话的id)
   canonical_addresses(接收者)表:content://mms-mms/canonical-addresses
   草稿:content://mms-sms/draft
   锁:content://mms-sms/locked
   pud(彩信):content://mms
   part(附件文件)表:content://mms/part
   sms(短信):content://sms