Android呼出电话流程(原)

一、应用层的流程

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.   
  7.     Intent intent = getIntent();  
  8.     processIntent(intent);  
  9. }  

        继续往下看:
[java] view plaincopy

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

        这个过程其实就是对原始的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.     //得到号码              
  15.     number = getResultData();  
  16.   
  17.     final PhoneGlobals app = PhoneGlobals.getInstance();  
  18.     //OTASP功能,CDMA制式支持  
  19.     if (TelephonyCapabilities.supportsOtasp(app.phone)) {  
  20.     }  
  21.   
  22.     //得到号码的Uri  
  23.     originalUri = intent.getStringExtra( OutgoingCallBroadcaster.EXTRA_ORIGINAL_URI);  
  24.     Uri uri = Uri.parse(originalUri);  
  25.   
  26.     //把字母转换为数字,比如:a–>2;d–>3;g–>4等  
  27.     number = PhoneNumberUtils.convertKeypadLettersToDigits(number);  
  28.     //把所有字符转换为数字  
  29.     number = PhoneNumberUtils.stripSeparators(number);  
  30.   
  31.     //继续处理  
  32.     startSipCallOptionHandler(context, intent, uri, number);  
  33. }  
  34. private void startSipCallOptionHandler(Context context, Intent intent, Uri uri, String number) {  
  35.     //再次构建Intent  
  36.     Intent newIntent = new Intent(Intent.ACTION_CALL, uri);  
  37.     newIntent.putExtra(EXTRA_ACTUAL_NUMBER_TO_DIAL, number);  
  38.     //把原始的Intent数据拷贝过来  
  39.     //主要去解析EXTRA_GATEWAY_PROVIDER_PACKAGE和EXTRA_GATEWAY_URI,而这两项均为null  
  40.     PhoneUtils.checkAndCopyPhoneProviderExtras(intent, newIntent);  
  41.   
  42.     //还有一个Intent  
  43.     Intent selectPhoneIntent = new Intent(ACTION_SIP_SELECT_PHONE, uri);  
  44.     //指明接受者是SipCallOptionHandler  
  45.     selectPhoneIntent.setClass(context, SipCallOptionHandler.class);  
  46.     //把上面的Intent放到EXTRA_NEW_CALL_INTENT中  
  47.     selectPhoneIntent.putExtra(EXTRA_NEW_CALL_INTENT, newIntent);  
  48.     //用新的task装载  
  49.     selectPhoneIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  50.     //发送,走起  
  51.     context.startActivity(selectPhoneIntent);  
  52. }  

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

        继续看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.   
  20.             if (mUseSipPhone && mOutgoingSipProfile == null) {  
  21.                 showDialog(DIALOG_START_SIP_SETTINGS);  
  22.                 return;  
  23.             } else {  
  24.                 //正常拨号  
  25.                 PhoneGlobals.getInstance().callController.placeCall(mIntent);  
  26.             }  
  27.             finish();  
  28.         }  
  29.     });  
  30. }  

        上面可以看出,在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.     //根据当前的通话状态决定是否可以继续拨号  
  7.     if (!canDial(phone)) {  
  8.         throw new CallStateException("cannot dial in current state");  
  9.     }  
  10.   
  11.     if ( hasActiveFgCall() ) {  
  12.         //已经有电话存在  
  13.     }  
  14.     //拨号  
  15.     result = basePhone.dial(dialString);  
  16.     return result;  
  17. }  

        代码走到这里,就简化为调用一个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(thisthis);  
  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.   
  9.     //mCM是在父类(PhoneBase)中初始化的  
  10.     mCM.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);  
  11.     //各种初始化  
  12.     mCT = new GsmCallTracker(this);  
  13.     mSST = new GsmServiceStateTracker (this);  
  14.     mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);  
  15.     mDataConnectionTracker = new GsmDataConnectionTracker (this);  
  16.     mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);  
  17.     mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);  
  18.     mSubInfo = new PhoneSubInfo(this);  
  19.     //对mCM进行各种注册  
  20.     mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);  
  21.     mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);  
  22.     mCM.registerForOn(this, EVENT_RADIO_ON, null);  
  23.     mCM.setOnUSSD(this, EVENT_USSD, null);  
  24.     mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);  
  25.     mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);  
  26.   
  27.     //设置系统属性,GSMPhone被激活  
  28.     SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,  
  29.             new Integer(PhoneConstants.PHONE_TYPE_GSM).toString());  
  30. }  

        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.   
  13.     mCommandsInterface.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);  
  14.     mCommandsInterface.registerForOn(this, EVENT_RADIO_ON, null);  
  15.     mCommandsInterface.registerForVoiceRadioTechChanged(  
  16.                          this, EVENT_VOICE_RADIO_TECH_CHANGED, null);  
  17.     mIccCardProxy = new IccCardProxy(phone.getContext(), mCommandsInterface);  
  18.     if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {  
  19.         // For the purpose of IccCardProxy we only care about the technology family  
  20.         mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);  
  21.     } else if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {  
  22.         mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);  
  23.     }  
  24. }  

        在这个过程中把刚才的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.   
  8.     if (uusInfo == null) {  
  9.         rr.mp.writeInt(0); // UUS information is absent  
  10.     } else {  
  11.         rr.mp.writeInt(1); // UUS information is present  
  12.         rr.mp.writeInt(uusInfo.getType());  
  13.         rr.mp.writeInt(uusInfo.getDcs());  
  14.         rr.mp.writeByteArray(uusInfo.getUserData());  
  15.     }  
  16.     //发送  
  17.     send(rr);  
  18. }  

        发送的过程就是把相应的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.   
  11.                 byte[] data;  
  12.                 data = rr.mp.marshall();  
  13.                 rr.mp.recycle();  
  14.                 rr.mp = null;  
  15.   
  16.                 dataLength[0] = dataLength[1] = 0;  
  17.                 dataLength[2] = (byte)((data.length >> 8) & 0xff);  
  18.                 dataLength[3] = (byte)((data.length) & 0xff);  
  19.   
  20.                 //把数据发送给RIL层  
  21.                 s.getOutputStream().write(dataLength);  
  22.                 s.getOutputStream().write(data);  
  23.             break;  
  24.         case EVENT_WAKE_LOCK_TIMEOUT:  
  25.     }  
  26. }  

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

三、总体流程图

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

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

Published by

风君子

独自遨游何稽首 揭天掀地慰生平