本流程圖基于MTK平臺 Android 7.0,普通來電,本流程只作為溝通學習使用
本篇博客主要來看看整個 IncallUI 界面的容器 InCallActivity
我們知道正常情況下 InCallActivity 的啟動分兩種情況,MO 和 MT 我們就以 MO 為例來看看它的啟動流程(MT其實也差不多) 
最關鍵的兩個地方:
1.//InCallController.connect 方法中通過binder 綁定到了InCallService 服務Intent intent = new Intent(InCallService.SERVICE_INTERFACE);2.//InCallPResenter.getInCallIntent 中指定了啟動的界面intent.setClass(mContext, InCallActivity.class);
通過上面的類圖關系我們可以知道,InCallActivity 是整個 incallUI 的容器,它控制著幾乎所有 fragment 的顯示和隱藏,然而 InCallPresenter 又控制著 InCallActivity 的創建和銷毀。InCallPresenter 還類似于一個狀態機,它控制并管理者大部分 與call 相關的狀態,incallUI 上面和 call 相關的界面變化都會通過 InCallPresenter 來收集和分發。
InCallActivity 的layout 是 incall_screen,然而 incall_screen 的所有代碼就只有上面那么6行,只定義了一個占滿全屏的 FrameLayout 里面什么子控件都沒有,那么復雜的incallUI又是怎么顯示出來的呢? 其實 InCallActivity 的作用就如我上面所說,針對界面顯示而言它只是一個容器,具體的界面實現是通過加載 CallCardFragment 來顯示的(onCreate–>internalResolveIntent–>showCallCardFragment(true)),下面我們就來簡單分析一下 CallCardFragment 吧。

部分說明:
call_card_fragment 是 CallCardFragment 的布局文件,它里面不僅包含很多控件,還include 了其它的布局文件CallCardFragment 中又包含了 AnswerFragment、DialpadFragment、CallButtonFragment、VideoCallFragment等一系列 fragmentCallCardPresenter 控制著整個界面的邏輯處理聲明:下圖為了說明,通過特別的代碼修改故意顯示部分在特殊條件下才會顯示的圖標,請不要被誤導。

這個布局文件整體是個 RelativeLayout 布局,可以分成上下兩個部分(對應于上圖):
這部分是一個垂直方向的 LinearLayout 布局,包含一個新的布局文件 primary_call_info 和 CallButtonFragment 界面,這里我們重點看一下 primary_call_info 布局文件信息。
整體是個垂直方向的 LinearLayout 布局:
第一行:callSubject,call的主題,通過call.getCallSubject方法拿到并顯示的字符串,一般都為空,如果為空則設置為不可見GONE。第二行:水平的 LinearLayout 布局,包含多個信息,1.workProfileIcon,工作賬戶圖標,通過call.hasproperty(PROPERTY_ENTERPRISE_CALL); 判讀是否有這個屬性決定顯示和隱藏,顯示在這行靠右下方、2.callStateIcon,sim卡圖標或者WiFicall 圖標,包括connection的狀態圖標,CallCardPresenter.getCallStateIcon 返回不為null則顯示、3.videoCallIcon,video通話圖標,如果是video通話則顯示(VideoUtils.isVideoCall(videoState))、4.callStateLabel,顯示當前call的狀態字符串,根據CallCardFragment.getCallStateLabelFromState方法來確定顯示的字符串(通過CallCardPresenter.getConnectionLabel來區分手機單卡和雙卡顯示的不同字符串),一直都會顯示,并且動態改變。第三行:一個RelativeLayout布局,包含兩個控件,1.name,顯示對方的名字或者電話號碼,一直顯示、2.photoSmall,顯示對方小頭像,顯示在這行最右邊,當底部大頭像顯示時,這個小頭像不顯示CallCardFragment.showContactContext。第四行:水平的 LinearLayout 包含了多個控件,1.hdAudioIcon,HD圖標,通過call.hasProperty(Details.PROPERTY_HIGH_DEF_AUDIO)判斷是否顯示、2.forwardIcon,呼叫轉接圖標,表示當前號碼是通過指定號碼轉接過來的,如果Call.getLastForwardedNumber不為null則顯示、3.電話類型label,比如: work,monile,sip等,是保存當前聯系人時用戶自己指定的、4.顯示來電號碼phoneNumber,如果當前來電不是已存聯系人,則name就顯示了電話號碼,此處就顯示地理位置,CallCardPresenter.getNumberForCall、5.elapsedTime,顯示當前電話接通后已經過去的時間,顯示在這行的最右邊。第五行:callTypeLabel,如果當前是SIP phone 的話顯示這個textview。這個在之前的博客中有詳細介紹,可以參考:Android N Phone_通話界面_CallButtonFragment 這篇博客。
下半部分就包含很多內容了,它們相互并列重疊,大部分通過代碼動態控制顯示和隱藏。
相關說明如下: 由上到下分別為:
answer_and_dialpad_container,是一個FrameLayout,我們的 AnswerFragmentr界面和 DialpadFragment界面通過 InCallActivity.getContainerIdForFragment 方法動態的顯示在這個控件上面,它可以覆蓋整個下半部分。secondary_call_info,include 了另外一個布局文件,顯示在下半部分的最底部,如果當前有 activity 的 call 和 hold 的 call ,則此處顯示 hold call 的信息,并且點擊會切換 activity 和 hold 狀態。manage_conference_call_button,include 了另外一個布局文件,顯示在整體的最底部,如果當前是會議電話則顯示,最終通過InCallActivity.createNewFragmentForTag去顯示ConferenceManagerFragment。floating_end_call_action_button,顯示在整體的底部居中,通話的掛斷按鈕。progressSpinner,ProgressBar進度條,通過 CallCardPresenter.maybeShowProgressSpinner 控制顯示和隱藏進度條VideoCallFragment,顯示在整個下半部分,布局文件video_call_fragment,通過 ViewStub占位符來加載具體的 layout 布局文件 video_call_views,通過 VideoCallFragment.inflateVideoUi 控制是否 inflate 具體的布局文件,從而控制VideoCallFragment 的顯示和隱藏,最終還是通過 call.getVideoState() 獲取當前的call是否是 videocall 來確定是否顯示的,ViewStub本身是不可見的。photoLarge,顯示大頭像占滿整個下半部分。voiceRecorderIcon,顯示錄音圖標,顯示在界面右邊。contact_context,包含一個 textview 和一個 listview,顯示聯系人交互信息,包括商業和個人,當 photoLarge 沒有顯示時才會顯示這些信息。顯示在整個下半部分。新聞熱點
疑難解答