一、应用层的流程

1.1、拨号盘初步处理

[java] view plaincopy
  1. @DialpadFragment.java
  2. public void dialButtonPressed() {
  3. //得到号码
  4. final String number = mDigits.getText().toString();
  5. //得到拨号的Intent
  6. final Intent intent = ContactsUtils.getCallIntent(number,
  7. (getActivity() instanceof DialtactsActivity ?
  8. ((DialtactsActivity)getActivity()).getCallOrigin() : null));
  9. startActivity(intent);
  10. mClearDigitsOnStop = true;
  11. getActivity().finish();
  12. }

来看上面得到Intent的过程:

[java] view plaincopy
  1. @ContactsUtils.java
  2. public static Intent getCallIntent(String number, String callOrigin) {
  3. 用号码构建一个类似tel:10086的Uri
  4. return getCallIntent(getCallUri(number), callOrigin);
  5. }
  6. public static Intent getCallIntent(Uri uri, String callOrigin) {
  7. final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, uri);
  8. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  9. if (callOrigin != null) {
  10. intent.putExtra(DialtactsActivity.EXTRA_CALL_ORIGIN, callOrigin);
  11. }
  12. return intent;
  13. }

这个过程可以看出,发出的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 plaincopy
  1. <activity-alias android:name="PrivilegedOutgoingCallBroadcaster"
  2. android:targetActivity="OutgoingCallBroadcaster"
  3. android:screenOrientation="nosensor"
  4. android:permission="android.permission.CALL_PRIVILEGED">
  5. <intent-filter>
  6. <action android:name="android.intent.action.CALL_PRIVILEGED" />
  7. <category android:name="android.intent.category.DEFAULT" />
  8. <data android:scheme="tel" />
  9. </intent-filter>
  10. </activity-alias>

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

[java] view plaincopy
  1. @OutgoingCallBroadcaster.java
  2. protected void onCreate(Bundle icicle) {
  3. super.onCreate(icicle);
  4. setContentView(R.layout.outgoing_call_broadcaster);
  5. mWaitingSpinner = (ProgressBar) findViewById(R.id.spinner);
  6. Intent intent = getIntent();
  7. processIntent(intent);
  8. }

继续往下看:

[java] view plaincopy
  1. private void processIntent(Intent intent) {
  2. final Configuration configuration = getResources().getConfiguration();
  3. String action = intent.getAction();
  4. String number = PhoneNumberUtils.getNumberFromIntent(intent, this);
  5. //得到当前的号码
  6. if (number != null) {
  7. if (!PhoneNumberUtils.isUriNumber(number)) {
  8. number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
  9. number = PhoneNumberUtils.stripSeparators(number);
  10. }
  11. } else {
  12. }
  13. //判断是否是紧急拨号
  14. final boolean isExactEmergencyNumber =
  15. (number != null) && PhoneNumberUtils.isLocalEmergencyNumber(number, this);
  16. final boolean isPotentialEmergencyNumber =
  17. (number != null) && PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, this);
  18. if (Intent.ACTION_CALL_PRIVILEGED.equals(action)) {
  19. if (isPotentialEmergencyNumber) {
  20. //紧急拨号的action
  21. action = Intent.ACTION_CALL_EMERGENCY;
  22. } else {
  23. //非紧急拨号的action
  24. action = Intent.ACTION_CALL;
  25. }
  26. //重新设置Action,当前不是紧急呼叫,因此Action改为ACTION_CALL
  27. intent.setAction(action);
  28. }
  29. if (Intent.ACTION_CALL.equals(action)) {
  30. if (isPotentialEmergencyNumber) {
  31. //判断不成立
  32. }
  33. //当前的callNow为false
  34. callNow = false;
  35. } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
  36. //紧急呼叫的处理
  37. } else {
  38. }
  39. Uri uri = intent.getData();
  40. String scheme = uri.getScheme();
  41. if (Constants.SCHEME_SIP.equals(scheme) || PhoneNumberUtils.isUriNumber(number)) {
  42. //互联网通话的处理
  43. }
  44. //重新构建Intent
  45. Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
  46. if (number != null) {
  47. broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
  48. }
  49. PhoneUtils.checkAndCopyPhoneProviderExtras(intent, broadcastIntent);
  50. broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);
  51. broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, uri.toString());
  52. broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
  53. //添加一个2秒的定时器,2秒内Intent没有收到的话,就显示一个进度条
  54. mHandler.sendEmptyMessageDelayed(EVENT_OUTGOING_CALL_TIMEOUT,
  55. OUTGOING_CALL_TIMEOUT_THRESHOLD);
  56. //发送广播,而且指明了接收者是OutgoingCallReceiver
  57. sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.OWNER,
  58. PERMISSION, new OutgoingCallReceiver(),
  59. null,
  60. Activity.RESULT_OK,
  61. number,
  62. null);
  63. }

这个过程其实就是对原始的Intent进行解析,对是否紧急呼叫进行不同的处理,对于正常的呼叫,需要重新构建Intent并发送出去。新的Intent构成:
            Intent:ACTION_NEW_OUTGOING_CALL;
            EXTRA_ALREADY_CALLED:false;
            EXTRA_ORIGINAL_URI:号码的Uri;
            发送目标:OutgoingCallReceiver;
        这里所谓的目标 OutgoingCallReceiver其实就是OutgoingCallBroadcaster.java中的内部类 ,我们直接来看他的接收地方:

[java] view plaincopy
  1. public void onReceive(Context context, Intent intent) {
  2. //去掉3妙的定时器
  3. mHandler.removeMessages(EVENT_OUTGOING_CALL_TIMEOUT);
  4. doReceive(context, intent);
  5. finish();
  6. }
  7. public void doReceive(Context context, Intent intent) {
  8. //这里的得到的是false
  9. alreadyCalled = intent.getBooleanExtra(OutgoingCallBroadcaster.EXTRA_ALREADY_CALLED, false);
  10. if (alreadyCalled) {
  11. return;
  12. }
  13. //得到号码
  14. number = getResultData();
  15. final PhoneGlobals app = PhoneGlobals.getInstance();
  16. //OTASP功能,CDMA制式支持
  17. if (TelephonyCapabilities.supportsOtasp(app.phone)) {
  18. }
  19. //得到号码的Uri
  20. originalUri = intent.getStringExtra( OutgoingCallBroadcaster.EXTRA_ORIGINAL_URI);
  21. Uri uri = Uri.parse(originalUri);
  22. //把字母转换为数字,比如:a-->2;d-->3;g-->4等
  23. number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
  24. //把所有字符转换为数字
  25. number = PhoneNumberUtils.stripSeparators(number);
  26. //继续处理
  27. startSipCallOptionHandler(context, intent, uri, number);
  28. }
  29. private void startSipCallOptionHandler(Context context, Intent intent, Uri uri, String number) {
  30. //再次构建Intent
  31. Intent newIntent = new Intent(Intent.ACTION_CALL, uri);
  32. newIntent.putExtra(EXTRA_ACTUAL_NUMBER_TO_DIAL, number);
  33. //把原始的Intent数据拷贝过来
  34. //主要去解析EXTRA_GATEWAY_PROVIDER_PACKAGE和EXTRA_GATEWAY_URI,而这两项均为null
  35. PhoneUtils.checkAndCopyPhoneProviderExtras(intent, newIntent);
  36. //还有一个Intent
  37. Intent selectPhoneIntent = new Intent(ACTION_SIP_SELECT_PHONE, uri);
  38. //指明接受者是SipCallOptionHandler
  39. selectPhoneIntent.setClass(context, SipCallOptionHandler.class);
  40. //把上面的Intent放到EXTRA_NEW_CALL_INTENT中
  41. selectPhoneIntent.putExtra(EXTRA_NEW_CALL_INTENT, newIntent);
  42. //用新的task装载
  43. selectPhoneIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  44. //发送,走起
  45. context.startActivity(selectPhoneIntent);
  46. }

上面的操作又是发起了一个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 plaincopy
  1. @SipCallOptionHandler.java
  2. public void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. //得到Intent
  5. Intent intent = getIntent();
  6. String action = intent.getAction();
  7. //外层的Intent
  8. if (!OutgoingCallBroadcaster.ACTION_SIP_SELECT_PHONE.equals(action)) {
  9. finish();
  10. return;
  11. }
  12. //得到拨号的Intent
  13. mIntent = (Intent) intent.getParcelableExtra(OutgoingCallBroadcaster.EXTRA_NEW_CALL_INTENT);
  14. if (mIntent == null) {
  15. finish();
  16. return;
  17. }
  18. //是否支持互联网通话
  19. boolean voipSupported = PhoneUtils.isVoipSupported();
  20. mSipProfileDb = new SipProfileDb(this);
  21. mSipSharedPreferences = new SipSharedPreferences(this);
  22. mCallOption = mSipSharedPreferences.getSipCallOption();
  23. Uri uri = mIntent.getData();
  24. String scheme = uri.getScheme();
  25. //得到通话的号码
  26. mNumber = PhoneNumberUtils.getNumberFromIntent(mIntent, this);
  27. //是否有网络
  28. boolean isInCellNetwork = PhoneGlobals.getInstance().phoneMgr.isRadioOn();
  29. //是否是tel:或者sip:的协议
  30. boolean isKnownCallScheme = Constants.SCHEME_TEL.equals(scheme)||Constants.SCHEME_SIP.equals(scheme);
  31. boolean isRegularCall = Constants.SCHEME_TEL.equals(scheme)
  32. && !PhoneNumberUtils.isUriNumber(mNumber);
  33. if (!isKnownCallScheme) {
  34. //异常处理,处理非法协议。
  35. setResultAndFinish();
  36. return;
  37. }
  38. if (!voipSupported) {
  39. if (!isRegularCall) {
  40. showDialog(DIALOG_NO_VOIP);
  41. } else {
  42. //当前不是IP通话,因此走这里
  43. setResultAndFinish();
  44. }
  45. return;
  46. }
  47. setResultAndFinish();
  48. }

继续看setResultAndFinish

[java] view plaincopy
  1. private void setResultAndFinish() {
  2. //放在主线程中操作
  3. runOnUiThread(new Runnable() {
  4. public void run() {
  5. if (mOutgoingSipProfile != null) {
  6. //互联网通话
  7. if (!isNetworkConnected()) {
  8. showDialog(DIALOG_NO_INTERNET_ERROR);
  9. return;
  10. }
  11. createSipPhoneIfNeeded(mOutgoingSipProfile);
  12. mIntent.putExtra(OutgoingCallBroadcaster.EXTRA_SIP_PHONE_URI,
  13. mOutgoingSipProfile.getUriString());
  14. if (mMakePrimary) {
  15. mSipSharedPreferences.setPrimaryAccount(
  16. mOutgoingSipProfile.getUriString());
  17. }
  18. }
  19. if (mUseSipPhone && mOutgoingSipProfile == null) {
  20. showDialog(DIALOG_START_SIP_SETTINGS);
  21. return;
  22. } else {
  23. //正常拨号
  24. PhoneGlobals.getInstance().callController.placeCall(mIntent);
  25. }
  26. finish();
  27. }
  28. });
  29. }

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

1.4、Phone模块其他的处理

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

[java] view plaincopy
  1. @CallController.java
  2. public void placeCall(Intent intent)
  3. {
  4. //拨打
  5. CallStatusCode status = placeCallInternal(intent);
  6. //显示InCallScreen
  7. mApp.displayCallScreen(!intent.getBooleanExtra(Constants.EXTRA_IS_VIDEO_CALL, false), forPlaceCall);
  8. }
  9. private CallStatusCode placeCallInternal(Intent intent) {
  10. //得到号码
  11. number = PhoneUtils.getInitialNumber(intent);
  12. //得到Phone对象
  13. phone = PhoneUtils.pickPhoneBasedOnNumber(mCM, scheme, number, sipPhoneUri);
  14. //检查当前状态
  15. okToCallStatus = checkIfOkToInitiateOutgoingCall(phone.getServiceState().getState());
  16. //得到联系人的数据
  17. Uri contactUri = intent.getData();
  18. //拨号
  19. int callStatus = PhoneUtils.placeCall(mApp,
  20. phone,
  21. number,
  22. contactUri,
  23. (isEmergencyNumber || isEmergencyIntent),
  24. inCallUiState.providerGatewayUri);
  25. }

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

[java] view plaincopy
  1. @PhoneUtils.java
  2. public static int placeCall(Context context, Phone phone,
  3. String number, Uri contactRef, boolean isEmergencyCall,
  4. Uri gatewayUri) {
  5. //得到app
  6. final PhoneGlobals app = PhoneGlobals.getInstance();
  7. //号码
  8. numberToDial = number;
  9. //拨号
  10. connection = app.mCM.dial(phone, numberToDial);
  11. //设置音频模式
  12. setAudioMode();
  13. return status;
  14. }

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

[java] view plaincopy
  1. mCM = CallManager.getInstance();

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

二、framework中的流程

[java] view plaincopy
  1. @CallManager.java
  2. public Connection dial(Phone phone, String dialString) throws CallStateException {
  3. //得到basePhone
  4. Phone basePhone = getPhoneBase(phone);
  5. //根据当前的通话状态决定是否可以继续拨号
  6. if (!canDial(phone)) {
  7. throw new CallStateException("cannot dial in current state");
  8. }
  9. if ( hasActiveFgCall() ) {
  10. //已经有电话存在
  11. }
  12. //拨号
  13. result = basePhone.dial(dialString);
  14. return result;
  15. }

代码走到这里,就简化为调用一个Phone对象的dial方法了,此时要想继续往下分析,就必须知道这个Phone对象的来历。下面我们要做两件事:

1、查出Phone对象到底来自于哪里。

2、我们如何通过PhoneUtils.pickPhoneBasedOnNumber()的方式得到了这个Phone对象

2.1、Phone的来历

Phone在通话中扮演着极其重要的操作,我们来看一下Phone是怎样产生的。
        我们知道, Phone模块进程第一个启动的类就是PhoneGlobals ,他是在手机开机的过程中启动的。那么我们看一下他的初始化过程:

[java] view plaincopy
  1. @PhoneGlobals.java
  2. public void onCreate() {
  3. //创建Phone对象
  4. PhoneFactory.makeDefaultPhones(this);
  5. //得到创建的Phone对象
  6. phone = PhoneFactory.getDefaultPhone();
  7. //初始化CallManager并把Phone对象注册给CallManager
  8. mCM = CallManager.getInstance();
  9. mCM.registerPhone(phone);
  10. //初始化NotificationMgr
  11. notificationMgr = NotificationMgr.init(this);
  12. phoneMgr = PhoneInterfaceManager.init(this, phone);
  13. //开启SIP服务
  14. mHandler.sendEmptyMessage(EVENT_START_SIP_SERVICE);
  15. //铃声初始化
  16. ringer = Ringer.init(this);
  17. //得到电源管理服务
  18. mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
  19. //距离传感器
  20. if (proximitySensorModeEnabled()) {
  21. mAccelerometerListener = new AccelerometerListener(this, this);
  22. }
  23. //按键管理
  24. mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
  25. //电源管理
  26. mPowerManagerService = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
  27. //又是各种初始化
  28. callController = CallController.init(this);
  29. inCallUiState = InCallUiState.init(this);
  30. callerInfoCache = CallerInfoCache.init(this);
  31. notifier = CallNotifier.init(this, phone, ringer, new CallLogAsync());
  32. //SIM卡状态监听
  33. IccCard sim = phone.getIccCard();
  34. if (sim != null) {
  35. sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
  36. }
  37. mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
  38. PhoneUtils.initializeConnectionHandler(mCM);
  39. mTtyEnabled = getResources().getBoolean(R.bool.tty_enabled);
  40. //注册一个Filter
  41. IntentFilter intentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
  42. intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
  43. intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
  44. intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
  45. intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
  46. intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
  47. intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
  48. intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
  49. intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
  50. intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
  51. intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
  52. registerReceiver(mReceiver, intentFilter);
  53. //注册Filter检测媒体按键的事件
  54. IntentFilter mediaButtonIntentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
  55. mediaButtonIntentFilter.setPriority(1);
  56. registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter);
  57. //注册Filter检测音频服务
  58. AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  59. am.registerMediaButtonEventReceiverForCalls(new ComponentName(this.getPackageName(),
  60. MediaButtonBroadcastReceiver.class.getName()));
  61. PhoneUtils.setAudioMode(mCM);
  62. }

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

[java] view plaincopy
  1. @PhoneFactory.java
  2. public static void makeDefaultPhones(Context context) {
  3. makeDefaultPhone(context);
  4. }
  5. public static void makeDefaultPhone(Context context) {
  6. //打开telephony的Socket
  7. new LocalServerSocket("com.android.internal.telephony");
  8. //Phone的通知管理
  9. sPhoneNotifier = new DefaultPhoneNotifier();
  10. //得到RILJ
  11. sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
  12. //得到当前的网络类型
  13. int phoneType = TelephonyManager.getPhoneType(networkMode);
  14. //根据当前的网络类型创建响应的PhoneProxy
  15. if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
  16. //用GSMPhone创建PhoneProxy
  17. sProxyPhone = new PhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));
  18. } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
  19. switch (TelephonyManager.getLteOnCdmaModeStatic()) {
  20. case PhoneConstants.LTE_ON_CDMA_TRUE:
  21. //用CDMALTEPhone创建PhoneProxy
  22. sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,sCommandsInterface, sPhoneNotifier));
  23. break;
  24. case PhoneConstants.LTE_ON_CDMA_FALSE:
  25. default:
  26. //用CDMAPhone创建PhoneProxy
  27. sProxyPhone = new PhoneProxy(new CDMAPhone(context,sCommandsInterface, sPhoneNotifier));
  28. break;
  29. }
  30. }
  31. }

上面看到,我们创建的Phone对象其实只是一个Phone的代理(PhoneProxy)而已,而创建这个代理对象需要分两步:

            1、首先根据当前的网络类型创建不同的PhoneBase对象,也就是GSMPhone/CDMALTEPhone/CDMAPhone等;

            2、然后再用这个PhoneBase对象去构建PhoneProxy对象。

那么,PhoneProxy和GSMPhone又是什么东西呢?我们来看看他们的继承关系:
        先来看一下PhoneProxy:

[java] view plaincopy
  1. public class PhoneProxy extends Handler implements Phone

再来看GSMPhone:

[java] view plaincopy
  1. public class GSMPhone extends PhoneBase
  2. 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 plaincopy
  1. sProxyPhone = new PhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));

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

[java] view plaincopy
  1. sPhoneNotifier = new DefaultPhoneNotifier();
  2. 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 plaincopy
  1. @GSMPhone.java
  2. public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) {
  3. this(context,ci,notifier, false);
  4. }
  5. public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {
  6. //把参数传递给父类,也就是PhoneBase类
  7. super(notifier, context, ci, unitTestMode);
  8. //mCM是在父类(PhoneBase)中初始化的
  9. mCM.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);
  10. //各种初始化
  11. mCT = new GsmCallTracker(this);
  12. mSST = new GsmServiceStateTracker (this);
  13. mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
  14. mDataConnectionTracker = new GsmDataConnectionTracker (this);
  15. mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
  16. mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);
  17. mSubInfo = new PhoneSubInfo(this);
  18. //对mCM进行各种注册
  19. mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
  20. mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
  21. mCM.registerForOn(this, EVENT_RADIO_ON, null);
  22. mCM.setOnUSSD(this, EVENT_USSD, null);
  23. mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
  24. mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
  25. //设置系统属性,GSMPhone被激活
  26. SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
  27. new Integer(PhoneConstants.PHONE_TYPE_GSM).toString());
  28. }

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

[java] view plaincopy
  1. @PhoneProxy.java
  2. public PhoneProxy(PhoneBase phone) {
  3. mActivePhone = phone;
  4. mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(
  5. TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);
  6. mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy(
  7. phone.getIccSmsInterfaceManager());
  8. mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(
  9. phone.getIccPhoneBookInterfaceManager());
  10. mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo());
  11. mCommandsInterface = ((PhoneBase)mActivePhone).mCM;
  12. mCommandsInterface.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
  13. mCommandsInterface.registerForOn(this, EVENT_RADIO_ON, null);
  14. mCommandsInterface.registerForVoiceRadioTechChanged(
  15. this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
  16. mIccCardProxy = new IccCardProxy(phone.getContext(), mCommandsInterface);
  17. if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
  18. // For the purpose of IccCardProxy we only care about the technology family
  19. mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
  20. } else if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
  21. mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
  22. }
  23. }

在这个过程中把刚才的GSMPhone注册给了mActivePhone变量,然后又创建了一些代理对象,比如mIccSmsInterfaceManagerProxy、IccPhoneBookInterfaceManagerProxy、mPhoneSubInfoProxy、mIccCardProxy等。
        经过上面的步骤,不仅创建了phone的对象,而且又注册了各种附加的代理对象,上层可以通过对不同的代理对象的调用去完成不同的功能。

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

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

要回答这个问题,我们就要看当初创建Phone对象之后还做了哪些动作。
        在分析Phone对象来历时,我们知道Phone对象是在PhoneGlobals中被创建的:

[java] view plaincopy
  1. @PhoneGlobals.java
  2. public void onCreate() {
  3. //创建Phone对象并获取
  4. PhoneFactory.makeDefaultPhones(this);
  5. phone = PhoneFactory.getDefaultPhone();
  6. //初始化CallManager
  7. mCM = CallManager.getInstance();
  8. //把Phone注册给CallManager
  9. mCM.registerPhone(phone);
  10. }

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

[java] view plaincopy
  1. @CallManager.java
  2. public boolean registerPhone(Phone phone) {
  3. Phone basePhone = getPhoneBase(phone);
  4. if (basePhone != null && !mPhones.contains(basePhone)) {
  5. if (mPhones.isEmpty()) {
  6. //第一次注册时,mPhones列表当然为空
  7. mDefaultPhone = basePhone;
  8. }
  9. mPhones.add(basePhone);
  10. }
  11. }

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

[java] view plaincopy
  1. public Phone getDefaultPhone() {
  2. return mDefaultPhone;
  3. }

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

[java] view plaincopy
  1. phone = PhoneUtils.pickPhoneBasedOnNumber(mCM, scheme, number, sipPhoneUri);

我们继续往下看:

[java] view plaincopy
  1. @PhoneUtils.java
  2. public static Phone pickPhoneBasedOnNumber(CallManager cm, String scheme, String number, String primarySipUri) {
  3. return cm.getDefaultPhone();
  4. }

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

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

2.3、继续拨号之旅

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

[java] view plaincopy
  1. @GSMPhone.java
  2. public Connection dial(String dialString) throws CallStateException {
  3. return dial(dialString, null);
  4. }

再次调用,此时uusInfo为空。

[java] view plaincopy
  1. public Connection dial (String dialString, UUSInfo uusInfo) throws CallStateException {
  2. return mCT.dial(newDialString, uusInfo);
  3. }

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

[java] view plaincopy
  1. mCT = new GsmCallTracker(this);

因此我们又要来到GsmCallTracker中:

[java] view plaincopy
  1. @GsmCallTracker.java
  2. Connection dial(String dialString, UUSInfo uusInfo) throws CallStateException {
  3. return dial(dialString, CommandsInterface.CLIR_DEFAULT, uusInfo);
  4. }

继续调用:

[java] view plaincopy
  1. Connection dial (String dialString, int clirMode, UUSInfo uusInfo) throws CallStateException {
  2. //构建一个GSM连接
  3. pendingMO = new GsmConnection(phone.getContext(), checkForTestEmergencyNumber(dialString), this, foregroundCall);
  4. //拨号
  5. cm.dial(pendingMO.address, clirMode, uusInfo, obtainCompleteMessage());
  6. //更新Phone状态
  7. updatePhoneState();
  8. //发送状态更新通知
  9. phone.notifyPreciseCallStateChanged();
  10. }

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

[java] view plaincopy
  1. GsmCallTracker (GSMPhone phone) {
  2. this.phone = phone;
  3. cm = phone.mCM;
  4. }

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

[java] view plaincopy
  1. @PhoneBase.java
  2. protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci, boolean unitTestMode) {
  3. this.mNotifier = notifier;
  4. this.mContext = context;
  5. mCM = ci;
  6. }

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

[java] view plaincopy
  1. @RIL.java
  2. public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
  3. //构建RIL层的请求码:RIL_REQUEST_DIAL
  4. RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
  5. rr.mp.writeString(address);
  6. rr.mp.writeInt(clirMode);
  7. if (uusInfo == null) {
  8. rr.mp.writeInt(0); // UUS information is absent
  9. } else {
  10. rr.mp.writeInt(1); // UUS information is present
  11. rr.mp.writeInt(uusInfo.getType());
  12. rr.mp.writeInt(uusInfo.getDcs());
  13. rr.mp.writeByteArray(uusInfo.getUserData());
  14. }
  15. //发送
  16. send(rr);
  17. }

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

[java] view plaincopy
  1. private void send(RILRequest rr) {
  2. Message msg;
  3. if (mSocket == null) {
  4. rr.onError(RADIO_NOT_AVAILABLE, null);
  5. rr.release();
  6. return;
  7. }
  8. msg = mSender.obtainMessage(EVENT_SEND, rr);
  9. acquireWakeLock();
  10. msg.sendToTarget();
  11. }

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

[java] view plaincopy
  1. @Override
  2. public void handleMessage(Message msg) {
  3. //得到要发送的数据
  4. RILRequest rr = (RILRequest)(msg.obj);
  5. switch (msg.what) {
  6. case EVENT_SEND:
  7. //得到Socket
  8. LocalSocket s;
  9. s = mSocket;
  10. byte[] data;
  11. data = rr.mp.marshall();
  12. rr.mp.recycle();
  13. rr.mp = null;
  14. dataLength[0] = dataLength[1] = 0;
  15. dataLength[2] = (byte)((data.length >> 8) & 0xff);
  16. dataLength[3] = (byte)((data.length) & 0xff);
  17. //把数据发送给RIL层
  18. s.getOutputStream().write(dataLength);
  19. s.getOutputStream().write(data);
  20. break;
  21. case EVENT_WAKE_LOCK_TIMEOUT:
  22. }
  23. }

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

三、总体流程图

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

Source: http://blog.csdn.net/u010961631/article/details/12217759

Android呼出电话流程(原)相关推荐

  1. android 拨打电话、 监听来电、监听呼出电话的功能实现

    demo1(通用): 权限 <!-- 监听呼出电话 --> <uses-permission android:name="android.permission.PROCES ...

  2. Android 10 拨打电话流程

    接续上一章节,理解Android 10 拨打电话流程 packages/apps/Dialer/java/com/android/dialer/dialpadview/DialpadFragment. ...

  3. 在android中监听呼出电话(电话拦截、修改呼出电话)

    2019独角兽企业重金招聘Python工程师标准>>> 在android中向外拨打电话时系统会发出一个有序广播,虽然该广播最终会被拔号器里的广播接收者所接收并实现电话拔打,但我们可以 ...

  4. Android屏蔽呼出电话提示音,Android来电拦截及拦截后的提示音

    Android电话拦截及拦截后的提示音 1. 电话拦截 这个功能大家可能都知道了,就是利用反射原理调用ITelephony的隐藏方法来实现.这个就不说了,在附件的代码里有. 2.拦截后提示忙音/空号/ ...

  5. android 修改呼出号码,在android中监听呼出电话(电话拦截、修改呼出电话)

    在android中向外拨打电话时系统会发出一个有序广播,虽然该广播最终会被拔号器里的广播接收者所接收并实现电话拔打,但我们可以在广播传递给拔号广播接收者之前先得到该广播,然后清除传递给拔号广播接收者的 ...

  6. android N 拨打电话流程(MO)

    本流程图基于MTK平台 Android 7.0,拨打的普通电话,本流程只作为沟通学习使用 整体流程图 流程中部分重点知识 packages-apps目录 dialer应用的DialpadFragmen ...

  7. android 通话的log分析,Android Telephony 接电话流程分析

    写在前面的话 本文主要分析Android 接电话的流程,研究的代码是Android 4.4的,现在我们只关注framework层,以CDMA为例,GSM同理. 如果图片看不清的话,可以右键选择在新标签 ...

  8. android 呼入电话游戏闪退,光遇闪退解决方法 游戏总是闪退怎么回事

    国内的安卓小伙伴终于可以在光遇游戏中开启自己的逐光之旅了,不过有一部分小伙伴就比较悲催了,下载安装好了游戏打开总是闪退,下面就来分享一下光遇闪退解决方法,如果你也遇到了游戏闪退问题,那么就一起来看看吧 ...

  9. android 呼入电话游戏闪退,安卓手机游戏卡顿、闪退问题解决方案

    安卓手机游戏卡顿.闪退问题解决方案,下面就由去游戏pro小编忆成殇为大家带来安卓手机游戏卡顿.闪退问题解决方案,剑魂之刃闪退.卡顿一直困扰着玩家,那么究竟怎样更好的玩好我们的卡顿及闪退问题呢,下面就随 ...

最新文章

  1. 2021年春季学期-信号与系统-第八次作业参考答案-第二小题
  2. mysql行转列和列转行_mysql 行转列和列转行实例详解
  3. DOM加载过程中ready和load的区别
  4. php改成IP连接数据库,thinkphp,pdo连接数据库,host自动被替换成了本机ip
  5. 揭开KPI异常检测顶级AI模型面纱
  6. agx 安装ros opencv_Ubuntu下安装realsense+melodic+OpenCV
  7. DevOps使用教程 华为云(5)迭代计划 进度管理
  8. excel打开2个独立窗口_喜欢用华为手机拍照,记得打开这2个开关,能让照片更加清晰...
  9. MySQL递归查询 三种实现方式
  10. 实例讲解反向传播(简单易懂)
  11. 夏普Sharp MX-B6581D 一体机驱动
  12. oracle中的各种命令(关于表的增删改查)
  13. hotmail接收邮件服务器(pop),Microsoft微软邮箱 outlook、hotmail 打开pop和imap的方法
  14. android adapter 组件,Android UI - AdapterView 及其子类
  15. 转载蓝叠模拟器与android studio连接步骤
  16. 白平衡测试—imatest
  17. 把你的阿里巴巴图标库转成你自己的@ant-design/icons
  18. 停用 微软上载服务器,如何完全禁用 Office上载中心
  19. 麦可网嵌入式linux,麦可网张凌华体系结构及裸板篇ARM嵌入式开发视频教程
  20. SpringBoot菜鸟教程(一)

热门文章

  1. Linux系统安全工具tcpdump用法
  2. iTextSharp.text.Rectangle 使用方法说明
  3. 平稳随机序列的自相关函数和功率谱密度
  4. Python 3 os.walk使用详解
  5. shell脚本的两种执行方式区别举例
  6. 机器学习导论(张志华):核定义
  7. 6.6 数据集的存储与表达
  8. 无功功率控制模式matlab,第9章_MATLAB在风力发电技术中的应用仿真.ppt
  9. [云炬商业计划书阅读分享] 珠江啤酒公司企业文化调查
  10. 科大星云诗社动态20210829