Android源碼分析:Telephony部分–phone進程

來源:互聯網
上載者:User

標籤:android   blog   http   java   使用   strong   

Android源碼分析:Telephony部分–phone進程
紅狼部落格

com.android.phone進程

它就象個後台進程一樣,開機即運行並一直存在。它的代碼位於:packages/apps/Phone/src/com/android/phone

當有來電時,它會作出反應,如顯示UI和鈴聲提示;當在通話過程中,它顯示InCallScreen; 當要撥號時ITeleohony的介面調用最終到Phone進程,然後由它去與PhoneFactory建立的GSMPhone或CDMAPhone進行互動;通話記錄也是由Phone添加到資料庫裡的。

 

最重要的一個類是PhoneAPP,繼承自Application,是頂層Phone應用程式類,包含了:

Phone phone;
CallNotifier notifier;
Ringer ringer;
BluetoothHandsfree mBtHandsfree;
PhoneInterfaceManager phoneMgr;

//此處省略了部分成員變數代碼

private InCallScreen mInCallScreen;

//此處省略了部分成員變數代碼

private Activity mPUKEntryActivity;
private ProgressDialog mPUKEntryProgressDialog;

//此處省略了部分成員變數代碼

private KeyguardManager mKeyguardManager;
private StatusBarManager mStatusBarManager;
private int mStatusBarDisableCount;
private AccelerometerListener mAccelerometerListener;

在froyo版本中, PhoneApp實現了檢測人臉對打電話時的幹擾,它使用了距離感應器來判斷臉部皮膚與螢幕的距離。

 

 

CallNotifier

CallNotifier是一個Handler,它為PhoneApp處理各個主動上報來的一些訊息。它監聽來自Telephony層phone狀態變化和其它各種事件,從而作出反應 如各種UI行為:啟動鈴音播放和來電顯示UI、播放正在通話時的來電提示、更新狀態列提示(通過NotificationMgr)、通話記錄添加等。

 

在PhoneBase中提供了一些RegistrantList,CallNotifier可以將自己作為一個感興趣者註冊進去,這樣,當狀態變化時,CallNotifier將得到通知,然後線上程中對其處理,作出UI方面的響應。在其建構函式中可以看出它處理的訊息事件類別目錄,下面的代碼列出了部分要處理的訊息種類(沒有列出針對CDMA或GSM特定類型的訊息):

mPhone.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);

mPhone.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null);

mPhone.registerForDisconnect(this, PHONE_DISCONNECT, null);

mPhone.registerForUnknownConnection(this, PHONE_UNKNOWN_CONNECTION_APPEARED, null);

mPhone.registerForIncomingRing(this, PHONE_INCOMING_RING, null);

當有PHONE_NEW_RINGING_CONNECTION類型訊息到來時,意味著一個RINGING或WAITING的串連(connection)出現,此時handleMessage函數調用onNewRingingConnection來處理。後者先檢查Settings裡的設定是否可以電話中;然後進行響鈴(見InCallTonePlayer)和顯示InCallScreen的UI,見PhoneUtils.showIncomingCallUi()和PhoneApp.displayCallScreen()兩個函數。

通話過程中的鈴音提示由線程類InCallTonePlayer完成。

當有PHONE_INCOMING_RING類型的訊息到來時,意味著RIL層受到Ring,此處播放鈴音。它使用的是Ringer.ring()函數,它會建立一個線程去播放鈴音(見Ringer.makeLooper函數)。

當收到PHONE_STATE_CHANGED訊息時,表明Phone的狀態發生了改變,比如響鈴後接通了電話,此時處理函數是onPhoneStateChanged,比如再次確認停止鈴音、更新狀態列列的狀態通知等。

當收到PHONE_DISCONNECT訊息時,表明電話串連已掛斷或RingCall斷掉。其處理函數是onDisconnect。它清理現場諸如音頻通道恢複、來電響鈴的停止確認、對InCallScreen的UI清理、若有未接電話須在狀態列顯示等。

 

PhoneInterfaceManager

它繼承自 Itelephony.Stub,實現了伺服器側的 ITelephony介面,其介面定義見檔案:

frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl

TelephonyManager作為用戶端通過Binder與其互動。

NotificationMgr

NotificationMgr以靜態成員函數的方式為PhoneApp用於Phone進程在狀態列中通知使用者訊息的功能,諸如:有未接電話、正在通話、是否靜音等資訊。它使用系統提供的API類NotificationManager和StatusBarManager完成通知功能。每項通知對應著通知、更新通知和取消通知的函數。當收到Message時,PhoneApp的Handler的handleMessage會使用NotificationMgr更新狀態列資訊。下面的程式碼片段用於更新狀態列的的提示資訊:

case EVENT_UPDATE_INCALL_NOTIFICATION:
NotificationMgr.getDefault().updateInCallNotification();//通話提示
break;
case EVENT_DATA_ROAMING_DISCONNECTED:
NotificationMgr.getDefault().showDataDisconnectedRoaming();//因漫遊資料連線斷開提示
break;
case EVENT_DATA_ROAMING_OK:
NotificationMgr.getDefault().hideDataDisconnectedRoaming();//隱藏漫遊斷開提示
break;

是否有未接電話的提示則是在PhoneApp建立NotificationMgr對象並調用其初始化函數時檢查提示的。

 

InCallScreen

它是手機正在通話時的Activity。當有來電、開始撥號或正在通話時,啟動並執行是該Activity,UI介面是其對應的View:

// Inflate everything in incall_screen.xml and add it to the screen.
setContentView(R.layout.incall_screen);

在其OnCreate函數中將自己指定為PhoneApp的InCallScreen:

app.setInCallScreenInstance(this);

 

InCallScreen需要處理來電時跳過鍵盤鎖直接可以電話中、是否有耳機插入的情況、是否用藍芽電話中、需要監聽並維護更新通話狀態並顯示給使用者、需要支援通話過程中的某些功能(如發送DTMF、電話會議、分離一路通話)操作、OTA Call等。

CallCard是InCallScreen中的一個call(可能是當前的Call或保持的Call或來電Call)。

當需要電話中或撥打到電話時,上層發來intent,然後InCallScreen收到intent時它的InCallScreen.onNewIntent函數被調用,解析intent,要麼調用placeCall撥打到電話,要麼調用internalAnswerCall電話中。

應用程式可發出Intent進行撥打電話,如在TwelveKeyDialer.java中進行呼叫時,去建立一個Intent:

void placeCall() {

final String number = mDigits.getText().toString();

boolean sendEmptyFlash = false;

Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,

Uri.fromParts(“tel”, number, null));

if (number == null || !TextUtils.isGraphic(number)) {

// There is no number entered.

if (phoneIsCdma() && phoneIsOffhook()) {

// We only want to send this empty flash extra if we’re CDMA and the

// phone is offhook (don’t want to send if ringing or dialing)

intent.putExtra(EXTRA_SEND_EMPTY_FLASH, true);

sendEmptyFlash = true;

} else {

playTone(ToneGenerator.TONE_PROP_NACK);

return;

}

}

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(intent);

在phone程式中OutgoingCallBroadcaster(檔案OutgoingCallBroadcaster.java)的包含一個內部類OutgoingCallReceiver,由它接收撥打電話Intent,然後經過轉換後再發送出去,由上述的InCallScreen接收處理,顯示撥號介面並進行呼叫等。

如OutgoingCallBroadcaster所說,它接收 CALL 和CALL_PRIVILEGED 兩種Intents,然後廣播出ACTION_NEW_OUTGOING_CALL intent,讓別的應用程式有機會去監視這些intent,最後這些呼叫intent又被自己收到轉換,啟動InCallScreen.

下面的代碼是Intent轉換,然後Intent被InCallScreen接收:

Intent newIntent = new Intent(Intent.ACTION_CALL, uri);

newIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);

PhoneUtils.checkAndCopyPhoneProviderExtras(intent, newIntent);

newIntent.setClass(context, InCallScreen.class);

newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

if (DBG) Log.v(TAG, “doReceive(): calling startActivity: ” + newIntent);

context.startActivity(newIntent);

}

這樣做的目的是

InCallTouchUi:

通話過程中的按鈕功能以及來電接聽時的滑動接聽功能。

 

ManageConferenceUtils:管理多方通話的工具,包括部分UI元素。藉助PhoneUtils實現其功能。

 

DTMFTwelveKeyDialer:通話狀態時的撥號盤,用於發送DTMF。

DTMFTwelveKeyDialerView:DTMF撥號視圖布局類。

InCallControlState維護著一些狀態資訊,諸如是否Enable了Speaker聲音免提、是否可以添加新的一路通話等等。它是MVC模式的資料部分。

InCallMenu是通話狀態菜單,裡麵包含各個功能表項目:

InCallMenuItemView mManageConference;
InCallMenuItemView mShowDialpad;
InCallMenuItemView mEndCall;
InCallMenuItemView mAddCall;
InCallMenuItemView mSwapCalls;
InCallMenuItemView mMergeCalls;
InCallMenuItemView mBluetooth;
InCallMenuItemView mSpeaker;
InCallMenuItemView mMute;
InCallMenuItemView mHold;
InCallMenuItemView mAnswerAndHold;
InCallMenuItemView mAnswerAndEnd;
InCallMenuItemView mAnswer;
InCallMenuItemView mIgnore;

InCallMenuItemView繼承自TextView,代表著手機處在通話狀態時的功能表項目。每個功能表項目保護一個文本,一個可選的“綠燈”,代表著開啟/關閉;在文本上面的可以有可選的表徵圖。其成員函數可以給它們賦值。當它們被點擊後,在函數InCallScreen.handleOnscreenButtonClick或InCallScreen.onClick中得到調用。前者用於InCallTouchUi上的點擊事件。

InCallScreen的成員函數

registerForPhoneStates:用於註冊InCallScreen對哪些狀態感興趣。對於GSM手機,則註冊了這些:

mPhone.registerForPreciseCallStateChanged(mHandler, PHONE_STATE_CHANGED, null);
mPhone.registerForDisconnect(mHandler, PHONE_DISCONNECT, null);
mPhone.registerForMmiInitiate(mHandler, PhoneApp.MMI_INITIATE, null); mPhone.registerForMmiComplete(mHandler, PhoneApp.MMI_COMPLETE, null);
mPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null);

當狀態變化收到Message後,由mHandler來響應處理。

 

應用程式Dialer/Contacts

Dialer程式在packages/apps/Contacts中,見DialtactsActivity,它繼承自TabActivity類,擁有四個Tab:Dialer、Call log、 Contacts和Favorites四個tab。通過實現介面 TabHost.OnTabChangeListener在各個tab之間切換。

本文連結地址: http://www.redwolf-blog.com/?p=1095

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.