Android通話應(yīng)用設(shè)計(jì)

目錄

Android通話應(yīng)用設(shè)計(jì) 1

一欧漱、 背景 1

二、 應(yīng)用框架設(shè)計(jì) 1

三污桦、 常駐進(jìn)程開機(jī)喚醒 2

1. Phone進(jìn)程 2

2. TelecomServer進(jìn)程 3

四灵迫、 應(yīng)用間進(jìn)程交互 6

1. 進(jìn)程交互方式 6

2. Binder交互過(guò)程 6

五、 通話流程 7

1. 撥號(hào)流程 8

2. 電話狀態(tài)更新流程 9

3. 用戶掛斷電話流程 10

4. 來(lái)電流程 11

六阱持、 主要設(shè)計(jì)模式 12

1. 命令模式+觀察者模式的復(fù)合使用 13

2. MVP模式 13

3. 狀態(tài)機(jī) 14

a) CallAudioModeStateMachine 15

b) CallAudioRouteStateMachine 17

背景

以下內(nèi)容基于Android N code。

本文會(huì)從應(yīng)用框架魔熏、流程衷咽、設(shè)計(jì)模式幾個(gè)方面,講解Android手機(jī)中語(yǔ)音通話的應(yīng)用層設(shè)計(jì)蒜绽。

應(yīng)用框架設(shè)計(jì)

Android電話模塊是一個(gè)典型的分層結(jié)構(gòu)設(shè)計(jì)兵罢,如下:

分為應(yīng)用層、框架層(framework層滓窍,簡(jiǎn)稱fw)、RIL(Radio Interface Layer)巩那、modem吏夯。

其中:

應(yīng)用層:app應(yīng)用此蜈,包括Dialer.apk、TeleService.apk噪生、Telecom.apk裆赵、InCallUI.apk。其中其中Dialer.apk跑在com.android.dialer進(jìn)程中跺嗽,TeleService.apk跑在常駐進(jìn)程com.android.phone進(jìn)程中战授,Telecom.apk跑在system進(jìn)程中、InCallUI.apk跑在com.android.incallui進(jìn)程中桨嫁。

框架層:包括telephony fw植兰、telecom fw。Code分別位于frameworks/opt/telephony璃吧、frameworks/base/telecomm楣导。

RIL:位于User Libraries層中的HAL層,提供AP(Application Processor)和BP(Baseband Processor)之間的通信功能畜挨。RIL通常分為RILJ筒繁、RILC,RILJ即為java的RIL.java巴元,code位于框架層毡咏,RILC才是真正的RIL層。Android的RIL驅(qū)動(dòng)模塊,在hardware/ril目錄下夕土,一共分rild迂曲,libril.so以及l(fā)ibrefrence_ril.so三個(gè)部分。

Modem:位于BP臊旭,負(fù)責(zé)實(shí)際的無(wú)線通信能力處理

常駐進(jìn)程開機(jī)喚醒

Phone進(jìn)程

phone進(jìn)程是常駐進(jìn)程,它的喚醒過(guò)程如下:

在TeleService app code的AndroidManifest.xml中箩退,application的屬性配置了android:persistent=”true”和android:directBootAware=”true”离熏。系統(tǒng)開機(jī)時(shí),如果沒(méi)有解鎖戴涝,SystemServer會(huì)喚醒所有在AndroidManifest中配置了persistent=“true”且設(shè)置了directBootAware=”true”的應(yīng)用滋戳,解鎖后再喚醒persistent為true但是unaware的應(yīng)用。

在TeleService app起來(lái)后會(huì)把PhoneInterfaceManager這個(gè)phone service加入到ServiceManager中啥刻。應(yīng)用可以通過(guò)TelephonyManager.java中封裝好的接口調(diào)用里面的方法奸鸯。

TelecomServer進(jìn)程

telecom app模塊由于跑在system進(jìn)程中,也會(huì)一開機(jī)就被喚醒可帽。各個(gè)應(yīng)用可以調(diào)用的TelecomManager的server端TelecomService也會(huì)在同一時(shí)間加入ServiceManager的services里娄涩。過(guò)程如下:

其時(shí)序圖如下:

ContextImpl會(huì)保存一份system services的緩存,應(yīng)用可以通過(guò)Context#getSystemService(name)來(lái)獲取這些system service如TelecomService等,其具體添加和獲取過(guò)程如下圖:

應(yīng)用間進(jìn)程交互

進(jìn)程交互方式

通話過(guò)程是一個(gè)多進(jìn)程交互的過(guò)程蓄拣,主要進(jìn)程有dialer進(jìn)程扬虚、phone進(jìn)程、telecom進(jìn)程(system)球恤、incallui進(jìn)程辜昵、audio進(jìn)程。其中

dialer進(jìn)程:負(fù)責(zé)撥號(hào)咽斧。

phone進(jìn)程:負(fù)責(zé)通話邏輯堪置,如實(shí)際向RIL撥號(hào)、掛電話张惹,及電話狀態(tài)如撥號(hào)舀锨、振鈴、接通等的變更诵叁。

telecom進(jìn)程(system進(jìn)程雁竞,本文為了描述稱為telecom進(jìn)程):負(fù)責(zé)邏輯控制,是溝通各個(gè)進(jìn)程交互的橋梁拧额。

incallui進(jìn)程:負(fù)責(zé)通話界面顯示碑诉。

audio進(jìn)程:負(fù)責(zé)通話聲音的傳輸。

上面五個(gè)進(jìn)程間通信都是通過(guò)Binder侥锦,只有phone進(jìn)程和RIL間的交互是通過(guò)socket进栽,如下圖:

Binder交互過(guò)程

各進(jìn)程間主要通過(guò)aidl進(jìn)行交互,其中telecom進(jìn)程維護(hù)向系統(tǒng)注冊(cè)了的TelecomService恭垦,audio進(jìn)程維護(hù)了向系統(tǒng)注冊(cè)了的AudioService快毛,其它進(jìn)程可以通過(guò)TelecomManager.java和AudioManager.java封裝好的接口和它們交互。

下圖描述了實(shí)現(xiàn)各進(jìn)程交互的aidl:

而它們實(shí)際的交互過(guò)程如下圖:

可以看到:

撥號(hào)和來(lái)電都是dialer和phone進(jìn)程調(diào)用TelecomManager的方法最后由位于telecom進(jìn)程的TelecomService來(lái)實(shí)現(xiàn)番挺。

Telecom進(jìn)程分別通過(guò)IConnectionService.aidl和IInCallService.aidl來(lái)控制phone進(jìn)程和Incallui進(jìn)程唠帝。而phone進(jìn)程和Incallui進(jìn)程通過(guò)IConnectionServiceAdapter.aidl和IInCallAdapter.aidl來(lái)通知telecom進(jìn)程需要變更。

通話流程

因?yàn)槭欠謱咏Y(jié)構(gòu)玄柏,來(lái)電襟衰、掛斷是從上到下,而來(lái)電和電話狀態(tài)的變化則是從下到上粪摘。如下圖:

用戶的操作是通過(guò)APP->FW->RIL->Modem向下傳瀑晒,而網(wǎng)絡(luò)消息是通過(guò)Modem->RIL->FW->APP向上傳。除了分層結(jié)構(gòu)外比較主要就是進(jìn)程間交互徘意,上面有討論苔悦,下面將不再重復(fù)。

撥號(hào)流程

撥號(hào)是從上往下椎咧,即從APP到FW到RIL再到Modem玖详。

如下圖:

撥號(hào)盤通過(guò)TelecomManager的接口撥號(hào),telecom一邊向phone進(jìn)程請(qǐng)求撥號(hào),一邊通知incallui顯示撥號(hào)界面竹宋。

電話狀態(tài)更新流程

電話狀態(tài)更新從結(jié)構(gòu)上看是從下往上劳澄,通過(guò)一層層的監(jiān)聽和通知通過(guò)觀察者模式從Modem通知到RIL到FW到APP。

如下圖:

開機(jī)時(shí)蜈七,Phone進(jìn)程起來(lái),PhoneFactory會(huì)構(gòu)建Phone和其對(duì)應(yīng)的RILJ莫矗,Phone會(huì)構(gòu)建其對(duì)應(yīng)的CallTracker飒硅,CallTracker會(huì)向RILJ注冊(cè)call狀態(tài)變更的監(jiān)聽,RILJ通過(guò)Socket向RILC注冊(cè)監(jiān)聽作谚。撥號(hào)成功或者來(lái)電后Telephony會(huì)構(gòu)建一個(gè)封裝了telephony fw Connection的TeleponyConnection三娩,它在構(gòu)建時(shí)會(huì)向Phone注冊(cè)Call狀態(tài)變更,所以只要網(wǎng)絡(luò)端返回狀態(tài)更新就可以從底層一直通知到應(yīng)用層的phone進(jìn)程妹懒,再通過(guò)AIDL跨進(jìn)程更新到telecom進(jìn)程雀监,telecom再通知incallui更新界面。

用戶掛斷電話流程

掛斷電話眨唬,從用戶在通話界面點(diǎn)擊“掛斷”按鈕開始也是一個(gè)自上而下的過(guò)程:

來(lái)電流程

來(lái)電和狀態(tài)更新相比的不同點(diǎn)就是多了注冊(cè)來(lái)電消息接收的過(guò)程会前,注冊(cè)監(jiān)聽后通過(guò)觀察者模式從下而上通知到應(yīng)用來(lái)電。下面這張圖就是描述注冊(cè)來(lái)電消息的流程:

開機(jī)后phone進(jìn)程起來(lái)會(huì)根據(jù)手機(jī)的待機(jī)模式構(gòu)建Phone匾竿,每個(gè)Phone會(huì)創(chuàng)建一個(gè)處理關(guān)于語(yǔ)音通話的對(duì)象GsmCdmaCallTracker瓦宜,CallTracker會(huì)向RILJ注冊(cè)通話狀態(tài)變化的監(jiān)聽,RILJ會(huì)通用Socket向RIL層注冊(cè)監(jiān)聽岭妖。而當(dāng)Telephony APP監(jiān)聽到sim卡可用時(shí)會(huì)向該卡的Phone注冊(cè)來(lái)電監(jiān)聽临庇。這樣Modem收到來(lái)電消息傳到RIL到RILJ后,RILJ會(huì)通知CallTracker昵慌,CallTracker再通知監(jiān)聽它的Phone的監(jiān)聽者假夺。

主要設(shè)計(jì)模式

Android源碼中運(yùn)用了很多設(shè)計(jì)模式使整個(gè)系統(tǒng)設(shè)計(jì)很良好也很美觀,如上面介紹流程時(shí)頻繁涉及到的觀察者模式斋攀。下面介紹幾種通話模塊中運(yùn)用比較典型的設(shè)計(jì)模式已卷。

命令模式+觀察者模式的復(fù)合使用

Call狀態(tài)的各種變更都是通過(guò)觀察者模式來(lái)實(shí)現(xiàn),而telephony fw通過(guò)RIL向modem下發(fā)撥號(hào)接聽等命令是通過(guò)命令模式來(lái)實(shí)現(xiàn)蜻韭,下面介紹一下這兩種模式的復(fù)合使用悼尾。

先看圖:

其中把一個(gè)Phone的所有操作,如撥號(hào)肖方、接聽等封裝成一個(gè)Command闺魏,通過(guò)CallTracker這個(gè)Invoker去調(diào)用Command中的方法執(zhí)行如dial()、accept()俯画。Command執(zhí)行的結(jié)果返回給Receiver RegistrantList析桥。RegistrantList再通知向它注冊(cè)過(guò)的接收者(RegistrantList是Android封裝好的觀察者模式Subject的實(shí)現(xiàn),具體就不介紹了)。

MVP模式

Incallui通話界面的實(shí)現(xiàn)是典型的MVP模式泡仗,先看其類結(jié)構(gòu)圖埋虹,如下:

這個(gè)實(shí)現(xiàn)中疊用了兩層MVP設(shè)計(jì):

外面的一層:InCallPresenter為P,CallList為M娩怎,里面的一層結(jié)構(gòu)MVP做為V搔课。當(dāng)CallList有數(shù)據(jù)發(fā)生變化時(shí)通知InCallPresenter,InCallPresenter再通知View去更新截亦。

里面一層:P根據(jù)顯示內(nèi)容的不同分為CallCardPresenter爬泥、CallButtonPresenter、AnswerPresenter崩瓤、DialpadPresenter袍啡、VideoCallPresenter五部分,它們分別對(duì)應(yīng)的view為xxxFragment却桶,而M部分則是Call和TelecomAdapter境输,實(shí)際上是telecom fw的Call,上圖為了簡(jiǎn)單只畫了Call颖系。當(dāng)Call有更新時(shí)通知xxxPresenter更新View xxxFragment嗅剖,當(dāng)xxxFragment有用戶操作時(shí)通過(guò)其對(duì)應(yīng)的xxxPresenter更新Call。

下面簡(jiǎn)述第二層MVP模式中每一個(gè)MVP的功能:

CallCardPresenter和CallCardFragment:控制聯(lián)系人信息的顯示集晚,如聯(lián)系人頭像窗悯、姓名、電話號(hào)碼等偷拔。

CallButtonPresenter和CallButtonFragment:控制通話界面用戶可以點(diǎn)擊的功能button的顯示和交互蒋院,如靜音、揚(yáng)聲器莲绰、dtmf盤等欺旧。

AnswerPresenter和AnsewrFragment:控制來(lái)電動(dòng)畫和操作的顯示。

DialpadPresenter和DialpadFragment:控制dtmf內(nèi)容的顯示和用戶點(diǎn)擊數(shù)字的操作蛤签。

VideoCallPresenter和VideoCallFragment:控制視頻通話界面本機(jī)圖像窗口和對(duì)端圖像窗口的顯示辞友。

狀態(tài)機(jī)

Telecom app中控制音頻和audio交互的過(guò)程是通過(guò)狀態(tài)機(jī)StateMachine來(lái)實(shí)現(xiàn)的,分為CallAudioModeStateMacine和CallAudioRouteStateMachine震肮。其中:

CallAudioModeStateMacine:主要功能是向AudioManager發(fā)送setMode請(qǐng)求称龙,即設(shè)置聲音模式為normal還是ringtone還是incall。語(yǔ)音通話中只有設(shè)置了聲音模式為incall后戳晌,通話中才能聽到對(duì)方的聲音鲫尊,本機(jī)的聲音也才能傳輸?shù)綄?duì)端。網(wǎng)絡(luò)通話則設(shè)置聲音模式為communication沦偎。

CallAudioRouteStateMachine:主要功能是控制通話過(guò)程中對(duì)端聲音在本機(jī)的播放方式疫向,如聽筒咳蔚、耳機(jī)、揚(yáng)聲器搔驼、藍(lán)牙等谈火。

CallAudioModeStateMachine

先看CallAudioModeStateMachine的狀態(tài)圖,一張圖表示一個(gè)狀態(tài)對(duì)外的變更舌涨。

可以看到這個(gè)狀態(tài)機(jī)共有5總狀態(tài)糯耍,分別是UnFocusedState、RingingFocusState囊嘉、SimCallFocusState谍肤、OtherFocusState、SimCallFocusState哗伯,初始狀態(tài)為UnFocusedState。

Entry表示進(jìn)入這個(gè)狀態(tài)會(huì)做什么操作篷角,比如進(jìn)入SimCallFocusState會(huì)調(diào)用AudioManager.setMode(MODE_IN_CALL)焊刹,而進(jìn)入U(xiǎn)nFocusedState會(huì)調(diào)用AudioManager.setMode(MODE_NORMAL)。其中進(jìn)入每個(gè)狀態(tài)都會(huì)去setCallAudioRouteFocusState(xxx)恳蹲,這個(gè)是觸發(fā)CallAudioRouteStateMachine狀態(tài)機(jī)狀態(tài)變更的一個(gè)重要條件虐块,下面會(huì)講到。

Exit表示退出這個(gè)狀態(tài)時(shí)會(huì)做什么操作嘉蕾,如退出RingingFocusState會(huì)停止響鈴贺奠。

箭頭:表示從一個(gè)狀態(tài)切到另外一個(gè)狀態(tài)的觸發(fā)條件,比如手機(jī)待機(jī)狀態(tài)處于UnFocusState错忱,此時(shí)撥號(hào)就會(huì)進(jìn)入SimCallFocusState儡率,電話結(jié)束播放掛斷鈴聲時(shí)會(huì)進(jìn)入OtherFocusState,掛斷鈴聲播放后又沒(méi)有任何通話就會(huì)回到UnFocusedState以清。

CallAudioRouteStateMachine

狀態(tài)圖如下:

CallAudioRouteStateMachine總共有9種狀態(tài)儿普,分成4類:EarpieceRoute、HeadsetRoute掷倔、SpeakerRouter眉孩、BluetoothRoute。每類Route都有quiescent和active兩種狀態(tài)勒葱,BluetoothRoute多了ringing的狀態(tài)浪汪。初始狀態(tài)都是quiescent route,具體類別根據(jù)當(dāng)前手機(jī)所連設(shè)備來(lái)確定凛虽。如果當(dāng)前手機(jī)藍(lán)牙可用死遭,初始狀態(tài)為QuiescentBluetoothRoute,如果當(dāng)前手機(jī)藍(lán)牙不可用但有耳機(jī)插入則為QuiescentHeadsetRoute涩维,否則為QuiescentEarpieceRoute殃姓。當(dāng)quiescent狀態(tài)收到CallAudioModeStateMachine發(fā)送過(guò)來(lái)的ACTIVE_FOCUS或RINGING_FOCUS時(shí)轉(zhuǎn)換到其對(duì)應(yīng)的active狀態(tài)或ringing狀態(tài)袁波,具體看上面的狀態(tài)圖。進(jìn)入active route時(shí)會(huì)根據(jù)當(dāng)前的狀態(tài)來(lái)處理speaker bluetooth的開關(guān)和前前的audio state蜗侈。比如進(jìn)入ActiveEarpieceRoute時(shí)會(huì)關(guān)掉speaker和bluetooth篷牌,audio state切為ROUTE_EARPIECE,進(jìn)入ActiveSpeakerRoute時(shí)會(huì)打開speaker關(guān)掉bluetooth踏幻,audio state切為ROUTE_SPEAKER枷颊。


原創(chuàng)內(nèi)容歡迎轉(zhuǎn)載,但請(qǐng)注明出處该面,謝謝夭苗!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市隔缀,隨后出現(xiàn)的幾起案子题造,更是在濱河造成了極大的恐慌,老刑警劉巖猾瘸,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件界赔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡牵触,警方通過(guò)查閱死者的電腦和手機(jī)淮悼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)揽思,“玉大人袜腥,你說(shuō)我怎么就攤上這事《ず梗” “怎么了羹令?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)儡湾。 經(jīng)常有香客問(wèn)我特恬,道長(zhǎng),這世上最難降的妖魔是什么徐钠? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任癌刽,我火速辦了婚禮,結(jié)果婚禮上尝丐,老公的妹妹穿的比我還像新娘显拜。我一直安慰自己,他們只是感情好爹袁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布远荠。 她就那樣靜靜地躺著,像睡著了一般失息。 火紅的嫁衣襯著肌膚如雪譬淳。 梳的紋絲不亂的頭發(fā)上档址,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音邻梆,去河邊找鬼守伸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛浦妄,可吹牛的內(nèi)容都是我干的尼摹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼剂娄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蠢涝!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起阅懦,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤和二,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后耳胎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體儿咱,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年场晶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怠缸。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诗轻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出揭北,到底是詐尸還是另有隱情扳炬,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布搔体,位于F島的核電站恨樟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏疚俱。R本人自食惡果不足惜劝术,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望呆奕。 院中可真熱鬧养晋,春花似錦、人聲如沸梁钾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)姆泻。三九已至零酪,卻和暖如春冒嫡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背四苇。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工孝凌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蛔琅。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓胎许,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親罗售。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辜窑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容