您的位置:首页 > 移动开发 > Android开发

Android呼出电话流程(原)

2017-04-20 15:45 387 查看

一、应用层的流程

1.1、拨号盘初步处理

[java] view
plain copy

@DialpadFragment.java

public void dialButtonPressed() {

//得到号码

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

//得到拨号的Intent

final Intent intent = ContactsUtils.getCallIntent(number,

(getActivity() instanceof DialtactsActivity ?

((DialtactsActivity)getActivity()).getCallOrigin() : null));

startActivity(intent);

mClearDigitsOnStop = true;

getActivity().finish();

}

来看上面得到Intent的过程:

[java] view
plain copy

@ContactsUtils.java

public static Intent getCallIntent(String number, String callOrigin) {

用号码构建一个类似tel:10086的Uri

return getCallIntent(getCallUri(number), callOrigin);

}

public static Intent getCallIntent(Uri uri, String callOrigin) {

final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, uri);

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

if (callOrigin != null) {

intent.putExtra(DialtactsActivity.EXTRA_CALL_ORIGIN, callOrigin);

}

return intent;

}

这个过程可以看出,发出的Intent由一下几个结构组成:

1、Action为:ACTION_CALL_PRIVILEGED,(android.intent.action.CALL_PRIVILEGED);

2、Flag为:FLAG_ACTIVITY_NEW_TASK;

3、号码Uri为:tel:10086

然后经过startActivity发送出去。那么是那个Activity接受的呢?

1.2、号码初级处理阶段

这个过程主要针对紧急呼叫处理(OutgoingCallBroadcaster.java)。
在Phone模块的AndroidManifest.xml文件中有如下描述:

[java] view
plain copy

<activity-alias android:name="PrivilegedOutgoingCallBroadcaster"

android:targetActivity="OutgoingCallBroadcaster"

android:screenOrientation="nosensor"

android:permission="android.permission.CALL_PRIVILEGED">

<intent-filter>

<action android:name="android.intent.action.CALL_PRIVILEGED" />

<category android:name="android.intent.category.DEFAULT" />

<data android:scheme="tel" />

</intent-filter>

</activity-alias>

activity-alias说明这个节点描述的Activity是另一个Activity的别名,也就是说,当前的PrivilegedOutgoingCallBroadcaster是指向OutgoingCallBroadcaster的。

[java] view
plain copy

@OutgoingCallBroadcaster.java

protected void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.outgoing_call_broadcaster);

mWaitingSpinner = (ProgressBar) findViewById(R.id.spinner);

Intent intent = getIntent();

processIntent(intent);

}

继续往下看:

[java] view
plain copy

private void processIntent(Intent intent) {

final Configuration configuration = getResources().getConfiguration();

String action = intent.getAction();

String number = PhoneNumberUtils.getNumberFromIntent(intent, this);

//得到当前的号码

if (number != null) {

if (!PhoneNumberUtils.isUriNumber(number)) {

number = PhoneNumberUtils.convertKeypadLettersToDigits(number);

number = PhoneNumberUtils.stripSeparators(number);

}

} else {

}

//判断是否是紧急拨号

final boolean isExactEmergencyNumber =

(number != null) && PhoneNumberUtils.isLocalEmergencyNumber(number, this);

final boolean isPotentialEmergencyNumber =

(number != null) && PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, this);

if (Intent.ACTION_CALL_PRIVILEGED.equals(action)) {

if (isPotentialEmergencyNumber) {

//紧急拨号的action

action = Intent.ACTION_CALL_EMERGENCY;

} else {

//非紧急拨号的action

action = Intent.ACTION_CALL;

}

//重新设置Action,当前不是紧急呼叫,因此Action改为ACTION_CALL

intent.setAction(action);

}

if (Intent.ACTION_CALL.equals(action)) {

if (isPotentialEmergencyNumber) {

//判断不成立

}

//当前的callNow为false

callNow = false;

} else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {

//紧急呼叫的处理

} else {

}

Uri uri = intent.getData();

String scheme = uri.getScheme();

if (Constants.SCHEME_SIP.equals(scheme) || PhoneNumberUtils.isUriNumber(number)) {

//互联网通话的处理

}

//重新构建Intent

Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);

if (number != null) {

broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);

}

PhoneUtils.checkAndCopyPhoneProviderExtras(intent, broadcastIntent);

broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);

broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, uri.toString());

broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

//添加一个2秒的定时器,2秒内Intent没有收到的话,就显示一个进度条

mHandler.sendEmptyMessageDelayed(EVENT_OUTGOING_CALL_TIMEOUT,

OUTGOING_CALL_TIMEOUT_THRESHOLD);

//发送广播,而且指明了接收者是OutgoingCallReceiver

sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.OWNER,

PERMISSION, new OutgoingCallReceiver(),

null,

Activity.RESULT_OK,

number,

null);

}

这个过程其实就是对原始的Intent进行解析,对是否紧急呼叫进行不同的处理,对于正常的呼叫,需要重新构建Intent并发送出去。新的Intent构成:

Intent:ACTION_NEW_OUTGOING_CALL;

EXTRA_ALREADY_CALLED:false;

EXTRA_ORIGINAL_URI:号码的Uri;

发送目标:OutgoingCallReceiver;

这里所谓的目标OutgoingCallReceiver其实就是OutgoingCallBroadcaster.java中的内部类,我们直接来看他的接收地方:

[java] view
plain copy

public void onReceive(Context context, Intent intent) {

//去掉3妙的定时器

mHandler.removeMessages(EVENT_OUTGOING_CALL_TIMEOUT);

doReceive(context, intent);

finish();

}

public void doReceive(Context context, Intent intent) {

//这里的得到的是false

alreadyCalled = intent.getBooleanExtra(OutgoingCallBroadcaster.EXTRA_ALREADY_CALLED, false);

if (alreadyCalled) {

return;

}

//得到号码

number = getResultData();

final PhoneGlobals app = PhoneGlobals.getInstance();

//OTASP功能,CDMA制式支持

if (TelephonyCapabilities.supportsOtasp(app.phone)) {

}

//得到号码的Uri

originalUri = intent.getStringExtra( OutgoingCallBroadcaster.EXTRA_ORIGINAL_URI);

Uri uri = Uri.parse(originalUri);

//把字母转换为数字,比如:a-->2;d-->3;g-->4等

number = PhoneNumberUtils.convertKeypadLettersToDigits(number);

//把所有字符转换为数字

number = PhoneNumberUtils.stripSeparators(number);

//继续处理

startSipCallOptionHandler(context, intent, uri, number);

}

private void startSipCallOptionHandler(Context context, Intent intent, Uri uri, String number) {

//再次构建Intent

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

newIntent.putExtra(EXTRA_ACTUAL_NUMBER_TO_DIAL, number);

//把原始的Intent数据拷贝过来

//主要去解析EXTRA_GATEWAY_PROVIDER_PACKAGE和EXTRA_GATEWAY_URI,而这两项均为null

PhoneUtils.checkAndCopyPhoneProviderExtras(intent, newIntent);

//还有一个Intent

Intent selectPhoneIntent = new Intent(ACTION_SIP_SELECT_PHONE, uri);

//指明接受者是SipCallOptionHandler

selectPhoneIntent.setClass(context, SipCallOptionHandler.class);

//把上面的Intent放到EXTRA_NEW_CALL_INTENT中

selectPhoneIntent.putExtra(EXTRA_NEW_CALL_INTENT, newIntent);

//用新的task装载

selectPhoneIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

//发送,走起

context.startActivity(selectPhoneIntent);

}

上面的操作又是发起了一个Intent,构成有:

Action ---> ACTION_SIP_SELECT_PHONE

EXTRA_NEW_CALL_INTENT--->拨号的Intent,而且这个Intent的Action为ACTION_CALL

EXTRA_ACTUAL_NUMBER_TO_DIAL ---> 为拨号的号码

1.3、互联网通话处理阶段(SipCallOptionHandler.java)

我们来看上面Intent的接受过程,在SipCallOptionHandler中:

[java] view
plain copy

@SipCallOptionHandler.java

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

//得到Intent

Intent intent = getIntent();

String action = intent.getAction();

//外层的Intent

if (!OutgoingCallBroadcaster.ACTION_SIP_SELECT_PHONE.equals(action)) {

finish();

return;

}

//得到拨号的Intent

mIntent = (Intent) intent.getParcelableExtra(OutgoingCallBroadcaster.EXTRA_NEW_CALL_INTENT);

if (mIntent == null) {

finish();

return;

}

//是否支持互联网通话

boolean voipSupported = PhoneUtils.isVoipSupported();

mSipProfileDb = new SipProfileDb(this);

mSipSharedPreferences = new SipSharedPreferences(this);

mCallOption = mSipSharedPreferences.getSipCallOption();

Uri uri = mIntent.getData();

String scheme = uri.getScheme();

//得到通话的号码

mNumber = PhoneNumberUtils.getNumberFromIntent(mIntent, this);

//是否有网络

boolean isInCellNetwork = PhoneGlobals.getInstance().phoneMgr.isRadioOn();

//是否是tel:或者sip:的协议

boolean isKnownCallScheme = Constants.SCHEME_TEL.equals(scheme)||Constants.SCHEME_SIP.equals(scheme);

boolean isRegularCall = Constants.SCHEME_TEL.equals(scheme)

&& !PhoneNumberUtils.isUriNumber(mNumber);

if (!isKnownCallScheme) {

//异常处理,处理非法协议。

setResultAndFinish();

return;

}

if (!voipSupported) {

if (!isRegularCall) {

showDialog(DIALOG_NO_VOIP);

} else {

//当前不是IP通话,因此走这里

setResultAndFinish();

}

return;

}

setResultAndFinish();

}

继续看setResultAndFinish

[java] view
plain copy

private void setResultAndFinish() {

//放在主线程中操作

runOnUiThread(new Runnable() {

public void run() {

if (mOutgoingSipProfile != null) {

//互联网通话

if (!isNetworkConnected()) {

showDialog(DIALOG_NO_INTERNET_ERROR);

return;

}

createSipPhoneIfNeeded(mOutgoingSipProfile);

mIntent.putExtra(OutgoingCallBroadcaster.EXTRA_SIP_PHONE_URI,

mOutgoingSipProfile.getUriString());

if (mMakePrimary) {

mSipSharedPreferences.setPrimaryAccount(

mOutgoingSipProfile.getUriString());

}

}

if (mUseSipPhone && mOutgoingSipProfile == null) {

showDialog(DIALOG_START_SIP_SETTINGS);

return;

} else {

//正常拨号

PhoneGlobals.getInstance().callController.placeCall(mIntent);

}

finish();

}

});

}

上面可以看出,在SipCallOptionHandler.java文件中主要针对互联网通话进行处理,注意,这里的互联网通话和IP拨号不同

1.4、Phone模块其他的处理

主要作用是把intent解析为号码,同时得到拨号必须的Phone、CM、context等重要信息。

[java] view
plain copy

@CallController.java

public void placeCall(Intent intent)

{

//拨打

CallStatusCode status = placeCallInternal(intent);

//显示InCallScreen

mApp.displayCallScreen(!intent.getBooleanExtra(Constants.EXTRA_IS_VIDEO_CALL, false), forPlaceCall);

}

private CallStatusCode placeCallInternal(Intent intent) {

//得到号码

number = PhoneUtils.getInitialNumber(intent);

//得到Phone对象

phone = PhoneUtils.pickPhoneBasedOnNumber(mCM, scheme, number, sipPhoneUri);

//检查当前状态

okToCallStatus = checkIfOkToInitiateOutgoingCall(phone.getServiceState().getState());

//得到联系人的数据

Uri contactUri = intent.getData();

//拨号

int callStatus = PhoneUtils.placeCall(mApp,

phone,

number,

contactUri,

(isEmergencyNumber || isEmergencyIntent),

inCallUiState.providerGatewayUri);

}

上面得到了一个极其重要的变量,Phone变量,我们待会儿详细分析他的来历,这里只需要记住,Phone是通过PhoneUtils.pickPhoneBasedOnNumber()的方式得到的。

[java] view
plain copy

@PhoneUtils.java

public static int placeCall(Context context, Phone phone,

String number, Uri contactRef, boolean isEmergencyCall,

Uri gatewayUri) {

//得到app

final PhoneGlobals app = PhoneGlobals.getInstance();

//号码

numberToDial = number;

//拨号

connection = app.mCM.dial(phone, numberToDial);

//设置音频模式

setAudioMode();

return status;

}

上面的dial是通过app.mCM完成的,而这个mCM就是在PhoneGlobals.java中的onCreate时初始化的:

[java] view
plain copy

mCM = CallManager.getInstance();

说明dial是通过CallManager去执行dial的:

二、framework中的流程

[java] view
plain copy

@CallManager.java

public Connection dial(Phone phone, String dialString) throws CallStateException {

//得到basePhone

Phone basePhone = getPhoneBase(phone);

//根据当前的通话状态决定是否可以继续拨号

if (!canDial(phone)) {

throw new CallStateException("cannot dial in current state");

}

if ( hasActiveFgCall() ) {

//已经有电话存在

}

//拨号

result = basePhone.dial(dialString);

return result;

}

代码走到这里,就简化为调用一个Phone对象的dial方法了,此时要想继续往下分析,就必须知道这个Phone对象的来历。下面我们要做两件事:
1、查出Phone对象到底来自于哪里。
2、我们如何通过PhoneUtils.pickPhoneBasedOnNumber()的方式得到了这个Phone对象

2.1、Phone的来历

Phone在通话中扮演着极其重要的操作,我们来看一下Phone是怎样产生的。

我们知道,Phone模块进程第一个启动的类就是PhoneGlobals,他是在手机开机的过程中启动的。那么我们看一下他的初始化过程:

[java] view
plain copy

@PhoneGlobals.java

public void onCreate() {

//创建Phone对象

PhoneFactory.makeDefaultPhones(this);

//得到创建的Phone对象

phone = PhoneFactory.getDefaultPhone();

//初始化CallManager并把Phone对象注册给CallManager

mCM = CallManager.getInstance();

mCM.registerPhone(phone);

//初始化NotificationMgr

notificationMgr = NotificationMgr.init(this);

phoneMgr = PhoneInterfaceManager.init(this, phone);

//开启SIP服务

mHandler.sendEmptyMessage(EVENT_START_SIP_SERVICE);

//铃声初始化

ringer = Ringer.init(this);

//得到电源管理服务

mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);

//距离传感器

if (proximitySensorModeEnabled()) {

mAccelerometerListener = new AccelerometerListener(this, this);

}

//按键管理

mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);

//电源管理

mPowerManagerService = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));

//又是各种初始化

callController = CallController.init(this);

inCallUiState = InCallUiState.init(this);

callerInfoCache = CallerInfoCache.init(this);

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

//SIM卡状态监听

IccCard sim = phone.getIccCard();

if (sim != null) {

sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);

}

mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);

PhoneUtils.initializeConnectionHandler(mCM);

mTtyEnabled = getResources().getBoolean(R.bool.tty_enabled);

//注册一个Filter

IntentFilter intentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);

intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);

intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);

intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);

intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);

intentFilter.addAction(Intent.ACTION_DOCK_EVENT);

intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);

intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);

intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);

intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);

intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);

registerReceiver(mReceiver, intentFilter);

//注册Filter检测媒体按键的事件

IntentFilter mediaButtonIntentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);

mediaButtonIntentFilter.setPriority(1);

registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter);

//注册Filter检测音频服务

AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

am.registerMediaButtonEventReceiverForCalls(new ComponentName(this.getPackageName(),

MediaButtonBroadcastReceiver.class.getName()));

PhoneUtils.setAudioMode(mCM);

}

可以看到,Phone模块在初始化过程就是对CallManager、CallController、NotificationMgr等进行初始化。同时注册各项必须的服务。而关于Phone对象的创建是通过PhoneFactory.makeDefaultPhones(this)实现的。我们继续往下看创建的过程:

[java] view
plain copy

@PhoneFactory.java

public static void makeDefaultPhones(Context context) {

makeDefaultPhone(context);

}

public static void makeDefaultPhone(Context context) {

//打开telephony的Socket

new LocalServerSocket("com.android.internal.telephony");

//Phone的通知管理

sPhoneNotifier = new DefaultPhoneNotifier();

//得到RILJ

sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);

//得到当前的网络类型

int phoneType = TelephonyManager.getPhoneType(networkMode);

//根据当前的网络类型创建响应的PhoneProxy

if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {

//用GSMPhone创建PhoneProxy

sProxyPhone = new PhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));

} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {

switch (TelephonyManager.getLteOnCdmaModeStatic()) {

case PhoneConstants.LTE_ON_CDMA_TRUE:

//用CDMALTEPhone创建PhoneProxy

sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,sCommandsInterface, sPhoneNotifier));

break;

case PhoneConstants.LTE_ON_CDMA_FALSE:

default:

//用CDMAPhone创建PhoneProxy

sProxyPhone = new PhoneProxy(new CDMAPhone(context,sCommandsInterface, sPhoneNotifier));

break;

}

}

}

上面看到,我们创建的Phone对象其实只是一个Phone的代理(PhoneProxy)而已,而创建这个代理对象需要分两步:
1、首先根据当前的网络类型创建不同的PhoneBase对象,也就是GSMPhone/CDMALTEPhone/CDMAPhone等;
2、然后再用这个PhoneBase对象去构建PhoneProxy对象。
那么,PhoneProxy和GSMPhone又是什么东西呢?我们来看看他们的继承关系:

先来看一下PhoneProxy:

[java] view
plain copy

public class PhoneProxy extends Handler implements Phone

再来看GSMPhone:

[java] view
plain copy

public class GSMPhone extends PhoneBase

public abstract class PhoneBase extends Handler implements Phone

上面的继承关系说明,PhoneProxy和GSMPhone其实都是一个Handler,而且是继承了Phone的接口。这么做的好处是什么呢?

我们知道,对于一个手机来说,无论采用哪种网络制式,他所具备的基本功能是相同的,比如都需要提供打电话、发短信、查询通话状态、读取SIM卡联系人等操作,因此对所有制式的phone都抽象为一个统一的接口:Phone。

但另一方面,不同的网络制式在具体的每项功能实现上,又有很大的不同。因此,需要根据不同的网络制式去实现不同的basePhone,但是都需要完成Phone接口所定义的方法。

而在basePhone之上,再次用PhoneProxy把不同的basePhone封装,这样一来,从上层来看,就屏蔽了不同的basePhone,所有的Phone都是统一的PhoneProxy。

在这里我们只分析GSMPhone,至于CDMAPhone和CDMALTEPhone的基本原理都是类似的。而在分析GSMPhone的创建过程之前,先来看一下创建GSMPhone的必要条件:

[java] view
plain copy

sProxyPhone = new PhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));

上面可以看出,创建GSMPhone对象需要用到2个特殊的变量,sCommandsInterface和sPhoneNotifier:

[java] view
plain copy

sPhoneNotifier = new DefaultPhoneNotifier();

sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);

看来sPhoneNotifier就是DefaultPhoneNotifier对象,而DefaultPhoneNotifier作用就是当相应的Phone有消息从底层上来时,将会通过DefaultPhoneNotifier把消息发送给上层,也就是说,sPhoneNotifier充当了通知的作用。

而sCommandsInterface就是RIL对象。这是framework层与RILC层沟通的渠道,所有上层与RIL层的沟通都需要通过RIL对象装换为相应的命令,最终在RIL.java中通过Socket通道发送给RIL层。

在创建相应的XXXPhone的时候把上面两个变量传递下去:

[java] view
plain copy

@GSMPhone.java

public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) {

this(context,ci,notifier, false);

}

public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {

//把参数传递给父类,也就是PhoneBase类

super(notifier, context, ci, unitTestMode);

//mCM是在父类(PhoneBase)中初始化的

mCM.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);

//各种初始化

mCT = new GsmCallTracker(this);

mSST = new GsmServiceStateTracker (this);

mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);

mDataConnectionTracker = new GsmDataConnectionTracker (this);

mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);

mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);

mSubInfo = new PhoneSubInfo(this);

//对mCM进行各种注册

mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);

mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);

mCM.registerForOn(this, EVENT_RADIO_ON, null);

mCM.setOnUSSD(this, EVENT_USSD, null);

mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);

mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);

//设置系统属性,GSMPhone被激活

SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,

new Integer(PhoneConstants.PHONE_TYPE_GSM).toString());

}

GSMPhone的初始化过程分为两个重要步骤,第一个步骤是在其父类中完成的,主要是用传递下来的sPhoneNotifier去初始化mNotifier,用传递下来的sCommandsInterface初始化mCM。第二个步骤就是在当前类中完成剩余的mCT、mSST、mSMS、mDataConnectionTracker等重要成员变量的初始化过程。

然后再来看PhoneProxy对象的初始化过程:

[java] view
plain copy

@PhoneProxy.java

public PhoneProxy(PhoneBase phone) {

mActivePhone = phone;

mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(

TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);

mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy(

phone.getIccSmsInterfaceManager());

mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(

phone.getIccPhoneBookInterfaceManager());

mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo());

mCommandsInterface = ((PhoneBase)mActivePhone).mCM;

mCommandsInterface.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);

mCommandsInterface.registerForOn(this, EVENT_RADIO_ON, null);

mCommandsInterface.registerForVoiceRadioTechChanged(

this, EVENT_VOICE_RADIO_TECH_CHANGED, null);

mIccCardProxy = new IccCardProxy(phone.getContext(), mCommandsInterface);

if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {

// For the purpose of IccCardProxy we only care about the technology family

mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);

} else if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {

mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);

}

}

在这个过程中把刚才的GSMPhone注册给了mActivePhone变量,然后又创建了一些代理对象,比如mIccSmsInterfaceManagerProxy、IccPhoneBookInterfaceManagerProxy、mPhoneSubInfoProxy、mIccCardProxy等。

经过上面的步骤,不仅创建了phone的对象,而且又注册了各种附加的代理对象,上层可以通过对不同的代理对象的调用去完成不同的功能。

至此,Phone的来历我们就摸清了,用一句话来表述就是,Phone对象就是GSMPhone对象(GSM制式下)

2.2、我们是如何通过pickPhoneBasedOnNumber()的方式得到的Phone对象的

要回答这个问题,我们就要看当初创建Phone对象之后还做了哪些动作。

在分析Phone对象来历时,我们知道Phone对象是在PhoneGlobals中被创建的:

[java] view
plain copy

@PhoneGlobals.java

public void onCreate() {

//创建Phone对象并获取

PhoneFactory.makeDefaultPhones(this);

phone = PhoneFactory.getDefaultPhone();

//初始化CallManager

mCM = CallManager.getInstance();

//把Phone注册给CallManager

mCM.registerPhone(phone);

}

我们看到,得到Phone对象后就把他注册给了CallManager,而所谓的注册其实就是把Phone对象传递给mDefaultPhone,同时把它放在一个叫做mPhones的数组中:

[java] view
plain copy

@CallManager.java

public boolean registerPhone(Phone phone) {

Phone basePhone = getPhoneBase(phone);

if (basePhone != null && !mPhones.contains(basePhone)) {

if (mPhones.isEmpty()) {

//第一次注册时,mPhones列表当然为空

mDefaultPhone = basePhone;

}

mPhones.add(basePhone);

}

}

这样一来,我们就可以通过getDefaultPhone的方式从CallManager中得到Phone:

[java] view
plain copy

public Phone getDefaultPhone() {

return mDefaultPhone;

}

我们回到上面拨号的过程,上面看到,在拨号的过程中,我们需要Phone时是通过以下方式得到Phone对象的:

[java] view
plain copy

phone = PhoneUtils.pickPhoneBasedOnNumber(mCM, scheme, number, sipPhoneUri);

我们继续往下看:

[java] view
plain copy

@PhoneUtils.java

public static Phone pickPhoneBasedOnNumber(CallManager cm, String scheme, String number, String primarySipUri) {

return cm.getDefaultPhone();

}

这里的cm就是传递下来了CallManager,因此pickPhoneBasedOnNumber的方式其实就是调用了CallManager中的getDefaultPhone方法,这种形式正好符合我们的预期。

由此,我们不仅在3.1节中分析了Phone对象的创建过程,而且也在当前节中分析了得到Phone对象的方法。

2.3、继续拨号之旅

在上面的两个小节中主要讲解了Phone对象的来历,简单的说,Phone对象就是GSMPhone对象(对GSM网络来说)。而在前面追踪拨号流程时,我们跟踪到了CallManager.java中的basePhone.dial(dialString),因此,这里的dial就到了GSMPhone中:

[java] view
plain copy

@GSMPhone.java

public Connection dial(String dialString) throws CallStateException {

return dial(dialString, null);

}

再次调用,此时uusInfo为空。

[java] view
plain copy

public Connection dial (String dialString, UUSInfo uusInfo) throws CallStateException {

return mCT.dial(newDialString, uusInfo);

}

我们将上面的代码简化到最关键的一句话,就是调用mCT的dial方法。而这里的mCT就是在GSMPhone的构造函数初始化的GsmCallTracker对象:

[java] view
plain copy

mCT = new GsmCallTracker(this);

因此我们又要来到GsmCallTracker中:

[java] view
plain copy

@GsmCallTracker.java

Connection dial(String dialString, UUSInfo uusInfo) throws CallStateException {

return dial(dialString, CommandsInterface.CLIR_DEFAULT, uusInfo);

}

继续调用:

[java] view
plain copy

Connection dial (String dialString, int clirMode, UUSInfo uusInfo) throws CallStateException {

//构建一个GSM连接

pendingMO = new GsmConnection(phone.getContext(), checkForTestEmergencyNumber(dialString), this, foregroundCall);

//拨号

cm.dial(pendingMO.address, clirMode, uusInfo, obtainCompleteMessage());

//更新Phone状态

updatePhoneState();

//发送状态更新通知

phone.notifyPreciseCallStateChanged();

}

在上面这个过程中,调用了cm的dial方法,这里的cm是Phone对象的mCM:

[java] view
plain copy

GsmCallTracker (GSMPhone phone) {

this.phone = phone;

cm = phone.mCM;

}

而在前面分析过,GSMPhone中的mCM是在其父类PhoneBase中被初始化的:

[java] view
plain copy

@PhoneBase.java

protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci, boolean unitTestMode) {

this.mNotifier = notifier;

this.mContext = context;

mCM = ci;

}

这里看到,mCM其实就是传递下来的CommandsInterface,在往上追溯的话,其实就是当初创建GSMPhone时传递的RIL对象。因此framework拨号的最后,是走到了RIL.java中,并构建拨号的请求发送给RILC,也就是RIL层:

[java] view
plain copy

@RIL.java

public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {

//构建RIL层的请求码:RIL_REQUEST_DIAL

RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);

rr.mp.writeString(address);

rr.mp.writeInt(clirMode);

if (uusInfo == null) {

rr.mp.writeInt(0); // UUS information is absent

} else {

rr.mp.writeInt(1); // UUS information is present

rr.mp.writeInt(uusInfo.getType());

rr.mp.writeInt(uusInfo.getDcs());

rr.mp.writeByteArray(uusInfo.getUserData());

}

//发送

send(rr);

}

发送的过程就是把相应的RILRequest通过mSender发送出去:

[java] view
plain copy

private void send(RILRequest rr) {

Message msg;

if (mSocket == null) {

rr.onError(RADIO_NOT_AVAILABLE, null);

rr.release();

return;

}

msg = mSender.obtainMessage(EVENT_SEND, rr);

acquireWakeLock();

msg.sendToTarget();

}

继续看一下mSender的处理流程:

[java] view
plain copy

@Override

public void handleMessage(Message msg) {

//得到要发送的数据

RILRequest rr = (RILRequest)(msg.obj);

switch (msg.what) {

case EVENT_SEND:

//得到Socket

LocalSocket s;

s = mSocket;

byte[] data;

data = rr.mp.marshall();

rr.mp.recycle();

rr.mp = null;

dataLength[0] = dataLength[1] = 0;

dataLength[2] = (byte)((data.length >> 8) & 0xff);

dataLength[3] = (byte)((data.length) & 0xff);

//把数据发送给RIL层

s.getOutputStream().write(dataLength);

s.getOutputStream().write(data);

break;

case EVENT_WAKE_LOCK_TIMEOUT:

}

}

经过以上的过程,就把拨号的请求发送到了RIL层。

三、总体流程图

现在我们贴出整个拨出号码的流程图:



Source: http://blog.csdn.net/u010961631/article/details/12217759
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: