Messaging中的Receiver
R eceiver廣播 接收器用於響應系統中的各類廣播事件並執行相關業務代碼的組件,經常使用於完成如:啓動service、顯示Activity等 任務 。在Messagin應用中一共有7個 R eceiver:
一、.transaction.SmsReceiver : 短消息 廣播 接收器,它負責處理與收到短消息相關的廣播事件。觸發該接收器運行的intent有兩個:
A.android.intent.action.BOOT_COMPLETED--->Android系統啓動完成時會發出該廣播,即SmsReceiver會在系統啓動完成時接收到調用;
B.com.android.mms.transaction.MESSAGE_SENT --->定義在 SmsReceiverService.java中的常量,被用在SmsMessageSender.sendMessage方法中——即短消息發送後 觸發的廣播事件;
徹底和預想的同樣,在 SmsReceiver中會啓動 SmsReceiverService,啓動代碼在beginStartingService方法裏。值得注意的是它同時還作了「屏幕喚醒鎖定 (WakeLock)」 操做,最終在service啓動完成後,經過回調用finishStartingService方法,解除了屏幕喚醒鎖定。
SmsReceiver.java中有編譯錯誤,由於沒法訪問android.provider.Telephony.Sms.Intents。其實 Intents 所在位置是:myeclair/frameworks/base/core/java/android/provider/Telephony.java,它被標記爲@hide。
二、 . transaction.PrivilegedSmsReceiver :該接收器是SmsReceiver的子類,惟一的區別在於該Receiver被申明有permission爲android.permission.BROADCAST_SMS。
三、.transaction.MmsSystemEventReceiver :Mms系統事件接收器,它負責 在收到新消息時 向通知區域(即標題欄)顯示小圖標,和 從新發送在發件箱中的MM。觸發該接收器運行的兩個Intent是:
A. android.intent.action.BOOT_COMPLETED ---> :與SmsReceiver中的狀況相同;
B.android.intent.action.CONTENT_CHANGED ---> :鏈接方式改變時系統會發出該廣播,即在鏈接方式變化,例如從gprs-->wifi時該接收器將被調用 ;
在MmsSystemEventReceiver類中,程序一旦得到數據鏈接時就會啓動TransactionService服務;當鏈接方式改變時還會調用PduCache.purge()方法清理緩存;還有當系統剛剛啓動時 會同步通知區域的圖標、未讀消息個數等信息。
MmsSystemEventReceiver.java中有編譯錯誤,由於它沒法訪問如下類:
一、com.google.android.mms.util.PduCache:位置-myeclair/frameworks/base/core/java/com/google/android/mms/util/PduCache.java,該類未包含在默認的android.jar文件中,須要從新編譯;
二、android.provider.Telephony.Mms: 位置- myeclair/frameworks/base/core/java/android/provider/Telephony.java,該類被標記爲 @hide 。
三、com.android.internal.telephony.TelephonyIntents:位置-myeclair/frameworks/base/telephony/java/com/android/internal/telephony/TelephonyIntents.java,該類是一個常量類是未被開放的API。
四、com.android.internal.telephony.Phone: 位置- myeclair/frameworks/base/telephony/java/com/android/internal/telephony/Phone.java, 該類被標記爲 @hide 。
四、.transaction.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將不會被觸發執行。
PushReceiver.java中有編譯錯誤,由於它沒法訪問如下類:
一、android.provider.Telephony : 位置- myeclair/frameworks/base/core/java/android/provider/Telephony.java,該類被標記爲 @hide 。
二、com.google.android.mms.*: 位置- myeclair/frameworks/base/core/java/com/google/android/mms/*,這些類未包括在公開的API中。
五、. transaction.MessageStatusReceiver :消息狀態改變時的廣播接收器,消息狀態改變是指消息的投遞狀態(即:是否成功送達、是否被目標用戶閱讀等)的變化,觸發該接收器的Intent是:com.android.mms.transaction.MessageStatusReceiver. MESSAGE_STATUS_RECEIVED,該值是申明在MessageStatusReceiver.java文件中的常量。該廣播事件是在SmsMessageSender.sendMessage()方法中被髮出的,收到廣播事件後,Receiver的會作兩件事情:a-取得pdu數據包 更新消息狀態(在updateMessageStatus方法中);b-更新通知區域的新消息指示信息 (在MessagingNotification.updateNewMessageIndicator()方法中)。
MessageStatusReceiver.java中有編譯錯誤,由於它沒法訪問如下類:
一、android.provider.Telephony : 位置- myeclair/frameworks/base/core/java/android/provider/Telephony.java,該類被標記爲 @hide 。
二、com.google.android.mms.util.SqliteWrapper: 位置- myeclair/frameworks/base/core/java/com/google/android/mms/ util/SqliteWrapper.java,該類未包括在公開的API中。
六、.transaction.SimFullReceiver :Sim卡短信存儲空間滿的事件通知,當系統發現Sim卡中存儲短信的空間耗盡時會發出該廣播事件。該接收器完成的工做是在通知區域顯示相關信息,點擊通知信息後,能夠進入管理Sim卡中短消息的Activity界面 。
SimFullReceiver.java中有編譯錯誤,由於它沒法訪問 android.provider.Telephony 類,所在位置-myeclair/frameworks/base/core/java/android/provider/Telephony.java,該類被標記爲 @hide 。
七、.transaction.SmsRejectedReceiver :短消息被拒絕時的事件接收器,當手機的存儲空間不足時會拒絕接收新的短消息,當該事件發生時SmsRejectedReceiver被調用,它會檢查確認是不是存儲空間不足,而後在通知區域顯示相關通知信息。
SmsRejectedReceiver.java中有編譯錯誤,由於它沒法訪問 android.provider.Telephony 類,所在位置-myeclair/frameworks/base/core/java/android/provider/Telephony.java,該類被標記爲 @hide 。
Messaging中的Activity
Activity是用來構建UI(用戶界面 )的組件,用戶操做界面表明了應用程序提供的基本功能,是應用程序和用戶之間的交互接口。在Messaging應用中有如下的Activity:
一、.ui.ConversationList ,對話列表界面,這是進入應用程序的主界面。它有兩個配置屬性值得咱們特別注意,a.android:configChanges="orientation|keyboardHidden":在Android系統中,當程序所運行的環境(如:屏幕方向、鍵盤狀態、字體等級,等等 )發生變化後 會致使Activity被從新啓動(以適應環境變化 ),然而 Activity也能夠宣稱本身來應付某些變化(而不是一股腦地全讓系統重啓本身), configChanges 屬性 正是用於 指定本身願意 應付 的變化狀況。此處該屬性有兩個值, orientation表明屏幕方向發生改變,keyboardHidden表示鍵盤可訪問狀態發生變化(即鍵盤彈出/收起 ),這意味着當屏幕方向和鍵盤可用狀態 發生變化時, Activity不會被從新啓動,而是調用其onConfigurationChanged方法,一般是在該方法中對本身作出調整,以適應變化;b.launchMode="singleTop":該屬性指示了Activity的加載模式,這與Activity在不一樣Task之間的重用有關,該屬性共有4個可用選項standard, singleTop,singleTask,singleInstance,它們將與Intent中的FLAG_ACTIVITY_* 標記 常量 協同產生相關做用。
ConversationList類中定義了程序中涉及到的選項菜單、會話(Conversation)項上的上下文菜單等UI元素。另外該類中的runOneTimeStorageLimitCheckForLegacyMessages方法用於檢測存儲空間限制。
SmsRejectedReceiver .java中有編譯錯誤,由於它沒法訪問如下類:
1.android.provider.Telephony 類,所在位置- myeclair/frameworks/base/core/java/android/provider/Telephony.java,該類被標記爲 @hide 。
2. com.google.android.mms.*: 位置- myeclair/frameworks/base/core/java/com/google/android/mms/*,這些類未包括在公開的API中。
二、.ui.ComposeMessageActivity ,建立新消息的用戶界面,經過選項菜單menu_compose_new會調用到該界面。這是個很龐大的類,內部實現也很複雜,等仔細看了再寫補充吧。
ComposeMessageActivity .java中有編譯錯誤,由於它沒法訪問如下類:
1.com.android.internal.widget.ContactHeaderWidget類,所在位置-myeclair/frameworks/base/core/java/com/android/internal/widget/ContactHeaderWidget.java,該類被標記爲 @hide 。
2.com.android.internal.telephony.* 類,所在位置- myeclair/frameworks/ base/telephony/java/com/android/internal/telephony/*,這些類未包括在公開的API中 。
3. com.google.android.mms.*: 位置- myeclair/frameworks/base/core/java/com/google/android/mms/*,這些類未包括在公開的API中 。
三、 .ui.ForwardMessageActivity ,用於轉發消息的Activity,這是ComposeMessageActivity的別名,用於把一條現有消息的內容帶到建立消息的界面上;
四、.ui.DeliveryReportActivity ,投遞報告 Activity, 用於報告消息的投遞狀態,它採用對話框風格的主題(android:theme="
@android :style/Theme.Dialog")。 DeliveryReportActivity .java中有編譯錯誤,由於它沒法訪問如下類: 1. com.google.android.mms.*: 位置- myeclair/frameworks/base/core/java/com/google/android/mms/*,這些類未包括在公開的API中 。 2. android.provider.Telephony 類,所在位置- myeclair/frameworks/base/core/java/android/provider/Telephony.java,該類被標記爲 @hide 。 五、.ui.WarnOfStorageLimitsActivity ,存儲空間限制警告,用於告知用戶 關於存儲空間限制的設置信息。 WarnOfStorageLimitsActivity .java中有編譯錯誤,由於它沒法訪問如下類: 1. com.android.internal.app.AlertActivity類, 位置- myeclair/frameworks/base/core/java/com/android/internal/app/AlertActivity.java,該類未包括在公開的API中 。 2. com.android.internal.app.AlertController類, 位置- myeclair/frameworks/base/core/java/com/android/internal/app/AlertController.java,該類未包括在公開的API中 。 6.ui.ConfirmRateLimitActivity ,發送多條彩信時向用戶提示確認的界面,它包括了自動 應答操做——即用戶 超過一段時間 未做出響應時自動取消發送。 七、.ui.ClassZeroActivity ,ClassZero是一種特殊的短消息類型,它會直接顯示在用戶屏幕上並等待用戶操做。ClassZeroActivity正是用來顯示此類型的短信消息 ,並運行用戶將信息保存起來 。 ClassZeroActivity .java中有編譯錯誤,由於它沒法訪問如下類: 1. android.provider.Telephony 類,所在位置- myeclair/frameworks/base/core/java/android/provider/Telephony.java,該類被標記爲 @hide 。 2. com.google.android.mms.util.SqliteWrapper: 位置- myeclair/frameworks/base/core/java/com/google/android/mms/ util/SqliteWrapper.java ,該類未包括在公開的API中。 八、.ui.MessagingPreferenceActivity ,這是Messaging應用的系統配置界面,其中有針對SMS、MMS、存儲限制等配置屬性,以及管理存儲在 SIM卡中 的短信消息。該Activity啓動時會檢查當前是否有SIM,以及是否支持MMS來動態調整配置項列表。 MessagingPreferenceActivity .java中有編譯錯誤,由於它沒法訪問TelephonyManager.getDefault()方法,能夠考慮使用Context.getSystemService(Context.TELEPHONY_SERVICE)方法來獲得類實例。 九、.ui.ManageSimMessages ,用於管理Sim卡中短消息的界面,它以列表的形式顯示了存儲在SIM卡中的短消息,並容許用戶將信息轉存到手機內存中,或者刪除消息。 ManageSimMessages .java中有編譯錯誤,由於它沒法訪問如下類: 1. android.provider.Telephony 類,所在位置- myeclair/frameworks/base/core/java/android/provider/Telephony.java,該類被標記爲 @hide 。 2. com.google.android.mms.util.SqliteWrapper: 位置- myeclair/frameworks/base/core/java/com/google/android/mms/ util/SqliteWrapper.java ,該類未包括在公開的API中。 十、.ui.SearchActivity ,用於信息搜索的操做界面。Android經過系統服務Context. SEARCH_SERVICE(即SearchManager類)提供了強大的信息搜索功能。在該應用中經過對聯繫人(或者電話號碼)、主題等信息的匹配來搜索信息,並將結果顯示在一個列表中。 SearchActivity .java中有編譯錯誤,由於它沒法訪問如下類: 1. android.provider.Telephony 類,所在位置- myeclair/frameworks/base/core/java/android/provider/Telephony.java,該類被標記爲 @hide 。 十一、.ui.SlideshowEditActivity , 所謂Slide是指MM中的一頁內容 即一幀,一般被稱爲幻燈片。 SlideshowEditActivity是彩信中全部內容(即多個Slide)的列表,用戶能夠選定列表項進入Slide播放/修改界面。 SlideshowEditActivity .java中有編譯錯誤,由於它沒法訪問如下類: 1. com.google.android.mms.*: 位置- myeclair/frameworks/base/core/java/com/google/android/mms/*,這些類未包括在公開的API中 。 十二、.ui.SlideshowActivity , 用於播放Slide幻燈片的界面,它會在全屏狀態下顯示幻燈片的內容。 SlideshowActivity .java中有編譯錯誤,由於它沒法訪問如下類: 1. com.google.android.mms.*: 位置- myeclair/frameworks/base/core/java/com/google/android/mms/*,這些類未包括在公開的API中 。 1三、.ui.SlideEditorActivity ,用於編輯Slide幻燈片內容的操做界面,它提供了:添加、移除 文本/圖片/音樂,以及Slide等功能。 SlideEditorActivity .java中有編譯錯誤,由於它沒法訪問如下類: 1. com.google.android.mms.*: 位置- myeclair/frameworks/base/core/java/com/google/android/mms/*,這些類未包括在公開的API中 。 1四、.ui.EditSlideDurationActivity ,用於修改Slide幻燈片持續顯示時間 的操做界面 ,默認持續顯示時間是5秒。 EditSlideDurationActivity .java編譯無錯誤。 Messaging中的Service 應用中共有兩個service:.transaction.TransactionService 和 .transaction.SmsReceiverService,前者負責處理與彩信(MMS)相關的網絡業務,後者是短消息(SMS)的接收器,二者都會響應來自通信網絡的通知並收取信息。它們只用於本應用內部(由於其未聲明任何intent-filter),上文介紹的廣播接收器中有顯式啓動它們的代碼。如下咱們將分別分析兩個Service的基本實現。 一、.transaction.SmsReceiverService ,它被建立時首先 初始化了新的工做線程(HandlerThread對象)用來在後臺完成相關動做,緊接着在onStartCommand方法裏會將具體的任務經過消息(即調用service的Intent)發送給工做線程進行處理。根據Intent.Action的名稱,工做線程會處理4中狀況: A.系統啓動完成後BOOT_COMPLETED:把發件箱(outbox)中的消息移動到發送隊列(QueuedBox),而後開始發送隊列中的消息,最後調用updateNewMessageIndicator方法更新狀態欄消息指示圖標; B.處理Sms接收handleSmsReceived:從Intent中取得消息對象,直接顯示給用戶(Class0類型)或者保持到數據庫中。 C.處理Sms發送handleSmsSent:從待發送消息隊列中取得消息,並按次序逐個發送; D.處理通信網絡狀態改變handleServiceStateChanged:用戶從無信號狀態進入有信息號狀態後,繼續執行發送任務的狀況; 二、.transaction.TransactionService , 是處理與彩信相關業務的服務組件,根據代碼中的註釋能夠了解到: 收發彩信時能夠是移動數據網絡(mobile data network)或Wi-Fi網絡。當沒有可用的移動數據網絡鏈接時,會嘗試經過Wi-Fi網絡發送/接收MMS信息(若是有 Wi-Fi 網絡的話)。 它 一樣在onCreate方法裏首先建立了後臺工做線程,經過NetworkConnectivityListener類( 一個被@hide的類 )監聽通信網絡連接狀態的變化,並根據不一樣的連接狀態做出相應的反應。 緊接着就是onStartCommand方法了,它首先會檢測當前的網絡鏈接狀態,而後分別完成如下幾件事情: A.針對收發彩信的業務,它將intent.getExtras()包裝成一個DTO—— TransactionBundle,再經過launchTransaction()方法將具體工做交給後臺工做線程去處理。 B.若是 intent.getExtras()爲Null時,它會嘗試從數據庫中掃描是否有(上次系統結束時)未完成的操做,若是有則遍歷全部操做項,逐個調用launchTransaction()方法,以完成操做; 重點仍是在後臺工做線程的處理邏輯上,在代碼中表現爲handleMessage方法,它共處理如下幾種不一樣類型的業務消息: Ⅰ.EVENT_CONTINUE_MMS_CONNECTIVITY ,與彩信系統創建網絡鏈接,它首 先會檢查當前是否有待處理的業務,而後經過調用beginMmsConnectivity方法來建立於彩信系統的網絡鏈接,若是網絡鏈接被正確創建,那麼它會經過一個30秒間隔的計時器來維持鏈接的持續存在; Ⅱ.EVENT_DATA_STATE_CHANGED ,網絡鏈接狀態發生改變分支,這一分支是經過對NetworkConnectivityListener對象的監聽而得到回調。在該分支中首先確認了網絡鏈接的有效性,(代碼在此處僅容許ConnectivityManager.TYPE_MOBILE_MMS類型那麼wi-fi鏈接屬於該類型? ),而後建立 TransactionSettings對象,並調用processPendingTransaction方法處理具體的彩信業務; Ⅲ.EVENT_TRANSACTION_REQUEST ,這是對具體彩信業務的處理分支,它首 先建立了承載業務參數的TransactionSettings對象,該對象包含有彩信中心服務地址(mmscUrl)、代理服務器地址和端口等用於創建 網絡鏈接的參數,而後根據不一樣的業務類型,分別進行處理。當前僅明確處理了如下4中業務: 一、NOTIFICATION_TRANSACTION,經過一條Push數據,通知手機端收到有新信息; 二、RETRIEVE_TRANSACTION,收取彩信; 三、SEND_TRANSACTION,發送彩信; 四、READREC_TRANSACTION,彩信閱讀報告; 用於處理具體業務的關鍵代碼在processTransaction方法中,它首先檢查業務是否已存在於處理隊列中(mProcessing & mPending),而後調用beginMmsConnectivity()方法確認網絡鏈接有效性,並點亮終端屏幕,而後將業務對象條件處處理隊列中並向業務附加觀察者,最後調用業務自身process()方法完成網絡通訊。注意:業務的process方法被調用又會觸發觀察者(即當前service) 的update方法被調用,這使得剛纔被處理掉的業務從隊列中被移除,而且開始處理下一條業務; Ⅴ.EVENT_HANDLE_NEXT_PENDING_TRANSACTION ,這是一個多條彩信業務可以 被 連續 處理的關鍵分支,首先在當前service中有mProcessing數組列表用於緩存連續的彩信業務,每條彩信業務是一個可被觀察的對象(注:觀察者模式 ), 當前service是惟一觀察者,其會感知到一條業務已處理結束,並觸發下一條業務處理的開始;