接下来的分析先从MMS中四大组件(Activity ,BroadCastReceiver,Service,ContentProvider),也是MMS中最核心的部分入手:
一. Activity
1、ConversationList 对话列表界面,这是进入应用程序的主界面。它有两个配置属性android:configChanges="orientation|keyboardHidden":在Android系统中,当程序所运行的环境(如:屏幕方向、键盘状态、字体等级,等等 )发生变化后 会导致Activity被重新启动(以适应环境变化 ),然而 Activity也可以宣称自己来应付某些变化(而不是全部让系统重启自己 ), configChanges 属性正是用于指定自己愿意应付的变化情况。此处该属性有两个值,orientation代表屏幕方向发生改变,keyboardHidden表示键盘可访问状态发生变化(即键盘弹出/收起 ),这意味着当屏幕方向和键盘可用状态发生变化时,Activity不会被重新启动,而是调用其onConfigurationChanged方法,通常是在该方法中对自己做出调整,以适应变化;launchMode="singleTop":该属性指示了Activity的加载模式,这与Activity在不同Task之间的重用有关,该属性共有4个可用选项standard, singleTop,singleTask,singleInstance,它们将与Intent中的FLAG_ACTIVITY_* 标记 常量 协同产生相关作用。 ConversationList类中定义了程序中涉及到的选项菜单、会话项上的上下文菜单等UI元素。另外该类中的runOneTimeStorageLimitCheckForLegacyMessages方法用于检测存储空间限制。
2、ComposeMessageActivity创建新消息的用户界面,通过选项菜单menu_compose_new会调用到该界面。这是个很庞大的类内部实现也很复杂,后面Mms入口部分会详细介绍。
3、ForwardMessageActivity用于转发消息的Activity,这是ComposeMessageActivity的别名,用于把一条现有消息的内容带到创建消息的界面上;
4、DeliveryReportActivity投递报告 Activity, 用于报告消息的投递状态,采用对话框风格的主题(android:theme="@android:style/Theme.Dialog)。
5、WarnOfStorageLimitsActivity存储空间限制警告,用于告知用户关于存储空间限制的设置信息。
6. ConfirmRateLimitActivity 发送多条彩信时向用户提示确认的界面,它包括了自动应答操作——即用户超过一段时间未作出响应时自动取消发送。
7、ClassZeroActivity ,ClassZero是一种特殊的短消息类型,它会直接显示在用户屏幕上并等待用户操作。ClassZeroActivity正是用来显示此类型的短信消息,并运行用户将信息保存起来。
8、MessagingPreferenceActivity 这是Mms应用的系统配置界面,其中有针对SMS、MMS、存储限制等配置属性,以及管理存储在 SIM卡中的短信消息。该Activity启动时会检查当前是否有SIM,以及是否支持MMS来动态调整配置项列表。
9、ManageSimMessages 用于管理Sim卡(手机是单卡)中短消息的界面,它以列表的形式显示了存储在SIM卡中的短消息,并允许用户将信息转存到手机内存中,或者删除消息。
10、SearchActivity 用于信息搜索的操作界面。Android通过系统服务Context. SEARCH_SERVICE(即SearchManager类)提供了强大的信息搜索功能。在该应用中通过对联系人(或者电话号码)、主题等信息的匹配来搜索信息,并将结果显示在一个列表中。
11、SlideshowEditActivity 所谓Slide是指MMS中的一页内容 即一帧,通常被称为幻灯片。 SlideshowEditActivity是彩信中所有内容(即多个Slide)的列表,用户可以选定列表项进入Slide播放/修改界面。
12、SlideshowActivity 用于播放Slide幻灯片的界面,它会在全屏状态下显示幻灯片的内容。
13、SlideEditorActivity 用于编辑Slide幻灯片内容的操作界面,它提供了添加、移除 文本/图片/音乐,以及Slide等功能。
14、EditSlideDurationActivity 用于修改Slide幻灯片持续显示时间 的操作界面 ,默认持续显示时间是5秒。
15、MultiSelectCntsListActivity 群发信息时,列出联系人列表。
16、CBConversationListActivity列出广播消息
17、CBMessageListActivity 查看单个广播消息
18、WPMessageActivity用于查看收到的wappush信息。
19、MmsShowActivity用于在收到彩信时,显示彩信中包含图片,录像,幻灯片等特殊格式的彩信。
20、SimMessagesTab用于双Sim卡中短消息的界面,以列表的形式显示在双SIM卡中的短消息。
21、ManageSim2Messages用于管理有Sim卡(手机是双卡)中短消息的界面,允许用户将信息转存到手机内存中,或者删除消息。
二. Receiver
在Mms应用中一共有11个Receiver:
1、SmsReceiver 短消息广播接收器,它负责处理与收到短消息相关的广播事件。触发该接收器运行的intent有两个:
A.android.intent.action.BOOT_COMPLETED Android系统启动完成时会发出该广播,即SmsReceiver会在系统启动完成时接收到调用。
B.com.android.mms.transaction.MESSAGE_SENT 该常量的定义在 SmsReceiverService.java中,被用在 SmsSingleRecipientSender. sendMultipartTextMessageGemini方法中——即短消息发送后触发的广播事件。完全和预想的一样,在SmsReceiver中会启动SmsReceiverService,启动代码在beginStartingService方法里。值得注意的是它同时还做了“屏幕唤醒锁定 (WakeLock)” 操作,最终在service启动完成后,通过回调用finishStartingService方法,解除了屏幕唤醒锁定。
2、PrivilegedSmsReceiver 该接收器是SmsReceiver的子类,唯一的区别在于该Receiver的permission增加了android.permission.BROADCAST_SMS。
3、MmsSystemEventReceiver Mms系统事件接收器,它负责在收到新消息时向通知区域(即标题栏)显示小图标,以及重新发送在发件箱中的短信。触发该接收器运行的两个Intent是:
A. android.intent.action.BOOT_COMPLETED 与SmsReceiver中的情况相同;
B. android.intent.action.CONTENT_CHANGED 连接方式改变时系统会发出该广播,即在连接方式变化,例如从gprs-->wifi时该接收器将被调用;
在MmsSystemEventReceiver类中,程序一旦获得数据连接时就会启动TransactionService服务;当连接方式改变时还会调用PduCache.purge()方法清理缓存;还有当系统刚刚启动时会同步通知区域的图标、未读消息个数等信息。
4、PushReceiver WAP_PUSH 事件的广播接收器,该事件发生时代表手机收到了一条新的WAP PUSH message。该接收器被调用后,首先唤醒手机屏幕5秒钟,然后在一个后台线程中处理push-data,将消息数据插入到数据库中,必要时启动 TransactionService服务以更新通知信息 。触发该接收器运行的 Intent是: (intent.action=android.provider.Telephony.WAP_PUSH_RECEIVED, data=application/vnd.wap.mms-message),其中Action.Name定义在android.provider.Telephony类中。值得注意的是该Receiver有申明权限:android.permission.BROADCAST_WAP_PUSH,这意味着发出该广播时必须携带该授权,否则本 Receiver将不会被触发执行。
5、MessageStatusReceiver 消息状态改变时的广播接收器,消息状态改变是指消息的投递状态(即:是否成功送达、是否被目标用户阅读等)的变化,触发该接收器的Intent是com.android.mms.transaction.MessageStatusReceiver. MESSAGE_STATUS_RECEIVED,该值是申明在MessageStatusReceiver.java文件中的常量。该广播事件是在SmsSingleRecipientSender. sendMultipartTextMessageGemini方法中被发出的,收到广播事件后,Receiver的会做两件事情:
A. 取得pdu数据包 更新消息状态(在updateMessageStatus方法中);
B. 更新通知区域的新消息指示信息(在MessagingNotification类的blockingUpdateNewMessageIndicator()方法中)。
6、SimFullReceiver Sim卡短信存储空间满的事件通知,当系统发现Sim卡中存储短信的空间耗尽时会发出该广播事件。该接收器完成的工作是在通知区域显示相关信息,点击通知信息后,可以进入管理Sim卡中短消息的Activity界面 。
7、SmsRejectedReceiver 短消息被拒绝时的事件接收器,当手机的存储空间不足时会拒绝接收新的短消息,当该事件发生时SmsRejectedReceiver被调用,它会检查确认是否是存储空间不足,然后在通知区域显示相关通知信息。
8、BootupReceiver 系统启动时候响应,并调用QuerySimContactsService将SIM中的联系人记录插入到Mms应用下的simcontacts.db数据库中。
9、CBMessageReceiver 用于响应广播消息。
10、WapPushReceiver 是wappush事件的广播接收器,唤醒系统并分发各种数据格式的wappush信息。会启动WapPushReceiverService,启动代码在beginStartingService方法里。值得注意的是它同时还做了“屏幕唤醒锁定 (WakeLock)” 操作,最终在service启动完成后,通过回调用finishStartingService方法,解除了屏幕唤醒锁定。
11、WapPushTimeChangedReceiver 处理设定的时间改变或者网络连接状态发生改变时候响应该广播信息。
三. Service
在Mms应用中一共有5个Service,他们分别是:SmsReceiverService、TransactionService、WapPushReceiverService、CBMessageReceiverService和QuerySimContactsService。
SmsReceiverService是短消息(SMS)的接收器,两者都会响应来自通讯网络的通知并收取信息;TransactionService负责处理与彩信(MMS)相关的网络业务;WapPushReceiverService负责处理推送的信息。它们只用于本应用内部(因为其未声明任何intent-filter),上文介绍的广播接收器中有显式启动它们的代码。以下我们将分别分析前两个Service的基本实现。
1、SmsReceiverService 被创建时首先初始化了一个新的工作线程(HandlerThread对象)用来在后台完成相关动作,紧接着在onStartCommand方法里会将具体的任务通过消息(即调用service的Intent)发送给工作线程进行处理。根据Intent.Action的名称,工作线程会处理5种情况:
A. ACTION_BOOT_COMPLETE:系统启动完成后BOOT_COMPLETED,把发件箱(outbox)中的消息移动到发送队列(QueuedBox),然后开始发送队列中的消息,最后调用blockingUpdateNewMessageIndicator()方法更新状态栏消息指示图标;
B. SMS_RECEIVED_ACTION:处理Sms接收handleSmsReceived,从Intent中取得消息对象,直接显示给用户并保持到数据库中。
C. MESSAGE_SENT_ACTION:处理Sms发送handleSmsSent,用于发送多条信息的时候。第一条由ACTION_SEND_MESSAGE处理,剩下是该action处理。从待发送消息队列中取得消息,并按次序逐个发送;
D. TelephonyIntents.ACTION_SERVICE_STATE_CHANGED:处理通讯网络状态改变handleServiceStateChanged,用户从无信号状态进入有信息号状态后,继续执行发送任务的情况;
E. ACTION_SEND_MESSAGE:处理Sms所发送的第一条短信,调用handleSendMessage。
2、TransactionService ,是处理与彩信相关业务的服务组件,根据代码中的注释可以了解到,收发彩信时可以是移动数据网络(mobile data network)或Wi-Fi网络。当没有可用的移动数据网络连接时,会尝试通过Wi-Fi网络发送或接收MMS信息(如果有 Wi-Fi 网络的话)。它同样在onCreate方法里首先创建了后台工作线程,通过NetworkConnectivityListener类监听通讯网络链接状态的变化,并根据不同的链接状态作出相应的反应。紧接着就是onStartCommand方法了,它首先会检测当前的网络连接状态,然后分别完成以下几件事情:
A.针对收发彩信的业务,它将intent.getExtras()包装成一个TransactionBundle,再通过launchTransaction()方法将具体工作交给后台工作线程去处理。
B.如果 intent.getExtras()为Null时,它会尝试从数据库中扫描是否有(上次系统结束时)未完成的操作,如果有则遍历所有操作项,逐个调用 launchTransaction()方法,以完成操作;
重点还是在后台工作线程的处理逻辑上,在代码中表现为handleMessage方法,它共处理以下几种不同类型的业务消息:
EVENT_CONTINUE_MMS_CONNECTIVITY ,与彩信系统建立网络连接,它首先会检查当前是否有待处理的业务,然后通过调用beginMmsConnectivity方法来创建彩信系统的网络连接,如果网络连接被正确建立,那么它会通过一个30秒间隔的计时器来维持连接的持续存在;
EVENT_DATA_STATE_CHANGED ,网络连接状态发生改变分支,这一分支是通过对NetworkConnectivityListener对象的监听而获得回调。在该分支中首先确认了网络连接的有效性,然后创建 TransactionSettings对象,并调用processPendingTransaction方法处理具体的彩信业务;
EVENT_TRANSACTION_REQUEST ,这是对具体彩信业务的处理分支,它首 先创建了承载业务参数的TransactionSettings对象,该对象包含有彩信中心服务地址(mmscUrl)、代理服务器地址和端口等用于建立网络连接的参数,然后根据不同的业务类型,分别进行处理。当前仅明确处理了以下4中业务:
(1)、NOTIFICATION_TRANSACTION,通过一条Push数据,通知手机端收到有新信息;
(2)、RETRIEVE_TRANSACTION,收取彩信;
(3)、SEND_TRANSACTION,发送彩信;
(4)、READREC_TRANSACTION,彩信阅读报告;
用于处理具体业务的关键代码在processTransaction方法中,它首先检查业务是否已存在于处理队列中(mProcessing & mPending),然后调用beginMmsConnectivityGemini()(双卡)或beginMmsConnectivity()(单卡)方法确认网络连接有效性,并点亮终端屏幕,然后将业务对象调到处理队列中并向业务附加观察者,最后调用业务自身process()方法完成网络通信。注意:业务的process方法被调用又会触发观察者(即当前service) 的update方法被调用,这使得刚才被处理掉的业务从队列中被移除,并且开始处理下一条业务;
EVENT_HANDLE_NEXT_PENDING_TRANSACTION ,这是一个多条彩信业务能够被连续处理的关键分支,首先在当前service中有mProcessing数组列表用于缓存连续的彩信业务,每条彩信业务是一个可被观察的对象(注:观察者模式 ),当前service是唯一观察者,其会感知到一条业务已处理结束,并触发下一条业务处理的开始; 所有彩信业务处理完成后, 会调用 service中的endMmsConnectivity()方法,结束与彩信中心的网络连接,并撤销屏幕点亮。
3、WapPushReceiverService当被创建时首先初始化了一个新的工作线程(HandlerThread对象)用来在后台完成相关动作,紧接着在onStartCommand方法里会将具体的任务通过消息(即调用service的Intent)发送给工作线程进行处理。根据Intent.Action的名称,工作线程会处理2种情况:
A.系统启动完成后BOOT_COMPLETED:把发件箱(outbox)中的消息移动到发送队列(QueuedBox),然后开始发送队列中的消息,最后调用blockingUpdateNewMessageIndicator()方法更新状态栏消息指示图标;
B.处理Wappush,调用handleWapPushReceived,从Intent中取得Wappush
消息对象,直接显示给用户并保持到数据库中。
4、CBMessageReceiverService当被创建时首先初始化了一个新的工作线程(HandlerThread对象)用来在后台完成相关动作,紧接着在onStartCommand方法里会将具体的任务通过消息(即调用service的Intent)发送给工作线程进行处理。根据Intent.Action的名称,工作线程会处理: Broadcast Message,调用handleCBMessageReceived,从Intent中取得Broadcast Message广播消息对象,直接显示给用户并保持到数据库中。
5、QuerySimContactsService 查询SIM卡中的联系人,并将数据插入到短信中的simcontacts.db数据库中。
四. ContentProvider
ContentProvider组织应用程序的数据,并向其他应用程序提供数据。在Mms应用中一共有2个ContentProvider,他们分别是:
1、SuggestionsProvider 提供对Mmssms.db数据库的访问。
2、SimContactsProvider 提供对Simcontacts.db数据库的访问。