Android 4.4 Kitkat Phone工作流程浅析(八)__Phone状态分析

来源:互联网 发布:京瓷1125mfp 网络配置 编辑:程序博客网 时间:2024/05/21 02:52
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处

本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉。

前置文章:

《Android 4.4 Kitkat Phone工作流程浅析(一)__概要和学习计划》

《Android 4.4 Kitkat Phone工作流程浅析(二)__UI结构分析》

《Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析》

《Android 4.4 Kitkat Phone工作流程浅析(四)__RILJ工作流程简析》

《Android 4.4 Kitkat Phone工作流程浅析(五)__MT(来电)流程分析》

《Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程》

《Android 4.4 Kitkat Phone工作流程浅析(七)__来电(MT)响铃流程》

概述

       通过前面一系列的文章,我们对整个Phone模块有了基本的了解,本文主要目的是分析在整个Telephony架构中Phone的状态以及它们之间的关系。关于Phone状态改变后的通知流程,请大家参看《Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程》。

       在《Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程》的概述中,我们提到Call的状态分为6种:ACTIVEHOLDINGDIALINGALERTINGINCOMINGWAITING。这里的依据是什么呢?在Google AOSP代码中,我们可以看到google使用的是AT+CLCC的方式来获取当前通话信息的,CLCC的状态描述总共有6种,也就是:active(0)、held(1)、dialing(2)、alterting(3)、incoming(4)、waiting(5),括号里为状态对应的数值,关于AT+CLCC的指令描述,请大家参考相关AT文档。这些状态值由Modem端返回,也就是说所有Call状态的源头在Modem端。

       但是,MTK并没有使用CLCC查询方式,而是改用了AT+ECPI的方式,根据ECPI的msg_type来判断当前Modem的状态,归根结底还是上面提到6种状态。详细请参看《Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程》中Telephony Framework接收处理反馈部分,该部分有简单分析MTK自己添加的AT指令ECPI。

       我们还是按照自底向上的方式分析状态改变的流程,从Telephony Framework开始,然后是TeleService,最后是InCallUI,整个流程如下图:



状态来源—— Modem

       通话状态的起始源自Modem状态的改变,而Modem会将这些信息通过串口方式返回给RILC,再由RILC返回给RILJ,我们在《Android 4.4 Kitkat Phone工作流程浅析(四)__RILJ工作流程简析》中有对这个流程简单分析,最后由RILJ来处理这些返回信息。比如当有一通来电时,我们会在radio Log中看到如下信息:
[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 01-01 18:11:47.047   682   705 D use-Rlog/RLOG-AT: AT< +ECPI: 1,130,0,0,0,0,"13800138000",129,""  
ECPI的格式如下:
[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. +ECPI:<call_id>,<msg_type>,<is_ibt>,<is_tch>,<dir>,<call_mode>,[<number>,<type>],[<disc_cause>]  
对应的信息如下图:


其中msg_type就是Modem返回的状态信息,这些状态信息以具体的数值表示,黑体加粗为目前MTK Android 4.4 有使用到的几种类型。

DriverCall. State状态获取

在GsmCallTracker的handleCallProgressInfo()方法中,首先会对收到的msg_type进行归类,并得到DriverCall.State,这里的handleCallProgressInfo()的作用实际上和AOSP中的handlePollCalls()的作用一致,关键代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //... ...省略  
  2. if (msgType == 132 || msgType == 6)  
  3.     dc.state = DriverCall.State.ACTIVE;  
  4. else if (msgType == 131)  
  5.     dc.state = DriverCall.State.HOLDING;  
  6. else if (msgType == 130 && callId != 254)  
  7.     dc.state = DriverCall.State.DIALING;  
  8. else if (msgType == 2)  
  9.     dc.state = DriverCall.State.ALERTING;  
  10. else if (msgType == 0)  
  11. {  
  12.     for (j = 0; j < MAX_CONNECTIONS; j++) {  
  13.         if (mConnections[j] != null) {  
  14.             count ++;  
  15.         }  
  16.     }  
  17.     if (mState == PhoneConstants.State.IDLE ||   
  18.         (count == 0 &&  mForegroundCall.getState() == GsmCall.State.DIALING))  
  19.     {  
  20.         dc.state = DriverCall.State.INCOMING;  
  21.     }  
  22.     else  
  23.         dc.state = DriverCall.State.WAITING;  
  24. }  
  25. //... ...省略  

也就是说DriverCall.State由ECPI的msg_type和callId值共同决定,这里我们主要看msg_type,它们之间的对应关系如下图:

DriverCall实际反映了Modem端真实的通话连接信息。

Call. State (Internal)状态获取

        这里的Call指的是com.android.internal.telephony.Call,源码路径在SourceCode/frameworks/opt/telephony/src/java/com/android/internal/telephony/Call.java。该类是一个抽象类,其子类有GsmCall、CDMACall,这里我们只关心GsmCall。

        在GsmCallTracker的handleCallProgressInfo()方法中,完成DriverCall.State的转换后,便开始执行DriverCall.State和Call.State的转换了,关键代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //... ...省略  
  2. if (conn == null)   
  3. {  
  4.     log("1. new connection appeared!!");  
  5.     if (mPendingMO != null)  
  6.     {  
  7.         //DriverCall.State.DIALING  
  8.         if (msgType == 130)  
  9.         {  
  10.             log("1.1. it is a MO call");  
  11.             mConnections[i] = mPendingMO;  
  12.             mPendingMO.mIndex = i;  
  13.             //GsmConnection根据DriverCall更新GsmCall  
  14.             mPendingMO.update(dc);  
  15.             mPendingMO = null;  
  16.             //... ...省略  
  17.         }  
  18.         //... ...省略  
  19.     }  
  20.     //DriverCall.State.INCOMING/DriverCall.State.WAITING  
  21.     else if (msgType == 0)   
  22.     {  
  23.         log("1.2 it is a MT call");  
  24.         //根据DriverCall新建GsmConnection对象,并根据DriverCall状态获取  
  25.         //对应的GsmCall对象  
  26.         mConnections[i] = new GsmConnection(mPhone.getContext(), dc, this, i);  
  27.         //... ...省略  
  28.     }  
  29.     //... ...省略  
  30. }  
  31. //... ...省略  

从以上代码可以看出,针对MT和MO流程采用了不同的方式获取Call.State。

MO流程获取Call. State (Internal)

MO流程使用GsmConnection的update()方法来获取Call.State(internal),关键代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. update (DriverCall dc) {  
  2.     GsmCall newParent;  
  3.     //... ...省略  
  4.     //根据DriverCall.State获取与之对应的GsmCall对象  
  5.     newParent = parentFromDCState(dc.state);  
  6.     //... ...省略  
  7.     //更新Call.State  
  8.     if (newParent != mParent) {  
  9.         if (mParent != null) {  
  10.             //移除先前连接,并将State设置为Call.State.IDLE  
  11.             mParent.detach(this);  
  12.         }  
  13.     //增加当前连接,并更新State  
  14.         newParent.attach(this, dc);  
  15.         mParent = newParent;  
  16.         changed = true;  
  17.     } else {  
  18.         boolean parentStateChange;  
  19.         //更新State  
  20.         parentStateChange = mParent.update (this, dc);  
  21.         changed = changed || parentStateChange;  
  22.     }  
  23.     //... ...省略  
  24.     return changed;  
  25. }  

我们看到parentFromDCState()方法,这里实际上是根据DriverCall.State来获取对应的GsmCall对象,如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private GsmCall  
  2. parentFromDCState (DriverCall.State state) {  
  3.     switch (state) {  
  4.         case ACTIVE:  
  5.         case DIALING:  
  6.         case ALERTING:  
  7.             return mOwner.mForegroundCall;  
  8.         //break;  
  9.         case HOLDING:  
  10.             return mOwner.mBackgroundCall;  
  11.         //break;  
  12.         case INCOMING:  
  13.         case WAITING:  
  14.             return mOwner.mRingingCall;  
  15.         //break;  
  16.         default:  
  17.             throw new RuntimeException("illegal call state: " + state);  
  18.     }  
  19. }  
通过以上代码可以知道GsmCall的三种状态:foregroundCall、backgroundCall、ringingCall它们所对应的DriverCall.State,如下图:

在根据DriverCall.State获取GsmCall对象之后,便根据GsmCall的detach()、attach()、update()方法来更新Call.State,而更新代码的关键是stateFromDCState(),关键代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mState = stateFromDCState (dc.state);  
  2.   
  3. static State  
  4. stateFromDCState (DriverCall.State dcState) {  
  5.     switch (dcState) {  
  6.         case ACTIVE:        return State.ACTIVE;  
  7.         case HOLDING:       return State.HOLDING;  
  8.         case DIALING:       return State.DIALING;  
  9.         case ALERTING:      return State.ALERTING;  
  10.         case INCOMING:      return State.INCOMING;  
  11.         case WAITING:       return State.WAITING;  
  12.         default:            throw new RuntimeException ("illegal call state:" + dcState);  
  13.     }     
  14. }  

到这里完成了MO流程DriverCall.State和Call.State(internal)的映射。

MT流程获取Call. State (Internal)

MO的Call.State获取是通过pendingMO.update()方法发起的,而MT流程则是通过实例化GsmConnection对象发起的,代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mConnections[i] = new GsmConnection(mPhone.getContext(), dc, this, i);  
  2.   
  3. GsmConnection (Context context, DriverCall dc, GsmCallTracker ct, int index) {  
  4.     //... ...省略  
  5.     //根据DriverCall.State获取GsmCall  
  6.     mParent = parentFromDCState (dc.state);  
  7.     //增加GsmConnection并更新Call.State  
  8.     mParent.attach(this, dc);  
  9. }  

后续和MO的流程一致,不在赘述。

在Call.State(internal)状态获取流程中,看起来似乎有些复杂,我们简单总结如下:

1. 6种DriverCall.State分别对应GsmCall对象fgCall、bgCall以及ringingCall;

2. Call.State(internal)是由GsmConnection发起更新的;系统中有三个GsmCall对象,分别是fgCall、bgCall已经ringingCall,GsmConnection根据DriverCall.State的改变,将自己划分到不同的GsmCall对象中;

(PS:比如来电的时候建立一个GsmConnection,此时它属于ringingCall;在来电接通后它会将自己更为属于fgCall,如果此时你再拨打一通电话,那么该GsmConnection又会将自己更改为属于bgCall。)

通过以上分析我们可以知道DriverCall.State与Call.State的对应关系如下:


TelephonyManager. CALL_STATE状态获取

       TelephonyManager状态用于给三方应用提供Phone状态,这一小节实际上可以分为两部分即:Phone.State和TelephonyManager.CallState,前者是内部使用,后者供外部使用;前者根据Call.State(Internal)获取对应状态,后者根据Phone.State获取对应状态。

       在Android 4.4中并没有所谓的Phone.State,这是Android 4.0之前的称呼,实际指的是PhoneConstants.State。PhoneConstants.State就是Android 4.0以及之前版本中的Phone.State,其使用IDLE、RINGING、OFFHOOK来表示当前Phone的状态,这些状态将提供给TelephonyManager并暴露给三方应用。

       在GsmCallTracker的handleCallProgressInfo()中,经过了DriverCall.State的获取与Call.State(internal)的获取之后,通过updatePhoneState()来更新PhoneConstants.State,关键代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void  
  2. updatePhoneState() {  
  3.     PhoneConstants.State oldState = mState;  
  4.     if (mRingingCall.isRinging()) {  
  5.         mState = PhoneConstants.State.RINGING;  
  6.     } else if (mPendingMO != null ||  
  7.             !(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) {  
  8.         mState = PhoneConstants.State.OFFHOOK;  
  9.     } else {  
  10.         mState = PhoneConstants.State.IDLE;  
  11.     }  
  12.     if (mState == PhoneConstants.State.IDLE && oldState != mState) {  
  13.     //如果是IDLE状态则发起通知,语音通话结束,告知数据连接可用  
  14.         mVoiceCallEndedRegistrants.notifyRegistrants(  
  15.             new AsyncResult(nullnullnull));  
  16.     } else if (oldState == PhoneConstants.State.IDLE && oldState != mState) {  
  17.     //如果是非IDLE状态,语音通话开始,告知数据连接不可用  
  18.         mVoiceCallStartedRegistrants.notifyRegistrants (  
  19.                 new AsyncResult(nullnullnull));  
  20.     }  
  21.     log("updatePhoneState: old: " + oldState +" , new: " + mState);  
  22.     if (mState != oldState) {  
  23.         //通知三方应用  
  24.         mPhone.notifyPhoneStateChanged();  
  25.     }  
  26. }  
通过代码我们可以很清楚的看到,PhoneConstants.State是由Call.State(internal)决定的,分别根据fgCall、bgCall、ringingCall来获取Call.State(internal)的状态。简单的分析下它们之间的对应关系。

PhoneConstants. State. RINGING

根据前面的代码,我们需要查看GsmCall中的isRinging()方法的返回值,如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public boolean isRinging() {  
  2.     return getState().isRinging();  
  3. }  
  4.   
  5. //这里的mState是com.android.internal.telephony.State对象  
  6. public State getState() {  
  7.     return mState;  
  8. }  
  9.   
  10. public boolean isRinging() {  
  11.     return this == INCOMING || this == WAITING;  
  12. }  
根据以上代码可以知道PhoneConstants.State.RINGING相当于Call.State.INCOMING和Call.State.WAITING。

PhoneConstants. State. OFFHOOK

这里就需要查看mPendingMO对象是否为null以及fgCall和bgCall的isIdle()方法的返回值,如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //如果mPendingMO不为null,则表示当前是MO流程。  
  2. //后面的判断表示只要fgCall或者bgCall其中之一不是IDLE状态,则是Phone状态为OFFHOOK  
  3. mPendingMO != null || !(mForegroundCall.isIdle() && mBackgroundCall.isIdle())  
  4.   
  5. //isIdle与isAlive是互斥的  
  6. public boolean isIdle() {  
  7.     return !getState().isAlive();  
  8. }  
  9.   
  10. //如果Call.State是IDLE/DISCONNECTED/DISCONNECTING中的任意一种状态,则返回false  
  11. //反之则为true  
  12. public boolean isAlive() {  
  13.     return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING);  
  14. }  
总的来讲,如果当前为MO流程以及Call.State(internal)不为IDLE、DISCONNECTED、DISCONNETING三者中的任意一种,即表示当前Phone状态为OFFHOOK。

PhoneConstants. State. IDLE

        除了PhoneConstants.State.RINGING和PhoneConstants.State.OFFHOOK之外的状态都属于PhoneConstants.State.IDLE,对应于Call.State.IDLE、Call.State.DISCONNECTING、Call.State.DISCONNECTED任意一种。

        在updatePhoneState()方法的最后,调用了notifyPhoneStateChanged()将Phone状态向TelephonyManager传送,并最终通过mRegistry.notifyCallState()方法将Phone状态传递给所有注册了PhoneStateChangeListener。这里我们主要看到DefaultPhoneNotifier.notifyPhoneState()方法,在这里最终实现了Phone.State向TelePhonyManager.Call_STATE的过度,整个过程关键代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //GsmCallTracker updatePhoneState()方法中调用  
  2. if (mState != oldState) {  
  3.     mPhone.notifyPhoneStateChanged();  
  4. }  
  5.   
  6. //这里的this是GSMPhone对象  
  7. /*package*/ void notifyPhoneStateChanged() {  
  8.     updateCipherIndication();  
  9.     mNotifier.notifyPhoneState(this);  
  10. }  
  11.   
  12. public void notifyPhoneState(Phone sender) {  
  13.     //这里是com.android.internal.telephony.Call, sender是GSMPhone对象  
  14.     Call ringingCall = sender.getRingingCall();  
  15.     String incomingNumber = "";   
  16.     if (ringingCall != null && ringingCall.getEarliestConnection() != null){  
  17.         incomingNumber = ringingCall.getEarliestConnection().getAddress();  
  18.     }     
  19.     try {  
  20.         //将Phone状态通知给所有注册了PhoneStateChange的Listener  
  21.         //根据conertCallState方法将PhoneConstants.State转换为TelephonyManager.CALL_STATE  
  22.         mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);  
  23.     } catch (RemoteException ex) {  
  24.         // system process is dead  
  25.     }     
  26. }  
  27. //这里重点关注三个方法:  
  28. //1. sender.getRingingCall()  
  29. //2. sender.getState()  
  30. //3. convertCallState(sender.getState())  
  31.   
  32. public GsmCall getRingingCall() {  
  33.     //mCT为GsmCalltracker对象,mRingingCall为GsmCall对象  
  34.     return mCT.mRingingCall;  
  35. }  
  36.   
  37. public PhoneConstants.State getState() {  
  38.     //mCT为GsmCallTracker对象  
  39.     //mState为PhoneConstants.State对象初始值为PhoneConstants.State.IDLE  
  40.     //mState就是前面提到的Phone.State,也就是PhoneConstants.State  
  41.     return mCT.mState;  
  42. }  
  43.   
  44. public static int convertCallState(PhoneConstants.State state) {  
  45.     switch (state) {  
  46.         case RINGING:  
  47.             return TelephonyManager.CALL_STATE_RINGING;  
  48.         case OFFHOOK:  
  49.             return TelephonyManager.CALL_STATE_OFFHOOK;  
  50.         default:  
  51.             return TelephonyManager.CALL_STATE_IDLE;  
  52.     }  
  53. }  

      这里可以很清楚的看到它们之间的对应关系,普通APP便可以通过获取TelephonyManager对象的CALL_STATE来判断当前Phone的状态,这里我们还是用表格来直观的看看Phone.State与Call.State(internal)以及TelephonyManager.CALL_STATE之间的对应关系,如下:


Call. State (TeleService)状态获取

        这里的Call指的是在com.android.services.telephony.common.Call,源码位于SourceCode/packages/services/Telephony/common/src/com/android/services/telephony/common/Call.java,这里在Call.State后面加上了TeleService用以和前面framework中的Call加以区别。

        在《Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程》中我们已经分析了,通话状态从底层传递到上层的整个流程。在经过了Telephony Framework的处理之后,便传递到TeleService中,具体流程请参看本文开头的“通话状态更新时序图”。当更新流程来到CallModeler的onPhoneStateChanged()方法中时,我们注意到以下关键代码:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void onPhoneStateChanged(AsyncResult r) {  
  2.     Log.i(TAG, "onPhoneStateChanged: ");  
  3.     //这里为com.android.services.telephony.Call  
  4.     final List<Call> updatedCalls = Lists.newArrayList();  
  5.     //根据Call.State(internal)更新Call.State(TeleService)  
  6.     doUpdate(false, updatedCalls);  
  7.     //... ...省略  
  8.     // M: add skip update logic. When 1A + 1R, skip update calls to InCallUI while query is running.  
  9.     if (!ignoreUpdate()) {  
  10.         if (updatedCalls.size() > 0) {  
  11.             for (int i = 0; i < mListeners.size(); ++i) {  
  12.                 //将状态改变向后继续传递,最终到达InCallUI  
  13.                 mListeners.get(i).onUpdate(updatedCalls);  
  14.             }  
  15.         }  
  16.     }  
  17.     //... ...省略  
  18. }  
在该方法中完成了Call.State(Internal)和Call.State(TeleService)的转换,重点关注doUpdate()方法,关键代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void doUpdate(boolean fullUpdate, List<Call> out) {  
  2. //... ...省略  
  3. //通过分析可以知道connection的getState()方法实际为,获取connection对应的  
  4. //Call(Internal)的状态,也就是Call.State(Internal)  
  5. //当Call.State(Internal)不属于IDLE/DISCONNECTED/INCOMING/WAITING时  
  6. //shouldUpdate返回true,我们可以理解为Phone状态位OFFHOOK时才需要更新  
  7. /*final*/ boolean shouldUpdate =  
  8.         (connection.getState() !=  
  9.                 com.android.internal.telephony.Call.State.DISCONNECTED &&  
  10.         connection.getState() !=  
  11.                 com.android.internal.telephony.Call.State.IDLE &&  
  12.         !connection.getState().isRinging())  
  13.         || fullUpdate;   
  14. //... ...省略  
  15. final boolean isDisconnecting = connection.getState() ==  
  16.                 com.android.internal.telephony.Call.State.DISCONNECTING;  
  17. //如果Phone状态位OFFHOOK,shouldCreate返回true  
  18. final boolean shouldCreate = shouldUpdate && !isDisconnecting;  
  19. //根据connection对象创建与之对应的TeleService Call对象  
  20. final Call call = getCallFromMap(mCallMap, connection, shouldCreate /* create */);   
  21. //... ...省略  
  22. //跳转实现Call.State(Internal)和Call.State(TeleService)的映射  
  23. boolean changed = updateCallFromConnection(call, connection, false);  
  24. //... ...省略  
  25. }  
继续查看updateCallFromConnection()方法,关键代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private boolean updateCallFromConnection(Call call, Connection connection,  
  2.         boolean isForConference) {  
  3.     boolean changed = false;  
  4.     //根据GsmConnection对象,获取Call.State(Internal)并更新Call.State(TeleService)  
  5.     final int newState = translateStateFromTelephony(connection, isForConference);  
  6.     //... ...省略  
  7.     return changed;  
  8. }  
  9.   
  10. private int translateStateFromTelephony(Connection connection, boolean isForConference) {  
  11.     //connection.getState实际上为connection所属的GsmCall的状态也就是Call.State(Internal)  
  12.     com.android.internal.telephony.Call.State connState = connection.getState();  
  13.     //... ...省略  
  14.     //Call.State(Internal)与Call.State(TeleService)对应关系  
  15.     int retval = State.IDLE;  
  16.     switch (connState) {  
  17.         case ACTIVE:  
  18.             retval = State.ACTIVE;  
  19.             break;  
  20.         case INCOMING:  
  21.             retval = State.INCOMING;  
  22.             break;  
  23.         case DIALING:  
  24.         case ALERTING:  
  25.             if (PhoneGlobals.getInstance().notifier.getIsCdmaRedialCall()) {  
  26.                 retval = State.REDIALING;  
  27.             } else {  
  28.                 retval = State.DIALING;  
  29.             }  
  30.             break;  
  31.         case WAITING:  
  32.             retval = State.CALL_WAITING;  
  33.             break;  
  34.         case HOLDING:  
  35.             retval = State.ONHOLD;  
  36.             break;  
  37.         case DISCONNECTING:  
  38.             retval = State.DISCONNECTING;  
  39.             break;  
  40.         case DISCONNECTED:  
  41.             retval = State.DISCONNECTED;  
  42.         default:  
  43.     }  
  44.   
  45.     //获取ConferenceCall的Call.State(TeleService)  
  46.     if (!isForConference) {  
  47.         // 如果是conferenceCall则返回State.CONFERENCED  
  48.         if (isPartOfLiveConferenceCall(connection) && connection.isAlive()) {  
  49.             return State.CONFERENCED;  
  50.         }  
  51.     }  
  52.     return retval;  
  53. }  
在经过以上处理之后,Call.State(Internal)就成功的转化为Call.State(TeleService)了,Call.State(TeleService)总共有11个状态,如下:
[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. INVALID = 0;  
  2. IDLE = 1;           /* The call is idle.  Nothing active */  
  3. ACTIVE = 2;         /* There is an active call */     
  4. INCOMING = 3;       /* A normal incoming phone call */   
  5. CALL_WAITING = 4;   /* Incoming call while another is active */   
  6. DIALING = 5;        /* An outgoing call during dial phase */  
  7. REDIALING = 6;      /* Subsequent dialing attempt after a failure */  
  8. ONHOLD = 7;         /* An active phone call placed on hold */  
  9. DISCONNECTING = 8;  /* A call is being ended. */  
  10. DISCONNECTED = 9;   /* State after a call disconnects */  
  11. CONFERENCED = 10;   /* Call part of a conference call */  
那么Call.State(Internal)与Call.State(TeleService)是如何对应的呢?我们用下面这张表格来说明,如下:

InCallState状态获取

       在Android 4.4中,因为原来的Phone已经被拆解为InCallUI和TeleService了,所以google又新增了一个InCallState用于标识InCallActivity的状态。InCallState的状态总共有4种,分别是NO_CALLS、INCOMING、INCALL、OUTGOING。通过查找我们可以在SourceCode/packages/apps/InCallUI/src/com/android/incallui/InCallPresenter.java中找到InCallState的定义,如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public enum InCallState {  
  2.     // InCall Screen is off and there are no calls  
  3.     // InCallUI界面退出并且没有通话  
  4.     NO_CALLS,  
  5.   
  6.     // Incoming-call screen is up  
  7.     // 显示来电界面  
  8.     INCOMING,  
  9.   
  10.     // In-call experience is showing  
  11.     // 处于通话中  
  12.     INCALL,  
  13.   
  14.     // User is dialing out  
  15.     // 主动呼叫即MT  
  16.     OUTGOING;  
  17.   
  18.     public boolean isIncoming() {  
  19.         return (this == INCOMING);  
  20.     }     
  21.   
  22.     public boolean isConnectingOrConnected() {  
  23.         return (this == INCOMING ||  
  24.                 this == OUTGOING ||  
  25.                 this == INCALL);  
  26.     }     
  27. }  
       该用于表示InCallActivity当前所处的状态,那么这些状态与Call.State(Internal)以及Call.State(TeleService)之间的对应关系又是什么呢?这里又需要我们回到本文开头的那张图,在来电状态变更之后,经过了Telephony Framework和TeleService的处理之后,会将相关信息传递到InCallUI中。此时,CallList便会处理这些信息并更新InCallState的状态。

        无论当前通话是来电或者挂断或者是呼叫保持,这些都能够在CallList中找到与之对应的处理方法,如:onIncoming、onDisconnect、onUpdate。通过这些方法可以完成对状态信息的处理以及更新,它们的共通特点是都会调用updateCallInMap()方法。在该方法中完成对Call(TeleService)对象的创建以及和GsmConnection对象的关联,关键代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private boolean updateCallInMap(Call call) {  
  2.     //... ...省略  
  3.     if (call.getState() == Call.State.DISCONNECTED) {  
  4.         //... ...省略  
  5.         mCallMap.put(id, call);  
  6.     } else if (!isCallDead(call)) {  
  7.         mCallMap.put(id, call);  
  8.         //... ...省略  
  9.     return updated;  
  10. }  
这里为什么会提到CallList呢?因为根据时序图我们可以知道在CallList处理之后,便会将消息通知到InCallPresenter.onCallListChange()方法中,正是在这里将我们更新了InCallState的状态,首先看到InCallPresenter.onCallListChange()关键代码:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public void onCallListChange(CallList callList) {  
  3.     if (callList == null) {  
  4.         return;  
  5.     }  
  6.     //将Call.State(TeleService)转换成InCallState  
  7.     InCallState newState = getPotentialStateFromCallList(callList);  
  8.     newState = startOrFinishUi(newState);  
  9.     //... ...省略  
  10. }  
继续查看getPotentialStateFromCallList()方法,如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static InCallState getPotentialStateFromCallList(CallList callList) {  
  2.     //InCallState默认状态位NO_CALLS  
  3.     InCallState newState = InCallState.NO_CALLS;  
  4.     //如果calllist为null返回默认状态NO_CALLS  
  5.     if (callList == null) {  
  6.         return newState;  
  7.     }  
  8.     //INCOMING/OUTGOING/INCALL的对应  
  9.     if (callList.getIncomingCall() != null) {  
  10.         newState = InCallState.INCOMING;  
  11.     } else if (callList.getOutgoingCall() != null) {  
  12.         newState = InCallState.OUTGOING;  
  13.     } else if (callList.getActiveCall() != null ||  
  14.             callList.getBackgroundCall() != null ||  
  15.             callList.getDisconnectedCall() != null ||  
  16.             callList.getDisconnectingCall() != null) {  
  17.         newState = InCallState.INCALL;  
  18.     }  
  19.     return newState;  
  20. }  
这里我们主要看下INCOMING、OUTGOING以及INCALL这几个状态是如何与Call.State(TeleService)对应的。

InCallState. INCOMING

根据前面的代码,首先查看CallList中的getInComingCall()方法,可以看到:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public Call getIncomingCall() {  
  2.     Call call = getFirstCallWithState(Call.State.INCOMING);  
  3.     if (call == null) {  
  4.         call = getFirstCallWithState(Call.State.CALL_WAITING);  
  5.     }     
  6.     //... ...省略  
  7.     return call;  
  8. }  
  9.   
  10. public Call getFirstCallWithState(int state) {  
  11.     return getCallWithState(state, 0);  
  12. }  
  13.   
  14. //在HashMap<Integer, Call> mCallMap中查找valuses  
  15. //是否有与对应state匹配的Call(TeleService)  
  16. public Call getCallWithState(int state, int positionToFind) {  
  17.     Call retval = null;  
  18.     int position = 0;  
  19.     for (Call call : mCallMap.values()) {  
  20.         if (call.getState() == state) {  
  21.             if (position >= positionToFind) {  
  22.                 retval = call;  
  23.                 break;  
  24.             } else {  
  25.                 position++;  
  26.             }  
  27.         }  
  28.     }  
  29.     return retval;  
  30. }  
        代码中所使用的是com.android.services.telephony.common.Call,通过分析可以知道,如果在CallList的mCallMap.valuses中有找到处于Call.State.INCOMING或者Call.State.CALL_WAITING的Call对象,即表示InCallState状态为INCOMING。

InCallState. OUTGOING

同样我们需要查看CallList中的getOutgoingCall()方法,关键代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public Call getOutgoingCall() {  
  2.     Call call = getFirstCallWithState(Call.State.DIALING);  
  3.     if (call == null) {  
  4.         call = getFirstCallWithState(Call.State.REDIALING);  
  5.     }  
  6.     return call;  
  7. }  
因为后面处理过程和前面InCallState.INCOMING类似,这里就不再重复。通过分析可以知道InCallState.OUTGOING与TeleService Common中的Call.State.DIALING和Call.State.REDIALING对应。

InCallState. INCALL

查看getActiveCall()、getBackgroundCall()、getDisconnectedCall()、getDisconnectingCall()方法,关键代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //ACTIVE  
  2. public Call getActiveCall() {  
  3.     return getFirstCallWithState(Call.State.ACTIVE);  
  4. }  
  5. //ONHOLD  
  6. public Call getBackgroundCall() {  
  7.     return getFirstCallWithState(Call.State.ONHOLD);  
  8. }  
  9. //DISCONNECTED  
  10. public Call getDisconnectedCall() {  
  11.     return getFirstCallWithState(Call.State.DISCONNECTED);  
  12. }  
  13. //DISCONNECTING  
  14. public Call getDisconnectingCall() {  
  15.     return getFirstCallWithState(Call.State.DISCONNECTING);  
  16. }  
同样我们可以得出InCallState.INCALL对应于TeleService Common中的:Call.State.ACTIVE、Call.State.ONHOLD、Call.State.DISCONNECTED、Call.State.DISCONNECTING。

InCallState. NO_CALLS

如果不满足INCOMING、OUTGOING、INCALL状态的,都属于NO_CALLS,但实际上NO_CALLS与Call.State.IDLE对应。

        通过前面的分析,我们大致知道了InCallState的作用以及来源,还是用一张图来看看InCallState与Call.State(TeleService)的对应关系,如下:


        这里大家可能会觉得奇怪,为什么Call.State.INVALID和Call.State.CONFERENCED没有与InCallState.NO_CALLS对应呢?INVALID是Call.State初始时赋的值,而实际状态不会为INVALID,而是IDLE。对于CONFERENCED来说,因为Conference Call会有自己单独的处理,这一点在CallModeler里面可以看到,因此也不属于NO_CALLS。

小结

        通过以上分析,我们知道了Telephony中的各种状态,以及它们之间的对应关系,这里简单的总结一下本文所述的内容:

1. Telephony中关于Call、Phone的状态有如下几6种:

(1). DriverCall.State;

        将Modem返回的通话状态转换成最基本的Call状态,DriverCall.State包含ACTIVE、HOLDING、DIALING、ALERTING、INCOMING、WAITING 6种

(2). Call.State(internal);

        在整个Telephony结构中,有且只有三种Call(internal)即:foregroundCall、backgroundCall、ringingCall,这三种类型描述了系统中所有存在的Call(internal)类型,而这三种Call的状态用Call.State(internal)来描述,包含ACTIVE、HOLDING、DIALING、ALERTING、INCOMING、WAITING、IDEL、DISCONNECTING、DISCONNECTED,总共9种类型

        在实际使用中,我们并不会直接使用Call.State(internal),取而代之的是GsmConnection对象的getState方法。一个GsmCall对象可以拥有多个GsmConnection,比如在使用会议电话时,一路通话中拥有多个连接GsmConnection对象会根据DriverCall.State的状态,将自己分配到不同的Call( fgCall、bgCall、ringingCall )对象中比如当有一路来电时,此时会建立GsmConnection对象,并归属于ringingCall对象;而当来电被接听后,该GsmConnection对象会将自己分配到foregroundCall对象中

(3). PhoneConstants.State;

        在Android 4.0以及之前叫做Phone.State,用于描述手机在通话过程中的状态,其状态更新来源于Call.State(internal)。根据Call.State(internal)的状态划分为三类:IDLE、RINGING、OFFHOOK。这些状态供系统以及系统级APP使用。

(4). TelephonyManager.CALL_STATE_XX;

        该状态源自PhoneConstants.State,并与其一一对应,即包含类型TelephonyManager.CALL_STATE_IDLE、TelephonyManager.CALL_STATE_RINGING、TelephonyManager.CALL_STATE_OFFHOOK。这些将会通过“广播”以及“PhoneStateChanged回调”通知给三方应用,该状态的主要目的也是暴露给三方使用。

(5). Call.State(TeleService);

        在Android 4.4中,Phone模块被划分为InCallUI和TeleService两部分,而这里的Call.State(TeleService)正是通话状态在TeleService中的表现,同时该状态也将为后面的InCallState提供参考基准。Call.State(TeleService)包含了基本的11种类型:ACTIVE、ONHOLD、DIALING、REDIALING、INCOMING、CALL_WAITING、DISCONNECTED、DISCONNECTING、IDLE、CONFERENCE、INVALID

        我们知道com.android.internal.telephony.Call也就是前面提及的Call(internal),GsmCall和CDMACall都是其子类,主要作用是对通话这种属性的一种抽象。而Call(TeleService)实际上是com.android.services.telephony.common.Call,在Telephony Framework中完成了GsmCall对象的处理和操作之后,会将相关的信息在TeleService中转换为Call(TeleService)对象,并存储在HashMap中。com.android.services.telephony.common.Call实现了Parcelable接口,其作用是描述一路通话及其状态,在这里能够获得许多关于该路通话的详细信息。

(6). InCallPresenter.InCallState;

        InCallState是用于决定InCallActivity所处状态,其包含类型为4种:NO_CALLS、INCALL、OUTGOING、INCOMING。该类型是首次出现在Android Telephony中,InCallUI的显示则依赖于此状态。

        特别注意:InCallState.INCALL等价于Call.State(TeleService)的ACTIVE、ONHOLD、DISCONNECTING、DISCONNECTED;而PhoneConstants.State.OFFHOOK对应于Call.State(TeleService)的ACTIVE、ONHOLD、DIALING、REDIALING

2. Telephony中的各种状态并不是独立存在的,它们之间是一种由底向上的依赖关系,即底层Modem端通话状态发生了改变,那么顶层的InCallSate状态也会随之而变化,不同的状态具有不同的作用。

   最后,用两张图来反应本文的分析结论,分别是Telephony架构中各种State的映射关系,如图1:


图 1

   下图2为Call.State(internal)各个状态之间的切换流程以及与PhoneConstants.State之间的对应关系,如下:

0 0