由於近期所做一個項目需要做類似於“來電秀”的功能,所以上網搜索了一些相關資料,加上自己的一些想法,做了一個Demo。一下是我對該功能實現的一些想法,不對的地方歡迎各位指出。最后我會給出Demo 的源代碼。
首先,Android系統的手機在監聽到有電話呼入的時候會向系統發送電話狀態改變的廣播(android.intent.action.PHONE_STATE)。要想實現來電秀功能,必須在自己的程序中注冊監聽該廣播。所以我們的程序大致功能就是通過監聽該廣播,當有電話呼入的時候顯示自定義的界面。
以什么樣的方式顯示自定義的界面呢?主要有兩種方式:
1 .以Activity的形式顯示界面。
這種方式就是當有來電時啟動自己的Activity並使其位於系統來電界面的上方,完全遮住系統界面。這種方式的好處是可以完全根據自己的需求做界面,但是主要面臨着以下幾個主要問題:
(1) 如何使自己的Activity遮住系統的來電界面:Android系統中系統級的應用有着最高的優先級,自己的應用不可能比系統優先級高,所以我們沒辦法屏蔽系統來電界面,只能等系統來電界面顯示之后再啟動我們自己的Activity ,暫時的處理是:在我們的應用接收到來電廣播的時候延遲一秒鍾啟動我們自定義的Activity,這時候系統的來電界面應該已經顯示了,這樣基本可保證我們的Activity位於系統來電界面之上。
(2) 使用自己的Activity如何接聽或掛斷電話:Android SDK並沒有將系統接聽或掛斷電話的接口開放出來,但是卻以.aidl(Android Interface Definition Language,Android接口定義語言,可以使應用程序跨進程訪問其他類的方法)向其他應用開放了(源碼位置:frameworks/base/telephony/Java/com/android/internal/telephony),我們可以在程序中建立一個同樣的.aidl文件,並在程序中以反射的方式獲取所需要的方法,主要的就是endCall方法(拒接或掛斷電話)和answerRingingCall方法(接聽電話)。但是另外一個問題是調用answerRingingCall方法需要權限(android.permission.MODIFY_PHONE_STATE , 該權限可以使應用程序改變電話的狀態) ,但是該權限在android2.3及以后的版本中被隱藏,只有系統級應用才能拿到,這樣我們只能通過模擬手機插上耳機時通過耳機上的按鈕接聽電話的操作來接聽電話(具體實現看http://yk8900.blog.163.com/blog/static/123183544201272835550952/ )。
(3) 按下接聽鍵前實時從網絡取數據:在2G網絡(GSM, GPRS,EDGE)情況下,來電的時候一般會斷網(沒有詳細測試)。在3G(CDMA2000[電信],WCDMA[移動],TD-CDMA[移動])或WIFI情況下來電的時候是不會斷網的,所以如果要從網絡取數據,必須是在3G或WIFI情況下使用來電秀。
(4) 兼容性問題:由於使用自定義的Activity涉及到比較多的android底層未開放的接口,而各大手機廠商為了生產有自己個性的手機都會在一定程度上修改android底層源碼,所以各種ROM的情況不一樣, 我們無法做到適配所有android手機(目前該方法在三星和魅族手機上測試正常)。
2.以系統級彈框形式顯示界面。
這種方式是當有來電時彈出一個窗口浮於系統所有界面之上的形式。也就是和360顯示來電歸屬地的方式一樣。使用這種方式實現同樣需要考慮的問題設置為全屏還是半屏:如果設置為全屏,那么需要自己實現接電話的流程,那么就和使用Activity顯示界面面臨同樣問題。如果設置為半屏,需要面對的問題是:一般來說彈窗和主界面的焦點不能兼得,如果能夠很方便地就使用戶既能操作彈窗內部的控件又不影響用戶點擊來電主界面上的各個按鈕,那么用這種方式無疑是最好的。
當然不管采用哪種方式我們都需要面對很多比較特殊的情況,比如,在接聽電話過程中有另一個電話進來怎么處理;在雙卡雙待的情況下會不會出現問題;用耳麥上的按鈕接聽電話,在接聽電話過程中拔出耳麥會不會有影響等等,以及一些其他的不可預見的情況。
3.Demo運行的效果:
( 程序主界面可以選擇以什么方式顯示來電秀,並可以自定義)。
(選擇彈窗的形式顯示“來電秀”,高度設置了為75%)
(選擇以Activity的形式顯示來電秀)。