標籤: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