android撥號的源碼分析

1 OutgoingCallBroadcaster.java
點擊撥號盤撥打按鈕後,進入通話的Phone包。此時首先進入的函數是OutgoingCallBroadcaster.java,該類是一個Activity。
由activity的生命週期可知,第一次進入時應調用onCreate()函數。(在該類中也只實現了這個函數。)解析一下這個函數:
1.1) 首先獲取Intent對象,獲取撥出的號碼。
1.2) 接着判斷號碼是否爲緊急號碼,如果是緊急號碼,將callNow變量賦值爲true,啓動InCallScreen,併發送廣播。而在receiver裏面判斷callNow爲ture就直接finish,而不再重複啓動InCallScreen;如果不是緊急號碼,將callNow變量賦值爲false,發送廣播“Intent.ACTION_NEW_OUTGOING_CALL”。

2 OutgoingCallReceiver.java
廣播發送後OutgoingCallReceiver將會收到該息。該類是一個內部類,在類OutgoingCallBroadcaster裏面,作用是接收OutgoingCallBroadcaster發送的廣播,判斷是否已經啓動InCallScreen。沒有啓動的話就進行一些初始化,如:對OTA進行初始化。接收到廣播之後,從Intent裏面取出電話號碼及其URi。然後,設置Intent爲ACTION_CALL,並帶上號碼和uri。啓動InCallScreen。關閉該Activity。
OTA:Over-the-Air Technology空中下載技術,是通過移動通信(GSM或CDMA)的空中接口對SIM卡數據及應用進行遠程管理的技術。空中接口可以採用WAP、GPRS、CDMA1X及短消息技術。OTA技術的應用,使得移動通信不僅可以提供語音和數據服務,而且還能提供新業務下載。
GSM:Global System for Mobile Communications,中文爲全球移動通訊系統,俗稱"全球通"。
CDMA:Code Division Multiple Access,又稱碼分多址,是在無線通訊上使用的技術,CDMA允許所有的使用者同時使用全部頻帶(1.2288Mhz),並且把其他使用者發出的訊號視爲雜訊,完全不必考慮到訊號碰撞 (collision) 的問題。CDMA的優點包括:CDMA中所提供的語音編碼技術,其通話品質比目前的GSM好,而且可以把用戶對話時周圍環境的噪音降低,使通話更爲清晰。

3 InCallScreen.java
該類extends了Acitivity,並且implements了OnClickListener,OnTouchListener和OnQueryCompleteListener。該類主要是負責通話的那一個界面,並且還負責菜單項各種按鍵事件和觸摸時間的處理。同時本類還複寫的finish()方法,所以一般不會被finish掉,調用這個方法時它又把自己放回棧中。InCallScreen可以接收這個Intent並啓動。
3.1) onCreate(第一次)
3.1.1) callScreenOnCreate獲得通話界面被創建的時間。
3.1.2) PhoneApp喚醒後臺的服務程序。
3.1.3) 判斷當前的通話狀態(IDLE =沒有通話行爲,RINGING =正在通話或呼叫等待,OFFHOOK = The phone is off hook. At least one call exists that is dialing, active or holding and no calls are ringing or waiting.),如果正在通話,不會出現鍵盤鎖。接着設置mPhone and mForegroundCall/mBackgroundCall/mRingingCall。
3.1.4) getBluetoothHandsfree設置藍牙耳機,如果存在藍牙耳機,則安裝該設備。
3.1.5) initInCallScreen加載各種view組建。
3.1.6) 對通話的各種狀態進行廣播。(registerForPreciseCallStateChanged,registerForDisconnect,registerForMmiInitiateregisterForMmiComplete,registerForCallWaiting,registerForSuppServiceFailed,registerForCdmaOtaStatusChange)
3.1.7) internalResolveIntent判斷是否使用了OTA技術,通過該判斷設置通話界面的樣式。
3.1.8) callScreenCreated記錄通話界面創建完成後的時間
3.2) onNewIntent(非第一次)。
我們重新啓動一個Intent時調用該函數。由於我們圍繞唯一的一個InCallScreen實例來完成通過的這個過程,那麼除了第一次被創建的InCallScreen,只要有來電或者去電,該程序就會發生。如果InCallScreen已經在前臺,該程序也會發生。
3.2.1) setIntent保存該Intent,以至於將來我們可以獲得該intent。
3.2.2) internalResolveIntent
3.3) onResume
進行一些初始化操作,如:獲取一個PhoneApp對象,解開Keyguard Notification的statusBar給Disable。還內置了一個Handler可以回調處理一些事件,比如:PHONE_STATE_CHANGED,PHONE_DISCONNECT,EVENT_HEADSET_PLUG_STATE_CHANGED。同時有一個獨立的BroadcastReceiver處理ACTION_HEADSET_PLUG,比如插入耳機等。
3.3.1) 首先對鎖屏情況下的來電除了處理。
3.3.2) disableStatusBar當正在通話界面時,使得狀態欄可用。
3.3.3) setIgnoreTouchUserActivity忽略通話過程中無意的觸碰事件,使得這些無意的觸碰不會阻止設備進入休眠。
3.3.4) registerReceiver監聽廣播
3.3.5) startDialerSession當在前臺是,保持一個dialer session。首先判斷時候需要播放本地鈴聲,如果需要,則判斷雙音多頻是否可用,如果可用,則創建一個聲音播放器。
3.3.6) isBluetoothAudioConnected做一個是否藍牙連接的判斷。
3.3.7) 如果是cdma通話,則初始化OTA狀態,進而如果是採用了OTA,則設置InCallScreenMode爲OTA通話模型。
3.3.8) clearDisconnected在檢查該通話狀態之前,切斷其他網絡連接。
3.3.9) syncWithPhoneState同步通話界面與Phone的當前狀態。如果沒有同步成功,則dismissAllDialogs();結束當前的所以通話,endInCallScreenSession();關閉通話界面的顯示。
3.3.10) updateWakeState設置基於當前Phone的喚醒狀態和屏幕超時,以及通話界面的當前狀態。
3.3.11) enableTouchLock當onresume時“觸摸鎖“疊加是不可見的,尤其是這個檢查可確保用戶通話按MUNU來喚醒屏幕後將不會被鎖。但如果撥號盤是打開的,而又需要通話計時,則造就了“觸摸鎖“覆蓋。

4 Profiler.java
該類對通話各個時間點進行記錄。
static long sTimeCallScreenRequested;//通話界面被請求的時間
static long sTimeCallScreenOnCreate;//通話界面被創建的時間
static long sTimeCallScreenCreated;//通話界面創建完成後的時間
static long sTimeIncomingCallPanelRequested;//正在通話時,通話界面被請求的時間
static long sTimeIncomingCallPanelOnCreate;//正在通話時,通話界面被創建的時間
static long sTimeIncomingCallPanelCreated;//正在通話時,通話界面創建完成後的時間

5 PhoneUtils.java
負責Phone對象的生成,主要調用phone.getForegroundCall(),phone.getBackgroundCall(),phone.getRingingCall(),phone.dial()。
5.1) placeCall(Phone phone, String number, Uri contactRef)
撥打傳入的電話號碼,該函數被InCallScreen中的placeCall調用。
參數phone手機對象;參數number用戶要撥打的號碼;參數contactRef要麼是“tel:”,要麼是“content://contacts”,取決於通話初始化,該參數引發呼叫;返回CALL_STATUS_DIALED,CALL_STATUS_DIALED_MMI,或CALL_STATUS_FAILED。
5.2) placeCallVia(Context context,Phone phone,String number,Uri contactRef,Uri gatewayUri)
使用第三方提供的網關撥打號碼,該函數被InCallScreen中的placeCall調用。如果電話號碼是緊急號碼,GSM MMI碼或者CDMA碼則不能被呼叫。如果連接成立,這個方法發出一個同步調用阻止查詢來電信息,使本地採用異步查詢。
參數phone手機對象;參數context執行CallerInfo查詢;參數number用戶要撥打的號碼,如果號碼不能建立連接,則僅被用於建立電話卡,並更新通話記錄;參數contactRef要麼是“tel:”,要麼是“content://contacts”,該參數引發呼叫;參數gatewayUri用於設置連接的地址;返回CALL_STATUS_DIALED或CALL_STATUS_FAILED。

6 PhoneApp.java
該類是一個普通的java類,主要負責Phone對象頂層應用的生成。這是一個虛擬的Phone對象,它從framework層取得一個Phone對象。該類繼承自Application,同時能常駐內存,他和PhoneUtils一起處理電話操作。在oncreate方法裏面進行各種全局的初始化:獲取Phone對象 NotificationMgr對象,PowerManager對象,SimCard對象等。同時內置的Handler可以回調處理各種事件,如:EVENT_SIM_ABSENT,EVENT_SIM_NETWORK_LOCKED,EVENT_UPDATE_INCALL_NOTIFICATION等。

7 CallNotifier.java
監聽Phone狀態的改變和來自telephony層各種事件,並觸發任何有關的UI行爲(如開始的鈴聲和來電的用戶界面,打在通話音,更新通知,寫呼叫記錄條目等)。
7.1) 在構造函數中,實現
mPhone.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);/*當有新來電或等待連接時Notifies。收到的訊息是:Message.obj將是一個AsyncResult,AsyncResult.userObj=obj,AsyncResult.result=a Connection。因爲這個消息已經過時,所以通過檢測Connection.isRinging()以確保連接有效。如果Connection.isRinging()爲true,那麼Connection.getCall()==Phone.getRingingCall()*/
mPhone.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null);/*爲通話狀態的改變註冊notification。通過調用PreciseCallState以獲取更準確的通話狀態。*/
mPhone.registerForDisconnect(this, PHONE_DISCONNECT, null);/*當由於本地或遠程電話掛斷或者出現錯誤掛斷通話時Notifies。收到的訊息是:Message.obj will be an AsyncResult,AsyncResult.userObj = obj,AsyncResult.result = a Connection object that is no longer connected.*/
mPhone.registerForUnknownConnection(this, PHONE_UNKNOWN_CONNECTION_APPEARED, null);/*當以前未跟蹤non-ringing/waiting連接時Notifies。這可能是由於一些其他實體(如SIM卡應用)發起呼叫。*/
mPhone.registerForIncomingRing(this, PHONE_INCOMING_RING, null);/*當有來電話響鈴時Notifies。收到的訊息是:Message.obj will be an AsyncResult,AsyncResult.userObj = obj,AsyncResult.result = a Connection.*/
另外如果是CDMA通訊類型,還執行:
mPhone.registerForCdmaOtaStatusChange(this, EVENT_OTA_PROVISION_CHANGE, null);/*當CDMA OTA提供者位置改變時註冊notification*/
mPhone.registerForCallWaiting(this, PHONE_CDMA_CALL_WAITING, null);/*當CDMA呼叫等待時註冊notification*/
mPhone.registerForDisplayInfo(this, PHONE_STATE_DISPLAYINFO, null);/*爲來自網絡顯示信息通知註冊。Message.obj將包含一個AsyncResult。AsyncResult.result將是一個SuppServiceNotification實例。*/
mPhone.registerForSignalInfo(this, PHONE_STATE_SIGNALINFO, null);/*爲來自網絡的信號信息通知註冊。Message.obj將包含一個AsyncResult。AsyncResult.result將是一個SuppServiceNotification實例。*/
mPhone.registerForInCallVoicePrivacyOn(this, PHONE_ENHANCED_VP_ON, null);/*當sInCall VoicePrivacy可用時註冊notification*/
mPhone.registerForInCallVoicePrivacyOff(this, PHONE_ENHANCED_VP_OFF, null);/*當sInCall VoicePrivacy不可用時註冊notification*/
mPhone.registerForCdmaFwdBurstDtmf(this, PHONE_CDMA_FWD_BURST_DTMF, null);/*爲 CDMA Forward Burst DTMF的事件通知設置處理程序*/
mPhone.registerForCdmaFwdContDtmfStart(this, PHONE_CDMA_FWD_CONT_DTMF_START, null);/*爲 CDMA Forward Burst DTMF啓動的事件通知設置處理程序*/
mPhone.registerForCdmaFwdContDtmfStop(this, PHONE_CDMA_FWD_CONT_DTMF_STOP, null);/*爲 CDMA Forward Burst DTMF停止的事件通知設置處理程序*/
如果是GSM類型,則執行:
mPhone.registerForRingbackTone(this, PHONE_RINGBACK_TONE, null);/*當帶外回鈴音(專業術語CRBT:COLOR RING BACK TONE,回鈴音定義:當別人打電話給您時,他(她)聽到的聲音叫做回鈴音。回鈴音是指撥打電話的呼叫方所聽到的對方電話的聲音,當撥通電話時聽到通話音,通常是長音;而當對方佔線時則聽到忙音,聲音短促,有時,忙音會變成人聲語音提示。)時Notifies。收到的訊息是:Message.obj將是一個AsyncResult,AsyncResult.userObj=obj,AsyncResult.result=true表示開始播放回鈴音;=false表示停止。*/
mPhone.registerForResendIncallMute(this, PHONE_RESEND_MUTE, null);/*爲復位上行靜音狀態成上行音頻註冊處理程序。*/
7.2) 整個類由函數handleMessage串起來。

發佈了41 篇原創文章 · 獲贊 9 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章