dialButtonPressed(){
.........
finalString number = mDigits.getText().toString();
startActivity(newDialNumberIntent(number));
mDigits.getText().clear();
finish();
}
代码中newDialNumberIntent()方法定义如下:
privateIntent newDialNumberIntent(String number) {
finalIntent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, Uri.fromParts("tel", number, null));
.............
}
从newDialNumberIntent的定义可以看出,当拨号键按下以后,DialpadFragment会启动一个特定的组件,该组件的ACTION为:ACTION_CALL_PRIVILEGED,经过查找,该ACTION启动的组件是目下:/androidsourcecode/packeges/Phone/的一个文件,在该文件下的AndroidMenifest.xml中可以查到:“ACTION_CALL_PRIVILEGED”启动的Activity的名字是:PrivilegedOutgoingCallBroadcast,但是我们到/android/sourcecode/packeges/Phone/src/....目下并找不到该文件,因为该文件在AndroidMenifest.xml中标记有点特殊: <activity-alias/>,这个标签的意思是这个Activity是另一个Activity的别名,真实的Activity在标签中用“android:targetActivity =OutgoingCallBroadcast”标出,所以“ACTION_CALL_PRIVILEGED”启动的PrivilegedOutgoingCallBroadcast所对应的真实“身份”是“OutgoingCallBroadcast”。
在OutgoingCallBroadcast.java的onCreate()方法中有:
protectedvoid onCreate(Bundle icicle) {
.......
Intentintent = getIntent();
........
Stringaction = intent.getAction();
.......
finalboolean emergencyNum = (number != null) && PhoneNumUtils.isEmergencyNumbernumber);//判断号码是否是紧急号码
.......
if(Intent.ACTION_CALL_PRIVILEGED.equals(action)) {
action= emergencyNum ? Intent.ACTION_CALL_EMERGENCY Intent.ACTION_CALL;
intent.setAction(action);
}
.......
intent.setClass(this,InCallScreen.class);
startActivity(intent);
}
在这个方法中,判断如果所收到的ACTION是“ACTION_CALL_PRIVILEGED”,那么根据所输入的号码是否是紧急号码进行转换,如果是紧急号码,则ACTION=Intent.ACTION_CALL_EMERGENCY,否则ACTION=Intent.ACTION_CALL,并启动转换Activity:InCallScreen.java
InCallScreen的onCreate中调用initInCallScreen初始化打电话界面,并调用registerForPhoneStates注册电话状态监听.
在onNewIntent()方法中有:
protectedvoid onNewIntent(Intent intent) {
..........
Stringaction= intent.getAction();
..........
elseif (action.equals(Intent.ACTION_CALL) || action.equals(Intent.ACTION_CALL_EMERGENCY)) {
..........
InCallInitStatusstatus = placeCall(intent);
}
}
//placeCall
privateInCallInitStatus placeCall(Intent intent) {
..............
intcallStatus = PhoneUtils.placeCall(........);
}
InCallScreen.java中的placeCall方法调用PhoneUtils.java文件的placeCall方法。
publicstatic int placeCall(...) {
Connectionconnection;
connection= PhoneApp.getInstance().mCM.dial(phone, numberToDial) ;
}
继续追踪,在PhoneApp.java中发现,mCM是CallManager.java类的一个对象,而CallManager.java是属于frameworks层的,所以,这个时候数据流已经进入frameworks.
在CallManager.java的dial()方法中,有:
publicConnection dial(Phone phone, String dialNumber) throws CallState Exception {
PhonebasePhone = getPhoneBase(phone);
Connectionresult;
result= basePhone.dial(dialString);
........
}
privatestatic Phone getPhoneBase(Phone phone) {
if(phone instanceof PhoneProxy) {
returnphone.getForegroundCall().getPhone();
}
returnphone;
}
PhoneBase.java抽象类实现了接口Phone.java,而GSMPhone.java又实现了抽象类PhoneBase,所以上述代码中:phone.getForegroundCall()实际相当于GSMPhone对象执行了getForegroundCall()方法。
GSMPhone.java:
GsmCallTrackermCT;
publicGsmCall getForegroundCall() {
returnmCT.foregroundCall;
}
可以看出getForegroundCall()函数继续调用GsmCallTracker.java的foregroundCall属性。
GsmCallTracker.java:
GSMCallforegroundCall = new GSMCall(this);
GsmCallTracker.java:GSMCall foregroundCall = new GSMCall(this);
打开GSMCall.java,找到getPhone()方法,发现:
GSMCallTrackerowner;
publicPhone getPhone() {
returnowner.phone;
}
而在GSMCallTracker.java中有如下声明:
GSMPhonephone;
到此,我们得出一下结论:第5部分代码所返回的就是GSMPhone的对象,进一步可以得出,第5部分的代码即是调用了GSMPhone对象的dial方法。
GSMCallTrackermCT;
publicConnection dial(String dialString) throws CallStateException {
returndial(dialString, null);
}
publicConnection dial(String dialString, UUSInfo uusInfo) throws CallStaeException {
.......
mCT.dial(.......);
}
继续调用GSMCallTracker.java中的dial()方法:
GSMCallTracker.java:
GSMCallTracker(GSMPhonephone) {
cm= phone.mCM;
}
Connectiondial(String dialString, int clirMode, UUSInfo uusInfo) {
cm.dial(........);
}
追踪mCM,发现:
publicCommandsInterface mCM;
所以GSMCallTracker持有CommandsInterface对象,即RIL.Java类的对象,所以"cm.dial(....)"即是调用RIL类对象的dial()方法。
publicvoid
dial(Stringaddress,intclirMode,Messageresult)
{
RILRequestrr=RILRequest.obtain(RIL_REQUEST_DIAL,result);
rr.mp.writeString(address);
rr.mp.writeInt(clirMode);
if(RILJ_LOGD)riljLog(rr.serialString()+">"+requestToString(rr.mRequest));
send(rr);
}
rr是以RIL_REQUEST_DIAL为request号而申请的一个RILRequest对象.这个request号在java框架和rild库中共享(参考RILConstants.java中这些值的由来:))
RILRequest初始化的时候,会连接名为rild的socket(也就是rild中s_listen_event绑定的socket),初始化数据传输的通道.
rr.mp是Parcel对象,Parcel是一套简单的序列化协议,用于将对象(或对象的成员)序列化成字节流,以供传递参数之用.这里可以看到Stringaddress和intclirMode都是将依次序列化的成员.在这之前,rr初始化的时候,request号跟request的序列号(自动生成的递增数),已经成为头两个将被序列化的成员.这为后面的request解析打下了基础.
接下来是send到handleMessage的流程,send将rr直接传递给另一个线程的handleMessage,handleMessage执行data=rr.mp.marshall()执行序列化操作,并将data字节流写入到rildsocket.
RIL对象负责把客户端的通话请求按照一定的格式发送给"rild"socket,至此,请求过程完毕。
PhoneApp创建一个CallNotifier:
notifier= CallNotifier.init(this, phone, ringer, mBtHandsfree, new CallLogAsync());
privateCallNotifier(PhoneApp app, Phone phone, Ringer ringer,BluetoothHandsfree btMgr, CallLogAsync callLog) {
mApplication= app;
mCM= app.mCM;
mCallLog= callLog;
mAudioManager= (AudioManager)mApplication.getSystemService(Context.AUDIO_SERVICE);
registerForNotifications();//状态监听
}
privatevoid registerForNotifications() {
mCM.registerForNewRingingConnection(this,PHONE_NEW_RINGING_CONNECTION, null);
mCM.registerForPreciseCallStateChanged(this,PHONE_STATE_CHANGED, null);
mCM.registerForDisconnect(this,PHONE_DISCONNECT, null);
mCM.registerForUnknownConnection(this,PHONE_UNKNOWN_CONNECTION_APPEARED, null);
mCM.registerForIncomingRing(this,PHONE_INCOMING_RING, null);
mCM.registerForCdmaOtaStatusChange(this,EVENT_OTA_PROVISION_CHANGE, null);
mCM.registerForCallWaiting(this,PHONE_CDMA_CALL_WAITING, null);
mCM.registerForDisplayInfo(this,PHONE_STATE_DISPLAYINFO, null);
mCM.registerForSignalInfo(this,PHONE_STATE_SIGNALINFO, null);
mCM.registerForInCallVoicePrivacyOn(this,PHONE_ENHANCED_VP_ON, null);
mCM.registerForInCallVoicePrivacyOff(this,PHONE_ENHANCED_VP_OFF, null);
mCM.registerForRingbackTone(this,PHONE_RINGBACK_TONE, null);
mCM.registerForResendIncallMute(this,PHONE_RESEND_MUTE, null);
}
publicvoid handleMessage(Message msg) {
switch(msg.what) {
casePHONE_NEW_RINGING_CONNECTION:
log("RINGING...(new)");
onNewRingingConnection((AsyncResult)msg.obj);
mSilentRingerRequested= false;
break;
}
有电话打入是RIL会通知CallNotifier,CallNotifier会调用InCallScreen,上面有讨论,简单提一下。CallNotifier会调用InCallScreen代码 。
InCallTouchUI实现了SlidingTab.OnTriggerListener,在该监听者的OnTrigge方法里面处理接听和挂断的动作,代码如下
onTrigger():
switch(whichHandle) {
caseANSWER_CALL_ID:
if(DBG) log("ANSWER_CALL_ID: answer!");
mInCallScreen.handleOnscreenButtonClick(R.id.incomingCallAnswer);
break;
…......
}
handleOnscreenButtonClick():
caseR.id.incomingCallReject:
hangupRingingCall();
break;
staticboolean hangup(Call call) {
try{
CallManagercm = PhoneApp.getInstance().mCM;
if(call.getState() == Call.State.ACTIVE &&cm.hasActiveBgCall()) {
//handle foreground call hangup while there is background call
log("-hangup(Call): hangupForegroundResumeBackground...");
cm.hangupForegroundResumeBackground(cm.getFirstActiveBgCall());
}else {
log("-hangup(Call): regular hangup()...");
call.hangup();
}
returntrue;
}catch (CallStateException ex) {
Log.e(LOG_TAG,"Call hangup: caught " + ex, ex);
}
returnfalse;
}
publicvoid hangup() throws CallStateException {
owner.hangup(this);
}
//*****Called from GsmCall
/*package */ void
hangup(GsmCall call) throws CallStateException {
if(call.getConnections().size() == 0) {
thrownew CallStateException("no connections in call");
}
if(call == ringingCall) {
if(Phone.DEBUG_PHONE) log("(ringing) hangup waiting orbackground");
cm.hangupWaitingOrBackground(obtainCompleteMessage());
}else if (call == foregroundCall) {
if(call.isDialingOrAlerting()) {
if(Phone.DEBUG_PHONE) {
log("(foregnd)hangup dialing or alerting...");
}
hangup((GsmConnection)(call.getConnections().get(0)));
}else {
hangupForegroundResumeBackground();
}
}else if (call == backgroundCall) {
if(ringingCall.isRinging()) {
if(Phone.DEBUG_PHONE) {
log("hangupall conns in background call");
}
hangupAllConnections(call);
}else {
hangupWaitingOrBackground();
}
}else {
thrownew RuntimeException ("GsmCall " + call +
"doesnot belong to GsmCallTracker " + this);
}
call.onHangupLocal();
phone.notifyPreciseCallStateChanged();
}
publicvoid hangupForegroundResumeBackground (Message result) {
RILRequestrr
=RILRequest.obtain(
RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
result);
if(RILJ_LOGD) riljLog(rr.serialString() + "> " +requestToString(rr.mRequest));
send(rr);
}