Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 對android M中Call的概要總結

對android M中Call的概要總結

編輯:關於Android編程

主要內容 1. Call涉及的目錄結構及框架結構 2. InCallUI層的基本架構(所涉及的Presenter、Fragment及Activity) 3. Call的幾種狀態(對應phone狀態)及上報流程 4. GSM與IMS MO流程的差異 5. 分析問題的常用log   希望你在看完本篇以後能夠: 1.快速找到Call界面某個小時內容對應的fragment及presenter 2.結合log快速定位當前call的狀態 PS:內容均為博主個人經驗總結,如有出錯的地方歡迎指正。

1. Call涉及的目錄結構及框架結構

1.1 目錄結構

packages/apps/Dialer/ packages/apps/InCallUI   packages/services/Telecomm packages/services/Telephony   framework/base/telecomm framework/opt/telephony (vendor/…/imsIms Call)   Dialer 撥打電話的入口,來電不會經過Dialer。但是撥打電話的出口不光是Dialer,在聯系人和短信裡也有撥打電話的出口。代碼運行在dialer進程。 InCallUI 負責顯示通話界面的信息,來電信息。dialer進程。 Telecomm 處理Intent,發送廣播,設置call的狀態,audio狀態。system_process和telecomm:ui進程。 Telephony 向下層傳遞撥號,注冊了很多廣播,申請很多權限(service data sms wap network)。 phone進程 telecomm 提供placeCall的接口(自android M開始),創建outgoingCall的connection,通知上層成功建立connection telephony 撥號 也就是dial命令的下發,但是如果是Ims網絡就會有下面一步 Vendor/ims 創建ImsConnection,ImsCall,撥號。phone進程。

1.2 框架結構

這只是框架上的一個大致結構 \ \ 在實際的流程中並不一定是自上而下或者自下而上的,也有可能跳過某個模塊直接傳遞信息。 比如在Dialer撥號的時候,就是直接調用framework/base/telecmm中TelecomManager的placeCall接口撥打電話。  

2. InCallUI層的基本架構(所涉及的Presenter、Fragment及Activity)

2.1InCallUI內有多個對應的Presenter和Fragment

Presenter和Fragment的關系:Fragment直接控制界面上的控件,並處理一些簡單的邏輯,對應的Presenter處理稍復雜的邏輯。 CallCardFragment CallCarfPresenter CallButtonFragment CallButtonPresenter CallCard和CallButton是綁定在一起顯示的,有CallCard就一定會有CallButton CallCard顯示撥打的電話的信息,包括聯系人姓名,號碼,通話時長,通話類型等(稍後有展示),CallButton包括可以對當前通話進行的操作,如通話保持,通話靜音,通話錄音等。   VideoCallFragment VideoCallPresenter 主要是視頻內容,在進入退出視頻模式時同時處理camera、audio相關信息。   AnswerFragment AnswerPresenter 顯示新來電,或者視頻升級請求,重點在於對不同類型的通話顯示不同的選項(也可根據運營商進行不同配置)。   DialpadFragment DialpadPresenter 撥號盤,添加通話的時候顯示。一般沒什麼問題,之前有該顯不顯的問題,同時dialpad的顯示會影響endCallButton的大小,兩者是同步變化的。   ConferenceManagerFragment ConferenceMangerPresenter 沒遇到過這裡的問題,只是准備PPT的時候才看到這個。 \ \
InCallActivity啟動的時候,在顯示完動畫後,調用showCallCardFragment()顯示CallCardFragment(CallCardFragment本身也有動畫)然後Fragment內new Presenter。 其他幾個也有各自的顯示流程,不一定是在InCallActivity的動畫顯示後立刻show出來。 另:VideoCallFragment不是通過showFragment()顯示的。

2.2 通話界面布局分析

注:界面被輕量定制,並非和原生完全一樣。 \ \ 圖1 CallCardFragment和CallButtonFragment 圖中除了priamry_card_info.xml和call_button_fragment.xml是布局文件,其他標注均為控件id。 AnswerFragment和DialpadFragment共用一個FramLayout @+id/answer_and_dialpad_container 在顯示的時候覆蓋在CallCard的上層,比如CallCard中的photo(聯系人頭像)就是被dialpad給覆蓋。 \ \ 圖2 VideoCallFragment(真人出境啦) 左側為普通視頻電話,右側為視頻會議電話。 注意,雖然右側看起來像是有4個小窗口顯示內容,但實際上和左邊一樣只有兩個控件顯示視頻,只不過右側上方的視頻內容被分成了3塊。我們把黑色的背景色調成藍色,就容易區分出是兩個控件了。 至於為什麼兩張圖incomingVideo的位置不一樣,CallCard一個顯示一個沒顯示,是因為,點擊屏幕(或者等5s)後CallCard會隱藏,然後incomingVideo會自動調整位置到中央。   \\ 圖3 AnswerFragment 更多的界面就不一一詳細說明了。 如果你看到了不常見的控件,那它在代碼中的位置,和臨近位置的控件的代碼位置也是臨近的(有點拗口= =)。  

2.3 InCallPresenter和InCallActivity

這個為什麼要單獨列成一條呢?因為這個Presenter比前面幾個Presenter都重要,它連結這界面的各個部分。 InCallPresenter 從CallList中獲取更新然後通知到InCallActivity,由InCallActivity控制界面顯示。 同時各個Fragment和Presenter可以獲得InCallPresenter的實例,進而更新/獲得數據。 單獨的Presenter負責對應的界面的邏輯,InCallPresenter負責整個界面的顯示,協調各個Fragment/Presenter之間的工作。 以視頻電話全屏為例,在VideoCallPresenter中有隱藏CallCard進入全屏模式的需求,在VideoCallPresenter中會通過InCallPresenter調用CallCardPresenter的onFullscreenModeChanged()方法,進而調用CallCardFragment的方法隱藏CallCard InCallActivity InCallActivity是InCallUI的主體,可以說所有的類都是圍繞著或者是為了這個Activity工作的,各個Fragment附著在InCallActivity上,InCallPresenter通過InCallActivity提供的get***Fragmment的方法,獲得具體Fragment對象, 更新界面。 Fragment是通過InCallActivity創建和顯示的,但是各個Presenter和InCallPresenter之間的交互不一定全都經過InCallActivity(比如可以通過listener調用) \\ 圖4 InCallUI基本架構 我們舉兩個例子 來說明界面上更新走過的流程: 1.設置CallStateLabel上的文本,比如"requesting video",代碼的執行經過InCallPresenter> CallCardPresenter> CallCardFragment,跳過了InCallActivity; 2.彈出dialog,比如“網絡不可用” ,代碼執行經過IncallPresenter > InCallActivity 還有另外一個比較重要的沒有體現在圖上的類叫做TelecomAdapter。 它的職責主要是把界面上操作的命令向下層傳遞,具體點就是把對call的操作傳給Telecomm,包括接聽,掛斷,拒接,靜音,切換audioRoute等。

3. Call的幾種狀態(對應phone狀態)及上報流程

3.1 Call的狀態

下面這張圖不用記,知道有這麼多就行了。 不同模塊的call的狀態不一樣,有些能對應上,有些是獨有的對應不上的。 比較重要的是InCallUI裡的Call.State和InCallPresenter的內部類InCallState InCallPresenter控制著界面顯示,這裡的InCallState就是界面顯示的依據。 TelephonyManager向外提供訪問手機狀態的接口,只有三種狀態。 \ \ 圖5 Call的狀態   下圖表現的是InCallUI Call狀態的轉化以及對應的TelephonyManager.CALL_STATE_***狀態 \ \ 圖6 InCallUI 中的Call狀態轉化 其中CONNECTING/SELECT_PHONE_ACCOUNT這兩個是二者取其一。如果是雙卡手機並設置每次詢問,則撥號後的狀態為SELECT_PHONE_ACCOUNT,如果有是單卡或者默認某一張卡撥打,則狀態為CONNECTING,並且這個狀態很短暫,很快就轉換為DIALING。  

3.2 上報流程

都是以UNSOL_RESPONSE_CALL_STATE_CHANGED消息上報為開始, //CS

  1. 09-09 10:52:42.093 D/RILJ ( 4017): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [SUB1] //PS 07-18 15:31:58.120
//PS

  1. D/ImsSenderRxr( 4499): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [id=1,DIALING,toa=129,norm,mo,0,voc,noevp,,cli=1,,3Call Details = 3 2 callSubState 0 videoPauseState2 mediaId0 Local Ability Peer Ability Cause code 0,CallFailCause Code= 501,CallFailCause String= null, ECT mask: 0] [SUB0]
  流程中多次用到RegistrantList消息處理機制,比較關鍵的一個地方是TelephonyConnection裡,在外撥(或者來電)設置連接的時候注冊了一個消息 getPhone().registerForPreciseCallStateChanged(mHandler,MSG_PRECISE_CALL_STATE_CHANGED, null);當收到這個消息的時候會調用updateState()更新狀態。 updateState 在Telephony更新call的狀態的時候不同的狀態對應不同的方法,如setActiveInternal() \\ 圖7 ims call state update(簡圖) 上圖也印證了之前說的,雖然層次上packages疊在framework上面,但實際上他們並不是嚴格按照相鄰的順序去調用。有可能隔著一層就調用了,也可能反復調用。 下圖以IMS電話接通狀態上報為例 \ \ 圖7 ims call state update(詳圖)

4. GSM與IMS MO流程的差異

  • 最大的區別是 IMS通話最後是通過高通私有代碼ims.app中撥出去的。
  • IMS MO也要經過GSMPhone,判斷到IMS網絡可用以後會調用到ImsPhone中的dial()方法。
  • ImsSenderRxr.java相當於CS call中的RIL.java,DIAL的命令也是在此發送
07-18 15:35:04.977 D/ImsSenderRxr( 4499): [0247]> DIAL[SUB0]
  • ImsPhone中的log是在radio log中打印,但是ImsSenderRxr的log是在main log打印。
  • 在ImsPhone的後續步驟中,會創建ImsPhoneConnection和ImsCall。
  對比圖 \\ 圖8 GSM MO和IMS MO 對比 箭頭指向為對應步驟,可以很明顯的看到Ims的MO流程在這部分更復雜一些。針對IMS網絡下的通話,專門建立了ImsPhoneConnection ImsCall。  

5. 分析問題的常用log

5.1InCallUI 前面說過InCallUI的界面顯示是以InCallState的狀態為根據的,而查看InCallState的關鍵字是Phone switching state:

  1. 14:42:29.721 I/InCall (24960): InCallPresenter - Phone switching state: NO_CALLS -> NO_CALLS
  2. 14:42:29.864 I/InCall (24960): InCallPresenter - Phone switching state: OUTGOING -> OUTGOING
  3. 14:42:30.262 I/InCall (24960): InCallPresenter - Phone switching state: OUTGOING -> PENDING_OUTGOING
  4. 14:42:31.194 I/InCall (24960): InCallPresenter - Phone switching state: PENDING_OUTGOING -> OUTGOING
  5. 14:42:34.975 I/InCall (24960): InCallPresenter - Phone switching state: OUTGOING -> INCALL
  6. 14:42:35.630 I/InCall (24960): InCallPresenter - Phone switching state: INCALL -> INCALL
InCallUI會根據這個狀態顯示界面信息。 這個狀態一般是跟CallList裡的call同步,但也有例外,就是會撤回狀態,關鍵字Undo the state change Log.i(this, "Undo the state change: " + newState + " -> " + mInCallState); 14:42:35.998 I/InCall (24960): InCallPresenter – Undo the state change: INCOMING ->NO_CALLS 這時候就出現了界面顯示和實際情況不一樣,上面的log就對應來電沒有界面。 注意:INCALL包括DISCONNECTING和DISCONNECTED,雖然這兩個是短暫的狀態,但是看到的最後幾個INCALL狀態可能call已經斷開了。   CallList中的onUpdate(),這是常見的看InCallUI中call的數量和狀態的地方,關鍵字CallList - onUpdate

  1. 17:13:21.514 I/InCall ( 4166): CallList - onUpdate - [Call_0, CONNECTING, [Capabilities:
  2. 17:13:21.568 I/InCall ( 4166): CallList - onUpdate - [Call_0, DIALING, [Capabilities: CAP
  3. 17:13:29.997 I/InCall ( 4166): CallList - onUpdate - [Call_0, ACTIVE, [Capabilities: CAPA
  4. 17:13:30.255 I/InCall ( 4166): CallList - onUpdate - [Call_0, ACTIVE, [Capabilities: CAPA
  5. 17:13:39.896 I/InCall ( 4166): CallList - onUpdate - [Call_1, CONNECTING, [Capabilities:]
  6. 17:13:43.179 I/InCall ( 4166): CallList - onUpdate - [Call_1, CONNECTING, [Capabilities:
  7. 17:13:43.266 I/InCall ( 4166): CallList - onUpdate - [Call_1, DIALING, [Capabilities: CA
  8. 17:13:43.451 I/InCall ( 4166): CallList - onUpdate - [Call_1, DIALING, [Capabilities: CA
  9. 17:13:43.471 I/InCall ( 4166): CallList - onUpdate - [Call_0, ONHOLD, [Capabilities: CAP
  10. 17:13:43.492 I/InCall ( 4166): CallList - onUpdate - [Call_0, ONHOLD, [Capabilities: CAP
5.2 Telecom 另外自android 6.0開始,Telecomm加了一個關鍵字為Event的log,會打印在Telecom內執行的關鍵步驟的log。打印出來如下

  1. 17:22:05.385 I/Telecom ( 769): Event: Call 8: CREATED, null
  2. 17:22:05.394 I/Telecom ( 769): Event: Call 8: SET_CONNECTING, ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService},
  3. 17:22:05.449 I/Telecom ( 769): Event: Call 8: AUDIO_ROUTE, EARPIECE
  4. 17:22:09.161 I/Telecom ( 769): Event: Call 8: BIND_CS, ComponentInfo{com.android.phone…
  5. 17:22:09.240 I/Telecom ( 769): Event: Call 8: CS_BOUND, ComponentInfo{com.android.phone…
  6. 17:22:09.241 I/Telecom ( 769): Event: Call 8: START_CONNECTION, tel:*****
  7. 17:22:09.399 I/Telecom ( 769): Event: Call 8: SET_DIALING, successful outgoing call
  8. 17:22:17.395 I/Telecom ( 769): Event: Call 8: SET_ACTIVE, active set explicitly
  9. 17:23:03.636 I/Telecom ( 769): Event: Call 8: REQUEST_DISCONNECT, null
  10. 17:23:04.211 I/Telecom ( 769): Event: Call 8: SET_DISCONNECTED, disconnected set explicitly> DisconnectCause [ Code: (LOCAL) Label: () Description: () Reason: (LOCAL) Tone: (27) ]
  11. 17:23:05.612 I/Telecom ( 769): Event: Call 8: DESTROYED, null
DisconnectCause是常用的查看通話斷開原因的log。 注意:Telecom的log是在system_process進程打印,用adb命令抓log的時候要加上-b system 5.3 MT 來電 在main log中我常看

  1. 00:01:21.154 D/Telephony( 1389): PstnIncomingCallNotifier: handleNewRingingConnection
如果這條看不到還可以查CallsManager中的setCallState,可以從狀態轉化中看到來電狀態。

  1. 14:42:34.888 I/Telecom ( 2920): CallsManager: setCallState DIALING -> ACTIVE, call: [100747014, DIALING,
5.4 MO DIAL IMS(PS)

  1. 19849: 07-05 18:30:35.325 D/ImsSenderRxr( 3325): [0056]> DIAL[SUB0]
  2. 20027: 07-05 18:30:35.365 D/ImsSenderRxr( 3325): [0056]< DIAL [SUB0
有DIAL回傳才表示撥號成功 GSM(CS)

  1. 2409: 09-08 17:29:56.206 D/RILJ ( 4017): [6301]> DIAL [SUB1]
  2. 2442: 09-08 17:29:56.250 D/RILJ ( 4017): [6301]< DIAL [SUB1]
5.5 HANGUP

  1. 07-18 15:32:37.899 D/ImsSenderRxr( 4499): [0240]> HANGUP[SUB0]
  2. 07-18 15:32:37.995 D/ImsSenderRxr( 4499): [0240]< HANGUP [SUB0]
5.6 IMS 在IMS網絡下通話的很多log是在main log中打印的,其中幾個比較關鍵的類包括ImsSenderRxr、ImsServiceSub,以這兩個類名為關鍵字在log中搜索就好了,或者以關鍵字/ImsSe把這兩個一起搜出來  

  1. 18:30:37.522 D/ImsSenderRxr( 3325): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [id=1,DIALING,toa=129,norm,mo,0,voc,noevp,,cli=1,,3Call Details = 3 2 callSubState 0 videoPauseState2 mediaId5 Local Ability Peer Ability Cause code 0,CallFailCause Code= 0,CallFailCause String= null, ECT mask: 0] [SUB0]
  2. 18:30:37.522 D/ImsServiceSub( 3325): Message received: what = 1
  3. 18:30:37.522 D/ImsServiceSub( 3325): >handleCalls
  4. 18:30:37.523 D/ImsServiceSub( 3325): handleCalls: dc = id=1,DIALING,toa=129,norm,mo,0,voc,noevp,,cli=1,,3Call Details = 3 2 callSubState 0 videoPauseState2 mediaId5 Local Ability Peer Ability Cause code 0,CallFailCause Code= 0,CallFailCause String= null, ECT mask: 0
  希望閱讀完對您有所幫助,也歡迎給出意見和建議。   //CS

  1. 09-09 10:52:42.093 D/RILJ ( 4017): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [SUB1] //PS 07-18 15:31:58.120
//PS

  1. D/ImsSenderRxr( 4499): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [id=1,DIALING,toa=129,norm,mo,0,voc,noevp,,cli=1,,3Call Details = 3 2 callSubState 0 videoPauseState2 mediaId0 Local Ability Peer Ability Cause code 0,CallFailCause Code= 501,CallFailCause String= null, ECT mask: 0] [SUB0]

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved