Android电话来电流程源码分析

2024-03-15 05:32

本文主要是介绍Android电话来电流程源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android的Phone设计的相当复杂,只有了解了Phone的设计框架才能把握电话的拨号或来电流程,在Android电话拨打流程源码分析中已经分析介绍了电话拨打流程,这里介绍一下电话的来电流程。

要理解这节内容,首先要知道Android电话的层次设计


Framework层的RIL中的RILReceiver线程从rild服务进程中读取modem发送上来的来电消息等信息,通过消息注册-响应机制来通知上层处理,上图清晰地显示了各层之间的消息处理关系,CallManager连接Framework层和应用层的Phone,

CallManager处理GSMPhone注册的消息事件,并且触发CallManager注册的消息事件,而CallNotifier处理CallManager消息,这样就将RIL层的消息一级一级传送的应用层的Phone了。

RIL层事件注册过程

frameworks\base\telephony\java\com\android\internal\telephony\ PhoneFactory.java

[java] view plain copy print ?
  1. public static void makeDefaultPhone(Context context) {  
  2.     synchronized(Phone.class) {  
  3.         if (!sMadeDefaults) {  
  4.             sLooper = Looper.myLooper();  
  5.             sContext = context;  
  6.             if (sLooper == null) {  
  7.                 throw new RuntimeException("PhoneFactory.makeDefaultPhone must be called from Looper thread");  
  8.             }  
  9.             int retryCount = 0;  
  10.             for(;;) {  
  11.                 boolean hasException = false;  
  12.                 retryCount ++;  
  13.                 try {  
  14.                     new LocalServerSocket("com.android.internal.telephony");  
  15.                 } catch (java.io.IOException ex) {  
  16.                     hasException = true;  
  17.                 }  
  18.                 if ( !hasException ) {  
  19.                     break;  
  20.                 } else if (retryCount > SOCKET_OPEN_MAX_RETRY) {  
  21.                     throw new RuntimeException("PhoneFactory probably already running");  
  22.                 } else {  
  23.                     try {  
  24.                         Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);  
  25.                     } catch (InterruptedException er) {  
  26.                     }  
  27.                 }  
  28.             }  
  29.             sPhoneNotifier = new DefaultPhoneNotifier();  
  30.             // Get preferred network mode   
  31.             int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;  
  32.             if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {  
  33.                 preferredNetworkMode = Phone.NT_MODE_GLOBAL;  
  34.             }  
  35.             //从数据库中读取网络模式   
  36.             int networkMode = Settings.Global.getInt(context.getContentResolver(),  
  37.                     Settings.Global.PREFERRED_NETWORK_MODE, preferredNetworkMode);  
  38.             Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode));  
  39.   
  40.             int cdmaSubscription;          
  41.             int lteOnCdma = TelephonyManager.getLteOnCdmaModeStatic();  
  42.             switch (lteOnCdma) {  
  43.                 case PhoneConstants.LTE_ON_CDMA_FALSE:  
  44.                     cdmaSubscription = CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV;  
  45.                     Log.i(LOG_TAG, "lteOnCdma is 0 use SUBSCRIPTION_FROM_NV");  
  46.                     break;  
  47.                 case PhoneConstants.LTE_ON_CDMA_TRUE:  
  48.                     cdmaSubscription = CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM;  
  49.                     Log.i(LOG_TAG, "lteOnCdma is 1 use SUBSCRIPTION_FROM_RUIM");  
  50.                     break;  
  51.                 case PhoneConstants.LTE_ON_CDMA_UNKNOWN:  
  52.                 default:  
  53.                     //Get cdmaSubscription mode from Settings.System   
  54.                     cdmaSubscription = Settings.Global.getInt(context.getContentResolver(),  
  55.                             Settings.Global.PREFERRED_CDMA_SUBSCRIPTION,  
  56.                             preferredCdmaSubscription);  
  57.                     Log.i(LOG_TAG, "lteOnCdma not set, using PREFERRED_CDMA_SUBSCRIPTION");  
  58.                     break;  
  59.             }  
  60.             Log.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);  
  61.             //reads the system properties and makes commandsinterface   
  62.             sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);  
  63.             // Instantiate UiccController so that all other classes can just call getInstance()   
  64.             UiccController.make(context, sCommandsInterface);    
  65.             //根据网络模式得到电话类型   
  66.             int phoneType = TelephonyManager.getPhoneType(networkMode);  
  67.             //根据电话类型创建对应类型的Phone对象,并且使用创建的Phone对象来构造PhoneProxy代理对象   
  68.             if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {  
  69.                 Log.i(LOG_TAG, "Creating GSMPhone");  
  70.                 sProxyPhone = new PhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));  
  71.             } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {  
  72.                 switch (TelephonyManager.getLteOnCdmaModeStatic()) {  
  73.                     case PhoneConstants.LTE_ON_CDMA_TRUE:  
  74.                         Log.i(LOG_TAG, "Creating CDMALTEPhone");  
  75.                         sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,sCommandsInterface, sPhoneNotifier));  
  76.                         break;  
  77.                     case PhoneConstants.LTE_ON_CDMA_FALSE:  
  78.                     default:  
  79.                         Log.i(LOG_TAG, "Creating CDMAPhone");  
  80.                         sProxyPhone = new PhoneProxy(new CDMAPhone(context,sCommandsInterface, sPhoneNotifier));  
  81.                         break;  
  82.                 }  
  83.             }  
  84.             sMadeDefaults = true;  
  85.         }  
  86.     }  
  87. }  
public static void makeDefaultPhone(Context context) {
synchronized(Phone.class) {
if (!sMadeDefaults) {
sLooper = Looper.myLooper();
sContext = context;
if (sLooper == null) {
throw new RuntimeException("PhoneFactory.makeDefaultPhone must be called from Looper thread");
}
int retryCount = 0;
for(;;) {
boolean hasException = false;
retryCount ++;
try {
new LocalServerSocket("com.android.internal.telephony");
} catch (java.io.IOException ex) {
hasException = true;
}
if ( !hasException ) {
break;
} else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
throw new RuntimeException("PhoneFactory probably already running");
} else {
try {
Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
} catch (InterruptedException er) {
}
}
}
sPhoneNotifier = new DefaultPhoneNotifier();
// Get preferred network mode
int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;
if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {
preferredNetworkMode = Phone.NT_MODE_GLOBAL;
}
//从数据库中读取网络模式
int networkMode = Settings.Global.getInt(context.getContentResolver(),
Settings.Global.PREFERRED_NETWORK_MODE, preferredNetworkMode);
Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode));
int cdmaSubscription;        
int lteOnCdma = TelephonyManager.getLteOnCdmaModeStatic();
switch (lteOnCdma) {
case PhoneConstants.LTE_ON_CDMA_FALSE:
cdmaSubscription = CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV;
Log.i(LOG_TAG, "lteOnCdma is 0 use SUBSCRIPTION_FROM_NV");
break;
case PhoneConstants.LTE_ON_CDMA_TRUE:
cdmaSubscription = CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM;
Log.i(LOG_TAG, "lteOnCdma is 1 use SUBSCRIPTION_FROM_RUIM");
break;
case PhoneConstants.LTE_ON_CDMA_UNKNOWN:
default:
//Get cdmaSubscription mode from Settings.System
cdmaSubscription = Settings.Global.getInt(context.getContentResolver(),
Settings.Global.PREFERRED_CDMA_SUBSCRIPTION,
preferredCdmaSubscription);
Log.i(LOG_TAG, "lteOnCdma not set, using PREFERRED_CDMA_SUBSCRIPTION");
break;
}
Log.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);
//reads the system properties and makes commandsinterface
sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
// Instantiate UiccController so that all other classes can just call getInstance()
UiccController.make(context, sCommandsInterface);  
//根据网络模式得到电话类型
int phoneType = TelephonyManager.getPhoneType(networkMode);
//根据电话类型创建对应类型的Phone对象,并且使用创建的Phone对象来构造PhoneProxy代理对象
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
Log.i(LOG_TAG, "Creating GSMPhone");
sProxyPhone = new PhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));
} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
switch (TelephonyManager.getLteOnCdmaModeStatic()) {
case PhoneConstants.LTE_ON_CDMA_TRUE:
Log.i(LOG_TAG, "Creating CDMALTEPhone");
sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,sCommandsInterface, sPhoneNotifier));
break;
case PhoneConstants.LTE_ON_CDMA_FALSE:
default:
Log.i(LOG_TAG, "Creating CDMAPhone");
sProxyPhone = new PhoneProxy(new CDMAPhone(context,sCommandsInterface, sPhoneNotifier));
break;
}
}
sMadeDefaults = true;
}
}
}
在PhoneFactory的makeDefaultPhone函数中,首先构造一个DefaultPhoneNotifier对象和RIL对象,然后从数据库中读取网络模式,根据网络模式得到对应的电话类型,从而构造对应的Phone对象,并为该Phone对象创建一个PhoneProxy代理对象。对于GSM网络,会构造一个GSMPhone对象

frameworks\base\telephony\java\com\android\internal\telephony\gsm\ GSMPhone.java 

[java] view plain copy print ?
  1. public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {  
  2.     super(notifier, context, ci, unitTestMode);  
  3.     mCM.setPhoneType(Phone.PHONE_TYPE_GSM);  
  4.     mIccCard.set(MsUiccController.getInstance(this).getIccCard());  
  5.     mIccRecords = mIccCard.get().getIccRecords();  
  6.     mCT = new GsmCallTracker(this);  
  7.     mSST = new GsmServiceStateTracker (this);  
  8.     mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);  
  9.     if (!unitTestMode) {  
  10.         mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);  
  11.         mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);  
  12.         mSubInfo = new PhoneSubInfo(this);  
  13.     }  
  14.     mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);  
  15.     registerForSimRecordEvents();  
  16.     mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);  
  17.     mCM.registerForOn(this, EVENT_RADIO_ON, null);  
  18.     mCM.setOnUSSD(this, EVENT_USSD, null);  
  19.     mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);  
  20.     mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);  
  21.   
  22.     mHandlerThread = new HandlerThread("GSMPhone_AsyncThread");  
  23.     mHandlerThread.start();  
  24.     mAsyncThread = new AsyncThread(mHandlerThread.getLooper());  
  25.     if (false) {  
  26.         try {  
  27.             //debugSocket = new LocalServerSocket("com.android.internal.telephony.debug");   
  28.             debugSocket = new ServerSocket();  
  29.             debugSocket.setReuseAddress(true);  
  30.             debugSocket.bind (new InetSocketAddress("127.0.0.1"6666));  
  31.   
  32.             debugPortThread  
  33.                 = new Thread(  
  34.                     new Runnable() {  
  35.                         public void run() {  
  36.                             for(;;) {  
  37.                                 try {  
  38.                                     Socket sock;  
  39.                                     sock = debugSocket.accept();  
  40.                                     Log.i(LOG_TAG, "New connection; resetting radio");  
  41.                                     mCM.resetRadio(null);  
  42.                                     sock.close();  
  43.                                 } catch (IOException ex) {  
  44.                                     Log.w(LOG_TAG,  
  45.                                         "Exception accepting socket", ex);  
  46.                                 }  
  47.                             }  
  48.                         }  
  49.                     },  
  50.                     "GSMPhone debug");  
  51.   
  52.             debugPortThread.start();  
  53.   
  54.         } catch (IOException ex) {  
  55.             Log.w(LOG_TAG, "Failure to open com.android.internal.telephony.debug socket", ex);  
  56.         }  
  57.     }  
  58.     //Change the system property   
  59.     SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,  
  60.             new Integer(Phone.PHONE_TYPE_GSM).toString());  
  61. }  
public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {
super(notifier, context, ci, unitTestMode);
mCM.setPhoneType(Phone.PHONE_TYPE_GSM);
mIccCard.set(MsUiccController.getInstance(this).getIccCard());
mIccRecords = mIccCard.get().getIccRecords();
mCT = new GsmCallTracker(this);
mSST = new GsmServiceStateTracker (this);
mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
if (!unitTestMode) {
mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);
mSubInfo = new PhoneSubInfo(this);
}
mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
registerForSimRecordEvents();
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);
mHandlerThread = new HandlerThread("GSMPhone_AsyncThread");
mHandlerThread.start();
mAsyncThread = new AsyncThread(mHandlerThread.getLooper());
if (false) {
try {
//debugSocket = new LocalServerSocket("com.android.internal.telephony.debug");
debugSocket = new ServerSocket();
debugSocket.setReuseAddress(true);
debugSocket.bind (new InetSocketAddress("127.0.0.1", 6666));
debugPortThread
= new Thread(
new Runnable() {
public void run() {
for(;;) {
try {
Socket sock;
sock = debugSocket.accept();
Log.i(LOG_TAG, "New connection; resetting radio");
mCM.resetRadio(null);
sock.close();
} catch (IOException ex) {
Log.w(LOG_TAG,
"Exception accepting socket", ex);
}
}
}
},
"GSMPhone debug");
debugPortThread.start();
} catch (IOException ex) {
Log.w(LOG_TAG, "Failure to open com.android.internal.telephony.debug socket", ex);
}
}
//Change the system property
SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
new Integer(Phone.PHONE_TYPE_GSM).toString());
}
在构造GSMPhone对象时,首先使用父类的成员变量CommandsInterfac mCM设置电话类型,由于RIL类实现了CommandsInterfac接口,因此mCM引用RIL对象。在构造GSMPhone对象时通过参数传入并设置父类PhoneBase的成员变量mCM。

frameworks\base\telephony\java\com\android\internal\telephony\ PhoneBase.java

[java] view plain copy print ?
  1. protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,  
  2.         boolean unitTestMode) {  
  3.     this.mNotifier = notifier;  
  4.     this.mContext = context;  
  5.     mLooper = Looper.myLooper();  
  6.     mCM = ci;  
  7.     setPropertiesByCarrier();  
  8.     setUnitTestMode(unitTestMode);  
  9.     SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);  
  10.     mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);  
  11.     mCM.setOnCallRing(this, EVENT_CALL_RING, null);  
  12.     mIsVoiceCapable = mContext.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);  
  13.     mDoesRilSendMultipleCallRing = SystemProperties.getBoolean(  
  14.             TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true);  
  15.     Log.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);  
  16.     mCallRingDelay = SystemProperties.getInt(  
  17.             TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);  
  18.     Log.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);  
  19.     // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.   
  20.     mSmsStorageMonitor = new SmsStorageMonitor(this);  
  21.     mSmsUsageMonitor = new SmsUsageMonitor(context);  
  22. }  
protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,
boolean unitTestMode) {
this.mNotifier = notifier;
this.mContext = context;
mLooper = Looper.myLooper();
mCM = ci;
setPropertiesByCarrier();
setUnitTestMode(unitTestMode);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);
mCM.setOnCallRing(this, EVENT_CALL_RING, null);
mIsVoiceCapable = mContext.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
mDoesRilSendMultipleCallRing = SystemProperties.getBoolean(
TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true);
Log.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
mCallRingDelay = SystemProperties.getInt(
TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);
Log.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);
// Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
mSmsStorageMonitor = new SmsStorageMonitor(this);
mSmsUsageMonitor = new SmsUsageMonitor(context);
}
构造GSMPhone对象同时也会创建一个GsmCallTracker对象,GSMCallTracker实现了电话的拨打(Dial)、接听/拒绝(accept/reject)、挂断(hangup)、保持(hold)、切换以及电话会议等功能,它还负责查询Modem当前有多少路通话,维护电话状态等功能。GSMCallTracker中包含了GsmConnection、RegistrantList、 GSMCall和Phone.State等类的对象实例。在GSMCallTracker构造函数中向RIL类实例注册了RegistrantList,当通话状态及射频Radio状态变化时,就会通知GSMCallTracker。
frameworks\base\telephony\java\com\android\internal\telephony\gsm\ GsmCallTracker.java 
[java] view plain copy print ?
  1. GsmCallTracker (GSMPhone phone) {  
  2.     this.phone = phone;  
  3.     cm = phone.mCM;  
  4.     cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);  
  5.     cm.registerForVideoCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);  
  6.     cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null);  
  7.     cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);  
  8.     sendEmptyMessage(EVENT_INITIALIZE);  
  9. }  
GsmCallTracker (GSMPhone phone) {
this.phone = phone;
cm = phone.mCM;
cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
cm.registerForVideoCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null);
cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);
sendEmptyMessage(EVENT_INITIALIZE);
}
cm引用RIL对象,在这里注册了电话状态改变事件,视频电话状态改变事件,无线开关事件等。由于RIL实现了CommandsInterface接口,并继承于BaseCommands抽象类,registerForCallStateChanged函数实现在RIL的父类BaseCommands中

这里为RIL注册了一些消息事件,并指定GsmCallTracker来处理这些消息。
frameworks\base\telephony\java\com\android\internal\telephony\BaseCommands.java

[java] view plain copy print ?
  1. public void registerForCallStateChanged(Handler h, int what, Object obj) {  
  2.     Registrant r = new Registrant (h, what, obj);  
  3.     mCallStateRegistrants.add(r);  
  4. }  
public void registerForCallStateChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
mCallStateRegistrants.add(r);
}
该函数通过Handler及对应的事件消息来构造一个Registrant对象,并将其注册到mCallStateRegistrants对象中,mCallStateRegistrants为RegistrantList类型变量,定义在RIL的父类BaseCommands中,RegistrantList类是用于保存注册的处理指定消息的所有Handler,RegistrantList类首先将某个消息及处理该消息的Handler封装成Registrant对象,并将该对象保存到成员变量registrants动态数组中。
frameworks\base\core\java\android\os\RegistrantList.java

[java] view plain copy print ?
  1. ArrayList   registrants = new ArrayList();       
  2. public synchronized void add(Handler h, int what, Object obj){  
  3.     add(new Registrant(h, what, obj));  
  4. }  
  5.   
  6. public synchronized void add(Registrant r){  
  7.     removeCleared();  
  8.     registrants.add(r);  
  9. }  
ArrayList   registrants = new ArrayList();     
public synchronized void add(Handler h, int what, Object obj){
add(new Registrant(h, what, obj));
}
public synchronized void add(Registrant r){
removeCleared();
registrants.add(r);
}
对于电话状态改变事件,注册的Handle对象为GsmCallTracker,因此在电话状态改变事件到来时,GsmCallTracker将处理EVENT_CALL_STATE_CHANGE消息事件。


GsmCallTracker有三个成员变量:

GsmCall ringingCall = new GsmCall(this) 前台Call,其中对应的Connection是ACTIVE,DIALING,ALERTING状态的,即激活状态
GsmCall foregroundCall = new GsmCall(this) 后台Call,其中对应的Connection是HOLDING状态的,即保持状态
GsmCall backgroundCall = new GsmCall(this) 来电Call,其中对应的Connection是INCOMING,WAITING状态的,即来电状态

Phone层事件注册过程

在Phone进程启动的时,PhoneApp的onCreate函数首先被调用,PhoneApp会构造各种全局对象,同时也会注册一些事件。

[java] view plain copy print ?
  1. mCM = CallManager.getInstance();  
  2. mCM.registerPhone(phone);  
mCM = CallManager.getInstance();
mCM.registerPhone(phone);
函数registerPhone为构造的相应类型的phone对象注册一些事件
frameworks\base\telephony\java\com\android\internal\telephony\CallManager.java
[java] view plain copy print ?
  1. public boolean registerPhone(Phone phone) {  
  2.     Phone basePhone = getPhoneBase(phone);  
  3.     if (basePhone != null && !mPhones.contains(basePhone)) {  
  4.         if (DBG) {  
  5.             Log.d(LOG_TAG, "registerPhone(" +  
  6.                     phone.getPhoneName() + " " + phone + ")");  
  7.         }  
  8.         if (mPhones.isEmpty()) {  
  9.             mDefaultPhone = basePhone;  
  10.         }  
  11.         mPhones.add(basePhone);  
  12.         mRingingCalls.add(basePhone.getRingingCall());  
  13.         mBackgroundCalls.add(basePhone.getBackgroundCall());  
  14.         mForegroundCalls.add(basePhone.getForegroundCall());  
  15.         registerForPhoneStates(basePhone);  
  16.         return true;  
  17.     }  
  18.     return false;  
  19. }  
public boolean registerPhone(Phone phone) {
Phone basePhone = getPhoneBase(phone);
if (basePhone != null && !mPhones.contains(basePhone)) {
if (DBG) {
Log.d(LOG_TAG, "registerPhone(" +
phone.getPhoneName() + " " + phone + ")");
}
if (mPhones.isEmpty()) {
mDefaultPhone = basePhone;
}
mPhones.add(basePhone);
mRingingCalls.add(basePhone.getRingingCall());
mBackgroundCalls.add(basePhone.getBackgroundCall());
mForegroundCalls.add(basePhone.getForegroundCall());
registerForPhoneStates(basePhone);
return true;
}
return false;
}
registerForPhoneStates函数用于注册电话状态变化事件
[java] view plain copy print ?
  1. private void registerForPhoneStates(Phone phone) {  
  2.     // for common events supported by all phones   
  3.     phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);  
  4.     phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);  
  5.     phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);  
  6.     phone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null);  
  7.     phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);  
  8.     phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);  
  9.     phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);  
  10.     phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);  
  11.     phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);  
  12.     phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);  
  13.     phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);  
  14.     phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);  
  15.     phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);  
  16.     phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);  
  17.     phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);  
  18.   
  19.     // for events supported only by GSM and CDMA phone   
  20.     if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ||  
  21.             phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {  
  22.         phone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL_CHARACTER, null);  
  23.     }  
  24.   
  25.     // for events supported only by CDMA phone   
  26.     if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ){  
  27.         phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);  
  28.         phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);  
  29.         phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);  
  30.         phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);  
  31.     }  
  32. }  
private void registerForPhoneStates(Phone phone) {
// for common events supported by all phones
phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
phone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null);
phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);
phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);
phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);
phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);
phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);
phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);
phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);
// for events supported only by GSM and CDMA phone
if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ||
phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
phone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL_CHARACTER, null);
}
// for events supported only by CDMA phone
if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ){
phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
}
}
此时的Phone类型为GsmPhone,其父类为PhoneBase,这里为PhoneBase注册了一些消息事件,并指定CallManager类的mHandler来处理这些消息。

CallManager层事件注册过程

在启动PhoneApp时,同样也会创建一个CallNotifier对象
[java] view plain copy print ?
  1. notifier = CallNotifier.init(this, phone, ringer, mBtHandsfree, new CallLogAsync());  
notifier = CallNotifier.init(this, phone, ringer, mBtHandsfree, new CallLogAsync());
参数phone是通过PhoneFactory.getDefaultPhone()创建而来的,创建过程在前面已经详细介绍了。
参数ringer的构造过程如下:
[java] view plain copy print ?
  1. ringer = Ringer.init(this);  
  2. static Ringer init(Context context) {  
  3.     synchronized (Ringer.class) {  
  4.         if (sInstance == null) {  
  5.             sInstance = new Ringer(context);  
  6.         } else {  
  7.             Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);  
  8.         }  
  9.         return sInstance;  
  10.     }  
  11. }  
  12.   
  13. private Ringer(Context context) {  
  14.     mContext = context;  
  15.     mPowerManager = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));  
  16.     mVibrator = new SystemVibrator();  
  17. }  
ringer = Ringer.init(this);
static Ringer init(Context context) {
synchronized (Ringer.class) {
if (sInstance == null) {
sInstance = new Ringer(context);
} else {
Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
}
return sInstance;
}
}
private Ringer(Context context) {
mContext = context;
mPowerManager = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
mVibrator = new SystemVibrator();
}
参数mBtHandsfree的构造过程如下:
[java] view plain copy print ?
  1. mBtHandsfree = BluetoothHandsfree.init(this, mCM);  
  2. static BluetoothHandsfree init(Context context, CallManager cm) {  
  3.     synchronized (BluetoothHandsfree.class) {  
  4.         if (sInstance == null) {  
  5.             sInstance = new BluetoothHandsfree(context, cm);  
  6.         } else {  
  7.             Log.wtf(TAG, "init() called multiple times!  sInstance = " + sInstance);  
  8.         }  
  9.         return sInstance;  
  10.     }  
  11. }  
mBtHandsfree = BluetoothHandsfree.init(this, mCM);
static BluetoothHandsfree init(Context context, CallManager cm) {
synchronized (BluetoothHandsfree.class) {
if (sInstance == null) {
sInstance = new BluetoothHandsfree(context, cm);
} else {
Log.wtf(TAG, "init() called multiple times!  sInstance = " + sInstance);
}
return sInstance;
}
}
CallNotifier对象构造过程:
packages\apps\Phone\src\com\android\phone\CallNotifier.java
[java] view plain copy print ?
  1. static CallNotifier init(PhoneApp app, Phone phone, Ringer ringer,  
  2.                                        BluetoothHandsfree btMgr, CallLogAsync callLog) {  
  3.     synchronized (CallNotifier.class) {  
  4.         if (sInstance == null) {  
  5.             sInstance = new CallNotifier(app, phone, ringer, btMgr, callLog);  
  6.         } else {  
  7.             Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);  
  8.         }  
  9.         return sInstance;  
  10.     }  
  11. }  
  12.   
  13. protected CallNotifier(PhoneApp app, Phone phone, Ringer ringer,  
  14.                      BluetoothHandsfree btMgr, CallLogAsync callLog) {  
  15.     mApplication = app;  
  16.     mCM = app.mCM;  
  17.     mCallLog = callLog;  
  18.     mLndAsync = new LndAsync();  
  19.   
  20.     telMgr = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);  
  21.     mAudioManager = (AudioManager) mApplication.getSystemService(Context.AUDIO_SERVICE);  
  22.     registerForNotifications();  
  23.     try {  
  24.         mSignalInfoToneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL,  
  25.                 TONE_RELATIVE_VOLUME_SIGNALINFO);  
  26.     } catch (RuntimeException e) {  
  27.         Log.e(LOG_TAG, "CallNotifier: Exception caught while creating " +  
  28.                 "mSignalInfoToneGenerator: " + e);  
  29.         mSignalInfoToneGenerator = null;  
  30.     }  
  31.     mRinger = ringer;  
  32.     mBluetoothHandsfree = btMgr;  
  33.     listen();  
  34. }  
static CallNotifier init(PhoneApp app, Phone phone, Ringer ringer,
BluetoothHandsfree btMgr, CallLogAsync callLog) {
synchronized (CallNotifier.class) {
if (sInstance == null) {
sInstance = new CallNotifier(app, phone, ringer, btMgr, callLog);
} else {
Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
}
return sInstance;
}
}
protected CallNotifier(PhoneApp app, Phone phone, Ringer ringer,
BluetoothHandsfree btMgr, CallLogAsync callLog) {
mApplication = app;
mCM = app.mCM;
mCallLog = callLog;
mLndAsync = new LndAsync();
telMgr = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);
mAudioManager = (AudioManager) mApplication.getSystemService(Context.AUDIO_SERVICE);
registerForNotifications();
try {
mSignalInfoToneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL,
TONE_RELATIVE_VOLUME_SIGNALINFO);
} catch (RuntimeException e) {
Log.e(LOG_TAG, "CallNotifier: Exception caught while creating " +
"mSignalInfoToneGenerator: " + e);
mSignalInfoToneGenerator = null;
}
mRinger = ringer;
mBluetoothHandsfree = btMgr;
listen();
}
这构造CallNotifier对象过程中,为CallManager层注册了一些消息事件,并指定CallNotifier来处理这些消息
[java] view plain copy print ?
  1. private void registerForNotifications() {  
  2.     mCM.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);  
  3.     mCM.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null);  
  4.     mCM.registerForDisconnect(this, PHONE_DISCONNECT, null);  
  5.     mCM.registerForUnknownConnection(this, PHONE_UNKNOWN_CONNECTION_APPEARED, null);  
  6.     mCM.registerForIncomingRing(this, PHONE_INCOMING_RING, null);  
  7.     mCM.registerForCdmaOtaStatusChange(this, EVENT_OTA_PROVISION_CHANGE, null);  
  8.     mCM.registerForCallWaiting(this, PHONE_CDMA_CALL_WAITING, null);  
  9.     mCM.registerForDisplayInfo(this, PHONE_STATE_DISPLAYINFO, null);  
  10.     mCM.registerForSignalInfo(this, PHONE_STATE_SIGNALINFO, null);  
  11.     mCM.registerForInCallVoicePrivacyOn(this, PHONE_ENHANCED_VP_ON, null);  
  12.     mCM.registerForInCallVoicePrivacyOff(this, PHONE_ENHANCED_VP_OFF, null);  
  13.     mCM.registerForRingbackTone(this, PHONE_RINGBACK_TONE, null);  
  14.     mCM.registerForResendIncallMute(this, PHONE_RESEND_MUTE, null);  
  15. }  
private void 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);
}
1.当有PHONE_NEW_RINGING_CONNECTION类型消息到来时,意味着一个RINGING或WAITING的连接(connection)出现,此时handleMessage函数调用onNewRingingConnection来处理。后者先检查Settings里的设置是否可以接听电话;然后进    行响铃(见InCallTonePlayer)和显示InCallScreen的UI,见PhoneUtils.showIncomingCallUi()和PhoneApp.displayCallScreen()两个函数。通话过程中的铃音提示由线程类InCallTonePlayer完成。
2.当有PHONE_INCOMING_RING类型的消息到来时,意味着RIL层受到Ring,此处播放铃音。它使用的是Ringer.ring()函数,它会创建一个线程去播放铃音,见Ringer.makeLooper函数。
3.当有PHONE_STATE_CHANGED消息时,表明Phone的状态发生了改变,比如响铃后接通了电话,此时处理函数是onPhoneStateChanged,比如再次确认停止铃音、更新状态栏列的状态通知等。
4.当有PHONE_DISCONNECT消息时,表明电话连接已挂断或RingCall断掉。其处理函数是onDisconnect。它清理现场诸如音频通道恢复、来电响铃的停止确认、对InCallScreen的UI清理、若有未接电话须在状态栏显示等。
CallManager类的消息注册方法:


电话状态改变事件处理

我们已经知道在RIL中分别创建了两个线程,一个用于往rild套接字中写入数据,一个用于从该套接字中读取rild服务进程发送上来的数据。对于来电事件,RILReceiver会读取到rild发送过来的来电信息。

frameworks\base\telephony\java\com\android\internal\telephony\RIL.java

[java] view plain copy print ?
  1. try {  
  2.     InputStream is = mSocket.getInputStream();  
  3.     for (;;) {  
  4.         Parcel p;  
  5.         //从rild套接字中读取消息   
  6.         length = readRilMessage(is, buffer);  
  7.         if (length < 0) {  
  8.             // End-of-stream reached   
  9.             break;  
  10.         }  
  11.         //将读取到的数据序列化到Parcel对象中   
  12.         p = Parcel.obtain();  
  13.         p.unmarshall(buffer, 0, length);  
  14.         p.setDataPosition(0);  
  15.         //数据处理   
  16.         processResponse(p);  
  17.         p.recycle();  
  18.     }  
  19. catch (java.io.IOException ex) {  
  20.     Log.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed", ex);  
  21. catch (Throwable tr) {  
  22.     Log.e(LOG_TAG, "Uncaught exception read length=" + length +  
  23.         "Exception:" + tr.toString());  
  24. }  
try {
InputStream is = mSocket.getInputStream();
for (;;) {
Parcel p;
//从rild套接字中读取消息
length = readRilMessage(is, buffer);
if (length < 0) {
// End-of-stream reached
break;
}
//将读取到的数据序列化到Parcel对象中
p = Parcel.obtain();
p.unmarshall(buffer, 0, length);
p.setDataPosition(0);
//数据处理
processResponse(p);
p.recycle();
}
} catch (java.io.IOException ex) {
Log.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed", ex);
} catch (Throwable tr) {
Log.e(LOG_TAG, "Uncaught exception read length=" + length +
"Exception:" + tr.toString());
}
这段代码是RILReceiver线程不断循环读取来自rild的AT Response,调用processResponse进行处理,根据返回结果中不同的Request号,调用到相应的responseXXX函数簇,获取AT执行结果。

[java] view plain copy print ?
  1. private void processResponse (Parcel p) {  
  2.     int type;  
  3.   
  4.     type = p.readInt();  
  5.   
  6.     if (type == RESPONSE_UNSOLICITED) {  
  7.         processUnsolicited (p);  
  8.     } else if (type == RESPONSE_SOLICITED) {  
  9.         processSolicited (p);  
  10.     }  
  11.     releaseWakeLockIfDone();  
  12. }  
private void processResponse (Parcel p) {
int type;
type = p.readInt();
if (type == RESPONSE_UNSOLICITED) {
processUnsolicited (p);
} else if (type == RESPONSE_SOLICITED) {
processSolicited (p);
}
releaseWakeLockIfDone();
}

在Android之rild进程启动源码分析介绍了,rild服务进程会接收到两种类型的消息,一种是Ap向Bp发送请求,Bp给Ap发送回复消息,一种是Bp主动给Ap发送事件,对于请求响应事件,调用processSolicited函数来处理,而对于BP主动发起的事件则调用processUnsolicited函数来处理。来电属于BP主动发起的请求事件,因此processUnsolicited函数将处理来电请求

[java] view plain copy print ?
  1. protected void processUnsolicited (Parcel p) {  
  2.     int response;  
  3.     Object ret;  
  4.     response = p.readInt();  
  5.     try {  
  6.         switch(response) {  
  7.             case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret =  responseVoid(p); break;           
  8.             default:  
  9.                 throw new RuntimeException("Unrecognized unsol response: " + response);  
  10.         }  
  11.     } catch (Throwable tr) {  
  12.         Log.e(LOG_TAG, "Exception processing unsol response: " + response +  
  13.             "Exception:" + tr.toString());  
  14.         return;  
  15.     }  
  16.     switch(response) {  
  17.         case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:  
  18.             if (RILJ_LOGD) unsljLog(response);  
  19.             mCallStateRegistrants.notifyRegistrants(new AsyncResult(nullnullnull));  
  20.         break;  
  21.     }  
  22. }  
protected void processUnsolicited (Parcel p) {
int response;
Object ret;
response = p.readInt();
try {
switch(response) {
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret =  responseVoid(p); break;         
default:
throw new RuntimeException("Unrecognized unsol response: " + response);
}
} catch (Throwable tr) {
Log.e(LOG_TAG, "Exception processing unsol response: " + response +
"Exception:" + tr.toString());
return;
}
switch(response) {
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
if (RILJ_LOGD) unsljLog(response);
mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
break;
}
}
mCallStateRegistrants为RegistrantList类型变量,前面已经介绍了消息注册过程,这里调用RegistrantList的notifyRegistrants函数来通知所有注册过该消息的Handler处理该消息。

frameworks\base\core\java\android\os\RegistrantList.java

[java] view plain copy print ?
  1. public void  notifyRegistrants(){  
  2.     internalNotifyRegistrants(nullnull);  
  3. }  
  4.   
  5. private synchronized void  internalNotifyRegistrants (Object result, Throwable exception){  
  6.    for (int i = 0, s = registrants.size(); i < s ; i++) {  
  7.         Registrant  r = (Registrant) registrants.get(i);  
  8.         r.internalNotifyRegistrant(result, exception);  
  9.    }  
  10. }  
public void  notifyRegistrants(){
internalNotifyRegistrants(null, null);
}
private synchronized void  internalNotifyRegistrants (Object result, Throwable exception){
for (int i = 0, s = registrants.size(); i < s ; i++) {
Registrant  r = (Registrant) registrants.get(i);
r.internalNotifyRegistrant(result, exception);
}
}
这里循环遍历成员变量registrants中保存的所有Registrant对象,前面介绍到,在注册某个Handler处理指定消息时,首先将其封装为Registrant对象,这里取出该消息对应的所有Registrant对象,并调用该对象的internalNotifyRegistrant函数来触发注册的Handler处理该消息。
frameworks\base\core\java\android\os\Registrant.java
[java] view plain copy print ?
  1. void internalNotifyRegistrant (Object result, Throwable exception){  
  2.     Handler h = getHandler();  
  3.     if (h == null) {  
  4.         clear();  
  5.     } else {  
  6.         Message msg = Message.obtain();  
  7.         msg.what = what;  
  8.         msg.obj = new AsyncResult(userObj, result, exception);  
  9.         h.sendMessage(msg);  
  10.     }  
  11. }  
void internalNotifyRegistrant (Object result, Throwable exception){
Handler h = getHandler();
if (h == null) {
clear();
} else {
Message msg = Message.obtain();
msg.what = what;
msg.obj = new AsyncResult(userObj, result, exception);
h.sendMessage(msg);
}
}
该函数其是就是向注册的Handler中发送消息,消息为注册的消息类型。由于在构造GsmCallTracker对象时,已经在BaseCommands中注册了EVENT_CALL_STATE_CHANGE消息的处理Handler为GsmCallTracker对象本身,

cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);

因此mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null))将向GsmCallTracker对象发送EVENT_CALL_STATE_CHANGE的消息

frameworks\base\telephony\java\com\android\internal\telephony\CallTracker.java

[java] view plain copy print ?
  1. public void handleMessage (Message msg) {  
  2.      AsyncResult ar;  
  3.      switch (msg.what) {  
  4.        case EVENT_CALL_STATE_CHANGE:  
  5.             pollCallsWhenSafe();  
  6.           break;  
  7.      }  
  8. }  
public void handleMessage (Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_CALL_STATE_CHANGE:
pollCallsWhenSafe();
break;
}
}
函数最终调用pollCallsWhenSafe来处理EVENT_CALL_STATE_CHANGE消息,pollCallsWhenSafe用于查询当前的通话状态。

[java] view plain copy print ?
  1. protected void pollCallsWhenSafe() {  
  2.     needsPoll = true;  
  3.     if (checkNoOperationsPending()) {  
  4.         lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);  
  5.         cm.getCurrentCalls(lastRelevantPoll);  
  6.     }  
  7. }  
protected void pollCallsWhenSafe() {
needsPoll = true;
if (checkNoOperationsPending()) {
lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
cm.getCurrentCalls(lastRelevantPoll);
}
}
函数checkNoOperationsPending就是判断变量pendingOperations是否等于0,如果等于0,则调用CommandsInterface的getCurrentCalls函数来发送一个EVENT_POLL_CALLS_RESULT消息,该函数实现在RIL.java中。

AT命令CLCC查询结果对应于Connection类中的成员变量,一 路电话对应一个对象。

frameworks\base\telephony\java\com\android\internal\telephony\RIL.java

[java] view plain copy print ?
  1. public void getCurrentCalls (Message result) {  
  2.     RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);  
  3.     if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));  
  4.     send(rr);  
  5. }  
public void getCurrentCalls (Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}

函数首先根据传进来的参数获取一个RILRequest请求对象,并调用send函数通过RILSender线程向rild服务进程发送RIL_REQUEST_GET_CURRENT_CALLS请求,请求查询当前所有的电话连接,使用CLCC 命令查询,底层返回来的查询结果如下         格式      |序号|0表示来电、1表示去电|电话状态|数据业务还是语音业务|是否是视频会议|号码

CLCC : 1、                   0、                        2、                     0、                            0                 1881234578 …..

每个通话连接用通话列表用DriverCall类表示。

这里介绍一下RILRequest数据结构

Android使用了一个RILRequest对象池来管理RILRequest


[java] view plain copy print ?
  1. static RILRequest obtain(int request, Message result) {  
  2.     RILRequest rr = null;  
  3.     synchronized(sPoolSync) {  
  4.         if (sPool != null) {  
  5.             rr = sPool;  
  6.             sPool = rr.mNext;  
  7.             rr.mNext = null;  
  8.             sPoolSize--;  
  9.         }  
  10.     }  
  11.     if (rr == null) {  
  12.         rr = new RILRequest();  
  13.     }  
  14.     synchronized(sSerialMonitor) {  
  15.         rr.mSerial = sNextSerial++;  
  16.     }  
  17.     rr.mRequest = request;  
  18.     rr.mResult = result;  
  19.     rr.mp = Parcel.obtain();  
  20.     if (result != null && result.getTarget() == null) {  
  21.         throw new NullPointerException("Message target must not be null");  
  22.     }  
  23.     rr.mp.writeInt(request);  
  24.     rr.mp.writeInt(rr.mSerial);  
  25.     return rr;  
  26. }  
static RILRequest obtain(int request, Message result) {
RILRequest rr = null;
synchronized(sPoolSync) {
if (sPool != null) {
rr = sPool;
sPool = rr.mNext;
rr.mNext = null;
sPoolSize--;
}
}
if (rr == null) {
rr = new RILRequest();
}
synchronized(sSerialMonitor) {
rr.mSerial = sNextSerial++;
}
rr.mRequest = request;
rr.mResult = result;
rr.mp = Parcel.obtain();
if (result != null && result.getTarget() == null) {
throw new NullPointerException("Message target must not be null");
}
rr.mp.writeInt(request);
rr.mp.writeInt(rr.mSerial);
return rr;
}
当Phone进程从framework层向rild服务进程发送完RIL_REQUEST_GET_CURRENT_CALLS请求后,就等待接收rild返回对该消息的处理结果,RILReceiver线程将读取到该消息事件,并调用processSolicited函数来处理。

frameworks\base\telephony\java\com\android\internal\telephony\RIL.java

[java] view plain copy print ?
  1. protected void processSolicited (Parcel p) {  
  2.     int serial, error;  
  3.     boolean found = false;  
  4.     serial = p.readInt();  
  5.     error = p.readInt();  
  6.     RILRequest rr;  
  7.     rr = findAndRemoveRequestFromList(serial);  
  8.     if (rr == null) {  
  9.         Log.w(LOG_TAG, "Unexpected solicited response! sn: "+ serial + " error: " + error);  
  10.         return;  
  11.     }  
  12.     Object ret = null;  
  13.     if (error == 0 || p.dataAvail() > 0) {  
  14.         try {  
  15.             switch (rr.mRequest) {  
  16.                             case RIL_REQUEST_GET_CURRENT_CALLS: ret =  responseCallList(p); break;  
  17.                         }  
  18.                 } catch (Throwable tr) {  
  19.             if (rr.mResult != null) {  
  20.                 AsyncResult.forMessage(rr.mResult, null, tr);  
  21.                 rr.mResult.sendToTarget();  
  22.             }  
  23.             rr.release();  
  24.             return;  
  25.         }  
  26.     }  
  27.     if (error != 0) {  
  28.         rr.onError(error, ret);  
  29.         rr.release();  
  30.         return;  
  31.     }  
  32.     if (rr.mResult != null) {  
  33.         AsyncResult.forMessage(rr.mResult, ret, null);  
  34.         rr.mResult.sendToTarget();  
  35.     }  
  36.     rr.release();  
  37. }  
protected void processSolicited (Parcel p) {
int serial, error;
boolean found = false;
serial = p.readInt();
error = p.readInt();
RILRequest rr;
rr = findAndRemoveRequestFromList(serial);
if (rr == null) {
Log.w(LOG_TAG, "Unexpected solicited response! sn: "+ serial + " error: " + error);
return;
}
Object ret = null;
if (error == 0 || p.dataAvail() > 0) {
try {
switch (rr.mRequest) {
case RIL_REQUEST_GET_CURRENT_CALLS: ret =  responseCallList(p); break;
}
} catch (Throwable tr) {
if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, null, tr);
rr.mResult.sendToTarget();
}
rr.release();
return;
}
}
if (error != 0) {
rr.onError(error, ret);
rr.release();
return;
}
if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, ret, null);
rr.mResult.sendToTarget();
}
rr.release();
}

读取RIL请求序列号并依次在RILRequest列表中查找已发送过的RILRequest请求

[java] view plain copy print ?
  1. protected RILRequest findAndRemoveRequestFromList(int serial) {  
  2.     synchronized (mRequestsList) {  
  3.             // 通过序号从变量列表mRequestsList中查找出指定的RILRequest   
  4.         for (int i = 0, s = mRequestsList.size() ; i < s ; i++) {  
  5.             RILRequest rr = mRequestsList.get(i);  
  6.             if (rr.mSerial == serial) {  
  7.                 mRequestsList.remove(i);  
  8.                 if (mRequestMessagesWaiting > 0)  
  9.                     mRequestMessagesWaiting--;  
  10.                 return rr;  
  11.             }  
  12.         }  
  13.     }  
  14.     return null;  
  15. }  
protected RILRequest findAndRemoveRequestFromList(int serial) {
synchronized (mRequestsList) {
// 通过序号从变量列表mRequestsList中查找出指定的RILRequest
for (int i = 0, s = mRequestsList.size() ; i < s ; i++) {
RILRequest rr = mRequestsList.get(i);
if (rr.mSerial == serial) {
mRequestsList.remove(i);
if (mRequestMessagesWaiting > 0)
mRequestMessagesWaiting--;
return rr;
}
}
}
return null;
}
若AT执行成功并有结果数据需要获取,则进入到switch-case语句根据请求号调用相应的responseXXX函数获得AT执行结果数据,放置在Object对象ret中;在取AT执行结果时若有异常发生,则ret保持为null空值。若AT执行发生错误时,则调用RILRequest的onError函数,这里的请求号为RIL_REQUEST_GET_CURRENT_CALLS,因此通过函数responseCallList读取查询结果

[java] view plain copy print ?
  1. protected Object responseCallList(Parcel p) {  
  2.     int num;  
  3.     int voiceSettings;  
  4.     ArrayList<DriverCall> response; //保存通话列表   
  5.     DriverCall dc;  
  6.     num = p.readInt();//读取通话列表数目   
  7.     response = new ArrayList<DriverCall>(num);  
  8.     //根据CLCC查询到的通话列表创建DriverCall   
  9.     for (int i = 0 ; i < num ; i++) {  
  10.         dc = new DriverCall();  
  11.         dc.state = DriverCall.stateFromCLCC(p.readInt());  
  12.         dc.index = p.readInt();  
  13.         dc.TOA = p.readInt();  
  14.         dc.isMpty = (0 != p.readInt());  
  15.         dc.isMT = (0 != p.readInt());  
  16.         dc.als = p.readInt();  
  17.         voiceSettings = p.readInt();  
  18.         dc.isVoice = (0 == voiceSettings) ? false : true;  
  19.         dc.isVoicePrivacy = (0 != p.readInt());  
  20.         dc.number = p.readString();  
  21.         int np = p.readInt();  
  22.         dc.numberPresentation = DriverCall.presentationFromCLIP(np);  
  23.         dc.name = p.readString();  
  24.         dc.namePresentation = p.readInt();  
  25.         int uusInfoPresent = p.readInt();  
  26.         if (uusInfoPresent == 1) {  
  27.             dc.uusInfo = new UUSInfo();  
  28.             dc.uusInfo.setType(p.readInt());  
  29.             dc.uusInfo.setDcs(p.readInt());  
  30.             byte[] userData = p.createByteArray();  
  31.             dc.uusInfo.setUserData(userData);  
  32.             riljLogv(String.format("Incoming UUS : type=%d, dcs=%d, length=%d",  
  33.                             dc.uusInfo.getType(), dc.uusInfo.getDcs(),  
  34.                             dc.uusInfo.getUserData().length));  
  35.             riljLogv("Incoming UUS : data (string)="  
  36.                     + new String(dc.uusInfo.getUserData()));  
  37.             riljLogv("Incoming UUS : data (hex): "  
  38.                     + IccUtils.bytesToHexString(dc.uusInfo.getUserData()));  
  39.         } else {  
  40.             riljLogv("Incoming UUS : NOT present!");  
  41.         }  
  42.   
  43.         // Make sure there's a leading + on addresses with a TOA of 145   
  44.         dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA);  
  45.   
  46.         response.add(dc);  
  47.   
  48.         if (dc.isVoicePrivacy) {  
  49.             mVoicePrivacyOnRegistrants.notifyRegistrants();  
  50.             riljLog("InCall VoicePrivacy is enabled");  
  51.         } else {  
  52.             mVoicePrivacyOffRegistrants.notifyRegistrants();  
  53.             riljLog("InCall VoicePrivacy is disabled");  
  54.         }  
  55.     }  
  56.   
  57.     Collections.sort(response);  
  58.   
  59.     if ((num == 0) && mTestingEmergencyCall.getAndSet(false)) {  
  60.         if (mEmergencyCallbackModeRegistrant != null) {  
  61.             riljLog("responseCallList: call ended, testing emergency call," +  
  62.                         " notify ECM Registrants");  
  63.             mEmergencyCallbackModeRegistrant.notifyRegistrant();  
  64.         }  
  65.     }  
  66.   
  67.     return response;  
  68. }  
protected Object responseCallList(Parcel p) {
int num;
int voiceSettings;
ArrayList<DriverCall> response; //保存通话列表
DriverCall dc;
num = p.readInt();//读取通话列表数目
response = new ArrayList<DriverCall>(num);
//根据CLCC查询到的通话列表创建DriverCall
for (int i = 0 ; i < num ; i++) {
dc = new DriverCall();
dc.state = DriverCall.stateFromCLCC(p.readInt());
dc.index = p.readInt();
dc.TOA = p.readInt();
dc.isMpty = (0 != p.readInt());
dc.isMT = (0 != p.readInt());
dc.als = p.readInt();
voiceSettings = p.readInt();
dc.isVoice = (0 == voiceSettings) ? false : true;
dc.isVoicePrivacy = (0 != p.readInt());
dc.number = p.readString();
int np = p.readInt();
dc.numberPresentation = DriverCall.presentationFromCLIP(np);
dc.name = p.readString();
dc.namePresentation = p.readInt();
int uusInfoPresent = p.readInt();
if (uusInfoPresent == 1) {
dc.uusInfo = new UUSInfo();
dc.uusInfo.setType(p.readInt());
dc.uusInfo.setDcs(p.readInt());
byte[] userData = p.createByteArray();
dc.uusInfo.setUserData(userData);
riljLogv(String.format("Incoming UUS : type=%d, dcs=%d, length=%d",
dc.uusInfo.getType(), dc.uusInfo.getDcs(),
dc.uusInfo.getUserData().length));
riljLogv("Incoming UUS : data (string)="
+ new String(dc.uusInfo.getUserData()));
riljLogv("Incoming UUS : data (hex): "
+ IccUtils.bytesToHexString(dc.uusInfo.getUserData()));
} else {
riljLogv("Incoming UUS : NOT present!");
}
// Make sure there's a leading + on addresses with a TOA of 145
dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA);
response.add(dc);
if (dc.isVoicePrivacy) {
mVoicePrivacyOnRegistrants.notifyRegistrants();
riljLog("InCall VoicePrivacy is enabled");
} else {
mVoicePrivacyOffRegistrants.notifyRegistrants();
riljLog("InCall VoicePrivacy is disabled");
}
}
Collections.sort(response);
if ((num == 0) && mTestingEmergencyCall.getAndSet(false)) {
if (mEmergencyCallbackModeRegistrant != null) {
riljLog("responseCallList: call ended, testing emergency call," +
" notify ECM Registrants");
mEmergencyCallbackModeRegistrant.notifyRegistrant();
}
}
return response;
}

GsmConnection的集合connections集合对象是一个数组,数组编号是从0开始的,所以我们会看到会有一个dc.index == i+1;的操作,对应关系就是这里建立的。之后会把底层查的DriverCall对象和GsmCallTracker中保存的GsmConnection对象进行比较。如DriverCall对象为空,我们本地保持的GsmConnection对象存在,很显然,是这路电话挂断了,反之如过DriverCall对象有,GsmConnection对象不存在,则是一个来电。最后使用forMessage函数将返回的结果封装到Message中的 obj中,并发送的消息的目标Handler处理,前面发送的是RIL_REQUEST_GET_CURRENT_CALLS请求,该请求中包含的一个EVENT_POLL_CALLS_RESULT消息。由于EVENT_POLL_CALLS_RESULT消息是从CallTracker中发出来的,而CallTracker是个抽象类,其handleMessage函数是由其子类GsmCallTracker实现的,因此EVENT_POLL_CALLS_RESULT是由GsmCallTracker来处理

frameworks\base\telephony\java\com\android\internal\telephony\gsm\GsmCallTracker.java

[java] view plain copy print ?
  1. public void handleMessage (Message msg) {  
  2.     AsyncResult ar;  
  3.     switch (msg.what) {  
  4.         case EVENT_POLL_CALLS_RESULT:  
  5.             ar = (AsyncResult)msg.obj;  
  6.             if (msg == lastRelevantPoll) {  
  7.                 needsPoll = false;  
  8.                 lastRelevantPoll = null;  
  9.                 handlePollCalls((AsyncResult)msg.obj);  
  10.                 mMoveToBack = false;  
  11.             }  
  12.         break;  
  13.     }  
  14. }  
public void handleMessage (Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_POLL_CALLS_RESULT:
ar = (AsyncResult)msg.obj;
if (msg == lastRelevantPoll) {
needsPoll = false;
lastRelevantPoll = null;
handlePollCalls((AsyncResult)msg.obj);
mMoveToBack = false;
}
break;
}
}

msg.obj中保存了查询到的所有DriverCall,函数直接调用handlePollCalls进行处理

[java] view plain copy print ?
  1. protected synchronized void handlePollCalls(AsyncResult ar) {  
  2.     List polledCalls;  
  3.     if (ar.exception == null) {  
  4.         polledCalls = (List)ar.result;  
  5.     } else if (isCommandExceptionRadioNotAvailable(ar.exception)) {  
  6.         // just a dummy empty ArrayList to cause the loop   
  7.         // to hang up all the calls   
  8.         polledCalls = new ArrayList();  
  9.     } else {  
  10.         // Radio probably wasn't ready--try again in a bit   
  11.         // But don't keep polling if the channel is closed   
  12.         pollCallsAfterDelay();  
  13.         return;  
  14.     }  
  15.     Connection newRinging = null//or waiting   
  16.     boolean hasNonHangupStateChanged = false;   // Any change besides   
  17.     boolean needsPollDelay = false;  
  18.     boolean unknownConnectionAppeared = false;  
  19.     for (int i = 0, curDC = 0, dcSize = polledCalls.size(); i < connections.length; i++) {  
  20.         GsmConnection conn = connections[i];  
  21.         DriverCall dc = null;  
  22.         // polledCall list is sparse   
  23.         if (curDC < dcSize) {  
  24.             dc = (DriverCall) polledCalls.get(curDC);  
  25.             if (dc.index == i+1) {  
  26.                 curDC++;  
  27.             } else {  
  28.                 dc = null;  
  29.             }  
  30.         }  
  31.         if (conn == null && dc != null) {  
  32.             // Connection appeared in CLCC response that we don't know about   
  33.             if (pendingMO != null && pendingMO.compareTo(dc)) {  
  34.                 if (DBG_POLL) log("poll: pendingMO=" + pendingMO);  
  35.                 // It's our pending mobile originating call   
  36.                 connections[i] = pendingMO;  
  37.                 pendingMO.index = i;  
  38.                 pendingMO.update(dc);  
  39.                 pendingMO = null;  
  40.                 // Someone has already asked to hangup this call   
  41.                 if (hangupPendingMO) {  
  42.                     hangupPendingMO = false;  
  43.                     try {  
  44.                         hangup(connections[i]);  
  45.                     } catch (CallStateException ex) {  
  46.                         Log.e(LOG_TAG, "unexpected error on hangup");  
  47.                     }  
  48.                     return;  
  49.                 }  
  50.             } else {  
  51.                 connections[i] = new GsmConnection(phone.getContext(), dc, this, i);  
  52.                 // it's a ringing call   
  53.                 if (connections[i].getCall() == ringingCall) {  
  54.                     newRinging = connections[i];  
  55.                 } else {  
  56.                     if (dc.state != DriverCall.State.ALERTING  
  57.                             && dc.state != DriverCall.State.DIALING) {  
  58.                         connections[i].connectTime = System.currentTimeMillis();  
  59.                     }  
  60.                     unknownConnectionAppeared = true;  
  61.                 }  
  62.             }  
  63.             hasNonHangupStateChanged = true;  
  64.         } else if (conn != null && dc == null) {  
  65.             // Connection missing in CLCC response that we were   
  66.             // tracking.   
  67.             droppedDuringPoll.add(conn);  
  68.             // Dropped connections are removed from the CallTracker   
  69.             // list but kept in the GsmCall list   
  70.             connections[i] = null;  
  71.         } else if (conn != null && dc != null && !conn.compareTo(dc)) {  
  72.             // Connection in CLCC response does not match what   
  73.             // we were tracking. Assume dropped call and new call   
  74.             droppedDuringPoll.add(conn);  
  75.             connections[i] = new GsmConnection (phone.getContext(), dc, this, i);  
  76.             if (connections[i].getCall() == ringingCall) {  
  77.                 newRinging = connections[i];  
  78.             } // else something strange happened   
  79.             hasNonHangupStateChanged = true;  
  80.         } else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */  
  81.             boolean changed;  
  82.             changed = conn.update(dc);  
  83.             hasNonHangupStateChanged = hasNonHangupStateChanged || changed;  
  84.         }  
  85.         if (REPEAT_POLLING) {  
  86.             if (dc != null) {  
  87.                 // FIXME with RIL, we should not need this anymore   
  88.                 if ((dc.state == DriverCall.State.DIALING  
  89.                         /*&& cm.getOption(cm.OPTION_POLL_DIALING)*/)  
  90.                     || (dc.state == DriverCall.State.ALERTING  
  91.                         /*&& cm.getOption(cm.OPTION_POLL_ALERTING)*/)  
  92.                     || (dc.state == DriverCall.State.INCOMING  
  93.                         /*&& cm.getOption(cm.OPTION_POLL_INCOMING)*/)  
  94.                     || (dc.state == DriverCall.State.WAITING  
  95.                         /*&& cm.getOption(cm.OPTION_POLL_WAITING)*/)  
  96.                 ) {  
  97.                     // Sometimes there's no unsolicited notification   
  98.                     // for state transitions   
  99.                     needsPollDelay = true;  
  100.                 }  
  101.             }  
  102.         }  
  103.     }  
  104.     // This is the first poll after an ATD.   
  105.     // We expect the pending call to appear in the list   
  106.     // If it does not, we land here   
  107.     if (pendingMO != null) {  
  108.         droppedDuringPoll.add(pendingMO);  
  109.         pendingMO = null;  
  110.         hangupPendingMO = false;  
  111.     }  
  112.     if (newRinging != null) {  
  113.         phone.notifyNewRingingConnection(newRinging);  
  114.     }  
  115.     // clear the "local hangup" and "missed/rejected call"   
  116.     // cases from the "dropped during poll" list   
  117.     // These cases need no "last call fail" reason   
  118.     for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) {  
  119.         GsmConnection conn = droppedDuringPoll.get(i);  
  120.         if (conn.isIncoming() && conn.getConnectTime() == 0) {  
  121.             // Missed or rejected call   
  122.             Connection.DisconnectCause cause;  
  123.             if (conn.cause == Connection.DisconnectCause.LOCAL) {  
  124.                 cause = Connection.DisconnectCause.INCOMING_REJECTED;  
  125.             } else {  
  126.                 cause = Connection.DisconnectCause.INCOMING_MISSED;  
  127.             }  
  128.             droppedDuringPoll.remove(i);  
  129.             conn.onDisconnect(cause);  
  130.         } else if (conn.cause == Connection.DisconnectCause.LOCAL) {  
  131.             // Local hangup   
  132.             droppedDuringPoll.remove(i);  
  133.             conn.onDisconnect(Connection.DisconnectCause.LOCAL);  
  134.         } else if (conn.cause ==  
  135.             Connection.DisconnectCause.INVALID_NUMBER) {  
  136.             droppedDuringPoll.remove(i);  
  137.             conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER);  
  138.         }  
  139.     }  
  140.     // Any non-local disconnects: determine cause   
  141.     if (droppedDuringPoll.size() > 0) {  
  142.         cm.getLastCallFailCause(obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE));  
  143.     }  
  144.     if (needsPollDelay) {  
  145.         pollCallsAfterDelay();  
  146.     }  
  147.     // Cases when we can no longer keep disconnected Connection's   
  148.     // with their previous calls   
  149.     // 1) the phone has started to ring   
  150.     // 2) A Call/Connection object has changed state...   
  151.     //    we may have switched or held or answered (but not hung up)   
  152.     if (newRinging != null || hasNonHangupStateChanged) {  
  153.         internalClearDisconnected();  
  154.     }  
  155.     updatePhoneState();  
  156.     if (unknownConnectionAppeared) {  
  157.         phone.notifyUnknownConnection();  
  158.     }  
  159.     if (hasNonHangupStateChanged || newRinging != null) {  
  160.         phone.notifyPreciseCallStateChanged();  
  161.     }  
  162. }  
protected synchronized void handlePollCalls(AsyncResult ar) {
List polledCalls;
if (ar.exception == null) {
polledCalls = (List)ar.result;
} else if (isCommandExceptionRadioNotAvailable(ar.exception)) {
// just a dummy empty ArrayList to cause the loop
// to hang up all the calls
polledCalls = new ArrayList();
} else {
// Radio probably wasn't ready--try again in a bit
// But don't keep polling if the channel is closed
pollCallsAfterDelay();
return;
}
Connection newRinging = null; //or waiting
boolean hasNonHangupStateChanged = false;   // Any change besides
boolean needsPollDelay = false;
boolean unknownConnectionAppeared = false;
for (int i = 0, curDC = 0, dcSize = polledCalls.size(); i < connections.length; i++) {
GsmConnection conn = connections[i];
DriverCall dc = null;
// polledCall list is sparse
if (curDC < dcSize) {
dc = (DriverCall) polledCalls.get(curDC);
if (dc.index == i+1) {
curDC++;
} else {
dc = null;
}
}
if (conn == null && dc != null) {
// Connection appeared in CLCC response that we don't know about
if (pendingMO != null && pendingMO.compareTo(dc)) {
if (DBG_POLL) log("poll: pendingMO=" + pendingMO);
// It's our pending mobile originating call
connections[i] = pendingMO;
pendingMO.index = i;
pendingMO.update(dc);
pendingMO = null;
// Someone has already asked to hangup this call
if (hangupPendingMO) {
hangupPendingMO = false;
try {
hangup(connections[i]);
} catch (CallStateException ex) {
Log.e(LOG_TAG, "unexpected error on hangup");
}
return;
}
} else {
connections[i] = new GsmConnection(phone.getContext(), dc, this, i);
// it's a ringing call
if (connections[i].getCall() == ringingCall) {
newRinging = connections[i];
} else {
if (dc.state != DriverCall.State.ALERTING
&& dc.state != DriverCall.State.DIALING) {
connections[i].connectTime = System.currentTimeMillis();
}
unknownConnectionAppeared = true;
}
}
hasNonHangupStateChanged = true;
} else if (conn != null && dc == null) {
// Connection missing in CLCC response that we were
// tracking.
droppedDuringPoll.add(conn);
// Dropped connections are removed from the CallTracker
// list but kept in the GsmCall list
connections[i] = null;
} else if (conn != null && dc != null && !conn.compareTo(dc)) {
// Connection in CLCC response does not match what
// we were tracking. Assume dropped call and new call
droppedDuringPoll.add(conn);
connections[i] = new GsmConnection (phone.getContext(), dc, this, i);
if (connections[i].getCall() == ringingCall) {
newRinging = connections[i];
} // else something strange happened
hasNonHangupStateChanged = true;
} else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */
boolean changed;
changed = conn.update(dc);
hasNonHangupStateChanged = hasNonHangupStateChanged || changed;
}
if (REPEAT_POLLING) {
if (dc != null) {
// FIXME with RIL, we should not need this anymore
if ((dc.state == DriverCall.State.DIALING
/*&& cm.getOption(cm.OPTION_POLL_DIALING)*/)
|| (dc.state == DriverCall.State.ALERTING
/*&& cm.getOption(cm.OPTION_POLL_ALERTING)*/)
|| (dc.state == DriverCall.State.INCOMING
/*&& cm.getOption(cm.OPTION_POLL_INCOMING)*/)
|| (dc.state == DriverCall.State.WAITING
/*&& cm.getOption(cm.OPTION_POLL_WAITING)*/)
) {
// Sometimes there's no unsolicited notification
// for state transitions
needsPollDelay = true;
}
}
}
}
// This is the first poll after an ATD.
// We expect the pending call to appear in the list
// If it does not, we land here
if (pendingMO != null) {
droppedDuringPoll.add(pendingMO);
pendingMO = null;
hangupPendingMO = false;
}
if (newRinging != null) {
phone.notifyNewRingingConnection(newRinging);
}
// clear the "local hangup" and "missed/rejected call"
// cases from the "dropped during poll" list
// These cases need no "last call fail" reason
for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) {
GsmConnection conn = droppedDuringPoll.get(i);
if (conn.isIncoming() && conn.getConnectTime() == 0) {
// Missed or rejected call
Connection.DisconnectCause cause;
if (conn.cause == Connection.DisconnectCause.LOCAL) {
cause = Connection.DisconnectCause.INCOMING_REJECTED;
} else {
cause = Connection.DisconnectCause.INCOMING_MISSED;
}
droppedDuringPoll.remove(i);
conn.onDisconnect(cause);
} else if (conn.cause == Connection.DisconnectCause.LOCAL) {
// Local hangup
droppedDuringPoll.remove(i);
conn.onDisconnect(Connection.DisconnectCause.LOCAL);
} else if (conn.cause ==
Connection.DisconnectCause.INVALID_NUMBER) {
droppedDuringPoll.remove(i);
conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER);
}
}
// Any non-local disconnects: determine cause
if (droppedDuringPoll.size() > 0) {
cm.getLastCallFailCause(obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE));
}
if (needsPollDelay) {
pollCallsAfterDelay();
}
// Cases when we can no longer keep disconnected Connection's
// with their previous calls
// 1) the phone has started to ring
// 2) A Call/Connection object has changed state...
//    we may have switched or held or answered (but not hung up)
if (newRinging != null || hasNonHangupStateChanged) {
internalClearDisconnected();
}
updatePhoneState();
if (unknownConnectionAppeared) {
phone.notifyUnknownConnection();
}
if (hasNonHangupStateChanged || newRinging != null) {
phone.notifyPreciseCallStateChanged();
}
}
对于新的来电使用phone.notifyNewRingingConnection(newRinging)触发CallManager中的mHandler来处理该消息,在前面介绍了在构造PhoneApp的onCreate函数中,首先得到CallManager实例对象,然后调用该对象的registerPhone方法为Phone层注册消息事件,注册的处理消息的Handler为CallManager的变量mHandler。

frameworks\base\telephony\java\com\android\internal\telephony\CallManager.java

[java] view plain copy print ?
  1. public void handleMessage(Message msg) {  
  2.     switch (msg.what) {  
  3.         case EVENT_NEW_RINGING_CONNECTION:  
  4.             if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)");  
  5.             if (getActiveFgCallState().isDialing() || hasMoreThanOneRingingCall()) {  
  6.                 Connection c = (Connection) ((AsyncResult) msg.obj).result;  
  7.                 try {  
  8.                     Log.d(LOG_TAG, "silently drop incoming call: " + c.getCall());  
  9.                     c.getCall().hangup();  
  10.                 } catch (CallStateException e) {  
  11.                     Log.w(LOG_TAG, "new ringing connection", e);  
  12.                 }  
  13.             } else {  
  14.                 mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);  
  15.             }  
  16.             break;  
  17.     }  
  18. }  
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_NEW_RINGING_CONNECTION:
if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)");
if (getActiveFgCallState().isDialing() || hasMoreThanOneRingingCall()) {
Connection c = (Connection) ((AsyncResult) msg.obj).result;
try {
Log.d(LOG_TAG, "silently drop incoming call: " + c.getCall());
c.getCall().hangup();
} catch (CallStateException e) {
Log.w(LOG_TAG, "new ringing connection", e);
}
} else {
mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
}
break;
}
}
mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj)将触发mNewRingingConnectionRegistrants中注册的handler处理PHONE_NEW_RINGING_CONNECTION消息,在前面我们也介绍了,在PhoneApp的onCreate函数中构造CallNotifier对象时,通过registerForNotifications函数注册了CallNotifier来处理该消息。

packages\apps\Phone\src\com\android\phone\CallNotifier.java

[java] view plain copy print ?
  1. public void handleMessage(Message msg) {  
  2.     switch (msg.what) {  
  3.         case PHONE_NEW_RINGING_CONNECTION:  
  4.             log("RINGING... (new)");  
  5.             onNewRingingConnection((AsyncResult) msg.obj);  
  6.             mSilentRingerRequested = false;  
  7.     }  
  8. }  
public void handleMessage(Message msg) {
switch (msg.what) {
case PHONE_NEW_RINGING_CONNECTION:
log("RINGING... (new)");
onNewRingingConnection((AsyncResult) msg.obj);
mSilentRingerRequested = false;
}
}
该函数直接调用onNewRingingConnection来处理来电

[java] view plain copy print ?
  1. private void onNewRingingConnection(AsyncResult r) {  
  2.     Connection c = (Connection) r.result;  
  3.     log("onNewRingingConnection(): state = " + mCM.getState() + ", conn = { " + c + " }");  
  4.     Call ringing = c.getCall();  
  5.     Phone phone = ringing.getPhone();  
  6.     // Check for a few cases where we totally ignore incoming calls.   
  7.     if (ignoreAllIncomingCalls(phone)) {  
  8.         PhoneUtils.hangupRingingCall(ringing);  
  9.         return;  
  10.     }  
  11.     if (!c.isRinging()) {  
  12.         Log.i(LOG_TAG, "CallNotifier.onNewRingingConnection(): connection not ringing!");  
  13.         return;  
  14.     }  
  15.     // Stop any signalInfo tone being played on receiving a Call   
  16.     stopSignalInfoTone();  
  17.     Call.State state = c.getState();  
  18.     if (VDBG) log("- connection is ringing!  state = " + state);  
  19.     if (VDBG) log("Holding wake lock on new incoming connection.");  
  20.     mApplication.requestWakeState(PhoneGlobals.WakeState.PARTIAL);  
  21.       
  22.     if (PhoneUtils.isRealIncomingCall(state)) {  
  23.         startIncomingCallQuery(c);  
  24.     } else {  
  25.         if (VDBG) log("- starting call waiting tone...");  
  26.         if (mCallWaitingTonePlayer == null) {  
  27.             mCallWaitingTonePlayer = new InCallTonePlayer(InCallTonePlayer.TONE_CALL_WAITING);  
  28.             mCallWaitingTonePlayer.start();  
  29.         }  
  30.         if (DBG) log("- showing incoming call (this is a WAITING call)...");  
  31.         showIncomingCall();  
  32.     }  
  33.     if (VDBG) log("- onNewRingingConnection() done.");  
  34. }  
private void onNewRingingConnection(AsyncResult r) {
Connection c = (Connection) r.result;
log("onNewRingingConnection(): state = " + mCM.getState() + ", conn = { " + c + " }");
Call ringing = c.getCall();
Phone phone = ringing.getPhone();
// Check for a few cases where we totally ignore incoming calls.
if (ignoreAllIncomingCalls(phone)) {
PhoneUtils.hangupRingingCall(ringing);
return;
}
if (!c.isRinging()) {
Log.i(LOG_TAG, "CallNotifier.onNewRingingConnection(): connection not ringing!");
return;
}
// Stop any signalInfo tone being played on receiving a Call
stopSignalInfoTone();
Call.State state = c.getState();
if (VDBG) log("- connection is ringing!  state = " + state);
if (VDBG) log("Holding wake lock on new incoming connection.");
mApplication.requestWakeState(PhoneGlobals.WakeState.PARTIAL);
if (PhoneUtils.isRealIncomingCall(state)) {
startIncomingCallQuery(c);
} else {
if (VDBG) log("- starting call waiting tone...");
if (mCallWaitingTonePlayer == null) {
mCallWaitingTonePlayer = new InCallTonePlayer(InCallTonePlayer.TONE_CALL_WAITING);
mCallWaitingTonePlayer.start();
}
if (DBG) log("- showing incoming call (this is a WAITING call)...");
showIncomingCall();
}
if (VDBG) log("- onNewRingingConnection() done.");
}
通过函数showIncomingCall来启动InCallScreen界面,并开启来电铃声

[java] view plain copy print ?
  1. private void showIncomingCall() {  
  2.     log("showIncomingCall()...  phone state = " + mCM.getState());  
  3.     try {  
  4.         ActivityManagerNative.getDefault().closeSystemDialogs("call");  
  5.     } catch (RemoteException e) {  
  6.     }  
  7.     mApplication.requestWakeState(PhoneGlobals.WakeState.FULL);  
  8.     if (DBG) log("- updating notification from showIncomingCall()...");  
  9.     mApplication.notificationMgr.updateNotificationAndLaunchIncomingCallUi();  
  10. }  
private void showIncomingCall() {
log("showIncomingCall()...  phone state = " + mCM.getState());
try {
ActivityManagerNative.getDefault().closeSystemDialogs("call");
} catch (RemoteException e) {
}
mApplication.requestWakeState(PhoneGlobals.WakeState.FULL);
if (DBG) log("- updating notification from showIncomingCall()...");
mApplication.notificationMgr.updateNotificationAndLaunchIncomingCallUi();
}
最后通过NotificationMgr类来启动来电界面

[java] view plain copy print ?
  1. public void updateNotificationAndLaunchIncomingCallUi() {  
  2.     updateInCallNotification(true);  
  3. }  
public void updateNotificationAndLaunchIncomingCallUi() {
updateInCallNotification(true);
}
在函数updateInCallNotification中通过以下语句来启动来电界面

[java] view plain copy print ?
  1. Intent inCallIntent = mApp.createInCallIntent(currentCall.getPhone().getPhoneId());  
  2. PendingIntent inCallPendingIntent =PendingIntent.getActivity(mContext, 0, inCallIntent, 0);  
  3. builder.setContentIntent(inCallPendingIntent);  
Intent inCallIntent = mApp.createInCallIntent(currentCall.getPhone().getPhoneId());
PendingIntent inCallPendingIntent =PendingIntent.getActivity(mContext, 0, inCallIntent, 0);
builder.setContentIntent(inCallPendingIntent);

这篇关于Android电话来电流程源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/810955

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57