android_apps_frameworks_通话处理流程

一、拨打电话功能处理流程

1、拨打电话是从拨号后按下拨号键开始,此步的代码在/android/packages/apps/Contacts/src/com/android/contacts/目录的DialpadFragment.java文件中,相关代码如下:

    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”

2这个时候电话的数据已经流到OutgoingCallBroadcast.java中了。

OutgoingCallBroadcast.javaonCreate()方法中有:

    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”,那么根据所输入的号码是否是紧急号码进行转换,如果是紧急号码,则ACTIONIntent.ACTION_CALL_EMERGENCY,否则ACTIONIntent.ACTION_CALL,并启动转换ActivityInCallScreen.java

3InCallScreen.java依然在目录/packeges/Phone/src/com/android/phone下。

InCallScreenonCreate中调用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方法。

4PhoneUtils.java依然在目录/packeges/Phone/src/com/android/phone下。

    publicstatic int placeCall(...) {

    Connectionconnection;

    connection= PhoneApp.getInstance().mCM.dial(phone, numberToDial) ;

    }

继续追踪,在PhoneApp.java中发现,mCMCallManager.java类的一个对象,而CallManager.java是属于frameworks层的,所以,这个时候数据流已经进入frameworks.

5、进入/frameworks/base/telephony/java/com/android/internal/telephony目录。

CallManager.javadial()方法中,有:

    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()方法。

6、继续追踪GSMPhone.java,该类位于/frameworks/base/telephony/java/com/android/internal/telephony/gsm/下。

    GSMPhone.java

    GsmCallTrackermCT;

    publicGsmCall getForegroundCall() {

    returnmCT.foregroundCall;

    }

可以看出getForegroundCall()函数继续调用GsmCallTracker.javaforegroundCall属性。

7GsmCallTracker.java位于/frameworks/base/telephony/java/com/android/internal/telephony/gsm/.

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方法。

8、在GSMPhone.java

    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()方法。

9RIL.java

publicvoid
dial
(Stringaddress,intclirMode,Messageresult)
{
RILRequest
rr=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_DIALrequest号而申请的一个RILRequest对象.这个request号在java框架和rild库中共享(参考RILConstants.java中这些值的由来:)
RILRequest
初始化的时候,会连接名为rildsocket(也就是rilds_listen_event绑定的socket,初始化数据传输的通道.
rr.mp
Parcel对象,Parcel是一套简单的序列化协议,用于将对象(或对象的成员)序列化成字节流,以供传递参数之用.这里可以看到StringaddressintclirMode都是将依次序列化的成员.在这之前,rr初始化的时候,request号跟request的序列号(自动生成的递增数),已经成为头两个将被序列化的成员.这为后面的request解析打下了基础.
接下来是sendhandleMessage的流程,sendrr直接传递给另一个线程的handleMessage,handleMessage执行data=rr.mp.marshall()执行序列化操作,并将data字节流写入到rildsocket.

RIL对象负责把客户端的通话请求按照一定的格式发送给"rild"socket,至此,请求过程完毕。



二、来电处理流程

1PhoneApp.java在初始化时会实例CallNotifier对象,Callnotifier主要是对电话状态的监听,通知事件

PhoneApp创建一个CallNotifier:

notifier= CallNotifier.init(this, phone, ringer, mBtHandsfree, new CallLogAsync());

2Callnotifier实现对电话状态的监听

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();//状态监听

}

3registerForNotifications方法注册电话状态监听

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);

}

4mCM.registerForNewRingingConnection(this,PHONE_NEW_RINGING_CONNECTION, null); 监听来电,在handleMessage函数内处理

publicvoid handleMessage(Message msg) {

    switch(msg.what) {

    casePHONE_NEW_RINGING_CONNECTION:

    log("RINGING...(new)");

    onNewRingingConnection((AsyncResult)msg.obj);

    mSilentRingerRequested= false;

    break;

}

5、转到onNewRingingConnection处理来电,最后转到showIncomingCall函数启动InCallScreen界面,当然还有处理一些状态更新,响铃之类的。比如挂断流程如下。

三、挂断电话处理流程

有电话打入是RIL会通知CallNotifierCallNotifier会调用InCallScreen,上面有讨论,简单提一下。CallNotifier会调用InCallScreen代码 。

1InCallScreen会显示InCallTouchUI, InCallTouchUI 就是可以拖动接听和挂断的那个界面,这个页面持有一个SlidingTab控件,这个就是可以左右拖动的控件了。

InCallTouchUI实现了SlidingTab.OnTriggerListener,在该监听者的OnTrigge方法里面处理接听和挂断的动作,代码如下

onTrigger():

switch(whichHandle) {

caseANSWER_CALL_ID:

if(DBG) log("ANSWER_CALL_ID: answer!");

mInCallScreen.handleOnscreenButtonClick(R.id.incomingCallAnswer);

break;

......

}

2、进入InCallScreen.java:

handleOnscreenButtonClick()

caseR.id.incomingCallReject:

hangupRingingCall();

break;

3、进入PhoneUtils.java:

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;

}

4、进入GsmCall.java:

publicvoid hangup() throws CallStateException {

owner.hangup(this);

}

5、进入GsmCallTracker.java:

//*****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();

}

6、下面进入RIL.java,向rild发请求了,比如:

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);

}


你可能感兴趣的:(android_apps_frameworks_通话处理流程)