Android 4.4 Kitkat Phone工作流程浅析(八)__Phone状态分析
前置文章:
《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种:ACTIVE、HOLDING、DIALING、ALERTING、INCOMING、WAITING。
这里的根据是什么呢?在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
01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: AT< +ECPI: 1,130,0,0,0,0,"13800138000",129,""ECPI的格式例如以下:
+ECPI:<call_id>,<msg_type>,<is_ibt>,<is_tch>,<dir>,<call_mode>,[<number>,<type>],[<disc_cause>]相应的信息例如以下图:
DriverCall. State状态获取
//... ...省略 if (msgType == 132 || msgType == 6) dc.state = DriverCall.State.ACTIVE; else if (msgType == 131) dc.state = DriverCall.State.HOLDING; else if (msgType == 130 && callId != 254) dc.state = DriverCall.State.DIALING; else if (msgType == 2) dc.state = DriverCall.State.ALERTING; else if (msgType == 0) { for (j = 0; j < MAX_CONNECTIONS; j++) { if (mConnections[j] != null) { count ++; } } if (mState == PhoneConstants.State.IDLE || (count == 0 && mForegroundCall.getState() == GsmCall.State.DIALING)) { dc.state = DriverCall.State.INCOMING; } else dc.state = DriverCall.State.WAITING; } //... ...省略
也就是说DriverCall.State由ECPI的msg_type和callId值共同决定。这里我们主要看msg_type,它们之间的相应关系例如以下图:
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的转换了,关键代码例如以下:
//... ...省略 if (conn == null) { log("1. new connection appeared!!"); if (mPendingMO != null) { //DriverCall.State.DIALING if (msgType == 130) { log("1.1. it is a MO call"); mConnections[i] = mPendingMO; mPendingMO.mIndex = i; //GsmConnection依据DriverCall更新GsmCall mPendingMO.update(dc); mPendingMO = null; //... ...省略 } //... ...省略 } //DriverCall.State.INCOMING/DriverCall.State.WAITING else if (msgType == 0) { log("1.2 it is a MT call"); //依据DriverCall新建GsmConnection对象,并依据DriverCall状态获取 //相应的GsmCall对象 mConnections[i] = new GsmConnection(mPhone.getContext(), dc, this, i); //... ...省略 } //... ...省略 } //... ...省略
从以上代码能够看出。针对MT和MO流程採用了不同的方式获取Call.State。
MO流程获取Call. State (Internal)
MO流程使用GsmConnection的update()方法来获取Call.State(internal),关键代码例如以下:
update (DriverCall dc) { GsmCall newParent; //... ...省略 //依据DriverCall.State获取与之相应的GsmCall对象 newParent = parentFromDCState(dc.state); //... ...省略 //更新Call.State if (newParent != mParent) { if (mParent != null) { //移除先前连接。并将State设置为Call.State.IDLE mParent.detach(this); } //添加当前连接,并更新State newParent.attach(this, dc); mParent = newParent; changed = true; } else { boolean parentStateChange; //更新State parentStateChange = mParent.update (this, dc); changed = changed || parentStateChange; } //... ...省略 return changed; }
我们看到parentFromDCState()方法。这里实际上是依据DriverCall.State来获取相应的GsmCall对象。例如以下:
private GsmCall parentFromDCState (DriverCall.State state) { switch (state) { case ACTIVE: case DIALING: case ALERTING: return mOwner.mForegroundCall; //break; case HOLDING: return mOwner.mBackgroundCall; //break; case INCOMING: case WAITING: return mOwner.mRingingCall; //break; default: throw new RuntimeException("illegal call state: " + state); } }通过以上代码能够知道GsmCall的三种状态:foregroundCall、backgroundCall、ringingCall它们所相应的DriverCall.State。例如以下图:
在依据DriverCall.State获取GsmCall对象之后。便依据GsmCall的detach()、attach()、update()方法来更新Call.State,而更新代码的关键是stateFromDCState(),关键代码例如以下:
mState = stateFromDCState (dc.state); static State stateFromDCState (DriverCall.State dcState) { switch (dcState) { case ACTIVE: return State.ACTIVE; case HOLDING: return State.HOLDING; case DIALING: return State.DIALING; case ALERTING: return State.ALERTING; case INCOMING: return State.INCOMING; case WAITING: return State.WAITING; default: throw new RuntimeException ("illegal call state:" + dcState); } }
到这里完毕了MO流程DriverCall.State和Call.State(internal)的映射。
MT流程获取Call. State (Internal)
MO的Call.State获取是通过pendingMO.update()方法发起的。而MT流程则是通过实例化GsmConnection对象发起的,代码例如以下:
mConnections[i] = new GsmConnection(mPhone.getContext(), dc, this, i); GsmConnection (Context context, DriverCall dc, GsmCallTracker ct, int index) { //... ...省略 //依据DriverCall.State获取GsmCall mParent = parentFromDCState (dc.state); //添加GsmConnection并更新Call.State mParent.attach(this, dc); }
兴许和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。关键代码例如以下:
private void updatePhoneState() { PhoneConstants.State oldState = mState; if (mRingingCall.isRinging()) { mState = PhoneConstants.State.RINGING; } else if (mPendingMO != null || !(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) { mState = PhoneConstants.State.OFFHOOK; } else { mState = PhoneConstants.State.IDLE; } if (mState == PhoneConstants.State.IDLE && oldState != mState) { //假设是IDLE状态则发起通知,语音通话结束。告知数据连接可用 mVoiceCallEndedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); } else if (oldState == PhoneConstants.State.IDLE && oldState != mState) { //假设是非IDLE状态,语音通话開始,告知数据连接不可用 mVoiceCallStartedRegistrants.notifyRegistrants ( new AsyncResult(null, null, null)); } log("updatePhoneState: old: " + oldState +" , new: " + mState); if (mState != oldState) { //通知三方应用 mPhone.notifyPhoneStateChanged(); } }通过代码我们能够非常清楚的看到。PhoneConstants.State是由Call.State(internal)决定的,分别依据fgCall、bgCall、ringingCall来获取Call.State(internal)的状态。
简单的分析下它们之间的相应关系。
PhoneConstants. State. RINGING
依据前面的代码,我们须要查看GsmCall中的isRinging()方法的返回值,例如以下:
public boolean isRinging() { return getState().isRinging(); } //这里的mState是com.android.internal.telephony.State对象 public State getState() { return mState; } public boolean isRinging() { return this == INCOMING || this == WAITING; }依据以上代码能够知道PhoneConstants.State.RINGING相当于Call.State.INCOMING和Call.State.WAITING。
PhoneConstants. State. OFFHOOK
这里就须要查看mPendingMO对象是否为null以及fgCall和bgCall的isIdle()方法的返回值。例如以下://假设mPendingMO不为null,则表示当前是MO流程。总的来讲。假设当前为MO流程以及Call.State(internal)不为IDLE、DISCONNECTED、DISCONNETING三者中的随意一种,即表示当前Phone状态为OFFHOOK。//后面的推断表示仅仅要fgCall或者bgCall当中之中的一个不是IDLE状态,则是Phone状态为OFFHOOK mPendingMO != null || !(mForegroundCall.isIdle() && mBackgroundCall.isIdle()) //isIdle与isAlive是相互排斥的 public boolean isIdle() { return !getState().isAlive(); } //假设Call.State是IDLE/DISCONNECTED/DISCONNECTING中的随意一种状态,则返回false //反之则为true public boolean isAlive() { return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING); }
PhoneConstants. State. IDLE
在updatePhoneState()方法的最后,调用了notifyPhoneStateChanged()将Phone状态向TelephonyManager传送,并终于通过mRegistry.notifyCallState()方法将Phone状态传递给全部注冊了PhoneStateChangeListener。这里我们主要看到DefaultPhoneNotifier.notifyPhoneState()方法,在这里终于实现了Phone.State向TelePhonyManager.Call_STATE的过度,整个过程关键代码例如以下:
//GsmCallTracker updatePhoneState()方法中调用 if (mState != oldState) { mPhone.notifyPhoneStateChanged(); } //这里的this是GSMPhone对象 /*package*/ void notifyPhoneStateChanged() { updateCipherIndication(); mNotifier.notifyPhoneState(this); } public void notifyPhoneState(Phone sender) { //这里是com.android.internal.telephony.Call, sender是GSMPhone对象 Call ringingCall = sender.getRingingCall(); String incomingNumber = ""; if (ringingCall != null && ringingCall.getEarliestConnection() != null){ incomingNumber = ringingCall.getEarliestConnection().getAddress(); } try { //将Phone状态通知给全部注冊了PhoneStateChange的Listener //依据conertCallState方法将PhoneConstants.State转换为TelephonyManager.CALL_STATE mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber); } catch (RemoteException ex) { // system process is dead } } //这里重点关注三个方法: //1. sender.getRingingCall() //2. sender.getState() //3. convertCallState(sender.getState()) public GsmCall getRingingCall() { //mCT为GsmCalltracker对象,mRingingCall为GsmCall对象 return mCT.mRingingCall; } public PhoneConstants.State getState() { //mCT为GsmCallTracker对象 //mState为PhoneConstants.State对象初始值为PhoneConstants.State.IDLE //mState就是前面提到的Phone.State,也就是PhoneConstants.State return mCT.mState; } public static int convertCallState(PhoneConstants.State state) { switch (state) { case RINGING: return TelephonyManager.CALL_STATE_RINGING; case OFFHOOK: return TelephonyManager.CALL_STATE_OFFHOOK; default: return TelephonyManager.CALL_STATE_IDLE; } }
这里能够非常清楚的看到它们之间的相应关系。普通APP便能够通过获取TelephonyManager对象的CALL_STATE来推断当前Phone的状态。这里我们还是用表格来直观的看看Phone.State与Call.State(internal)以及TelephonyManager.CALL_STATE之间的相应关系,例如以下:
Call. State (TeleService)状态获取
在《Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程》中我们已经分析了。通话状态从底层传递到上层的整个流程。在经过了Telephony Framework的处理之后,便传递到TeleService中,详细流程请參看本文开头的“通话状态更新时序图”。
当更新流程来到CallModeler的onPhoneStateChanged()方法中时,我们注意到下面关键代码:
private void onPhoneStateChanged(AsyncResult r) { Log.i(TAG, "onPhoneStateChanged: "); //这里为com.android.services.telephony.Call final List<Call> updatedCalls = Lists.newArrayList(); //依据Call.State(internal)更新Call.State(TeleService) doUpdate(false, updatedCalls); //... ...省略 // M: add skip update logic. When 1A + 1R, skip update calls to InCallUI while query is running. if (!ignoreUpdate()) { if (updatedCalls.size() > 0) { for (int i = 0; i < mListeners.size(); ++i) { //将状态改变向后继续传递。终于到达InCallUI mListeners.get(i).onUpdate(updatedCalls); } } } //... ...省略 }在该方法中完毕了Call.State(Internal)和Call.State(TeleService)的转换,重点关注doUpdate()方法,关键代码例如以下:
private void doUpdate(boolean fullUpdate, List<Call> out) { //... ...省略 //通过分析能够知道connection的getState()方法实际为,获取connection相应的 //Call(Internal)的状态,也就是Call.State(Internal) //当Call.State(Internal)不属于IDLE/DISCONNECTED/INCOMING/WAITING时 //shouldUpdate返回true,我们能够理解为Phone状态位OFFHOOK时才须要更新 /*final*/ boolean shouldUpdate = (connection.getState() != com.android.internal.telephony.Call.State.DISCONNECTED && connection.getState() != com.android.internal.telephony.Call.State.IDLE && !connection.getState().isRinging()) || fullUpdate; //... ...省略 final boolean isDisconnecting = connection.getState() == com.android.internal.telephony.Call.State.DISCONNECTING; //假设Phone状态位OFFHOOK。shouldCreate返回true final boolean shouldCreate = shouldUpdate && !isDisconnecting; //依据connection对象创建与之相应的TeleService Call对象 final Call call = getCallFromMap(mCallMap, connection, shouldCreate /* create */); //... ...省略 //跳转实现Call.State(Internal)和Call.State(TeleService)的映射 boolean changed = updateCallFromConnection(call, connection, false); //... ...省略 }继续查看updateCallFromConnection()方法,关键代码例如以下:
private boolean updateCallFromConnection(Call call, Connection connection, boolean isForConference) { boolean changed = false; //依据GsmConnection对象。获取Call.State(Internal)并更新Call.State(TeleService) final int newState = translateStateFromTelephony(connection, isForConference); //... ...省略 return changed; } private int translateStateFromTelephony(Connection connection, boolean isForConference) { //connection.getState实际上为connection所属的GsmCall的状态也就是Call.State(Internal) com.android.internal.telephony.Call.State connState = connection.getState(); //... ...省略 //Call.State(Internal)与Call.State(TeleService)相应关系 int retval = State.IDLE; switch (connState) { case ACTIVE: retval = State.ACTIVE; break; case INCOMING: retval = State.INCOMING; break; case DIALING: case ALERTING: if (PhoneGlobals.getInstance().notifier.getIsCdmaRedialCall()) { retval = State.REDIALING; } else { retval = State.DIALING; } break; case WAITING: retval = State.CALL_WAITING; break; case HOLDING: retval = State.ONHOLD; break; case DISCONNECTING: retval = State.DISCONNECTING; break; case DISCONNECTED: retval = State.DISCONNECTED; default: } //获取ConferenceCall的Call.State(TeleService) if (!isForConference) { // 假设是conferenceCall则返回State.CONFERENCED if (isPartOfLiveConferenceCall(connection) && connection.isAlive()) { return State.CONFERENCED; } } return retval; }在经过以上处理之后。Call.State(Internal)就成功的转化为Call.State(TeleService)了,Call.State(TeleService)总共同拥有11个状态,例如以下:
INVALID = 0; IDLE = 1; /* The call is idle. Nothing active */ ACTIVE = 2; /* There is an active call */ INCOMING = 3; /* A normal incoming phone call */ CALL_WAITING = 4; /* Incoming call while another is active */ DIALING = 5; /* An outgoing call during dial phase */ REDIALING = 6; /* Subsequent dialing attempt after a failure */ ONHOLD = 7; /* An active phone call placed on hold */ DISCONNECTING = 8; /* A call is being ended. */ DISCONNECTED = 9; /* State after a call disconnects */ 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的定义。例如以下:
public enum InCallState { // InCall Screen is off and there are no calls // InCallUI界面退出而且没有通话 NO_CALLS, // Incoming-call screen is up // 显示来电界面 INCOMING, // In-call experience is showing // 处于通话中 INCALL, // User is dialing out // 主动呼叫即MT OUTGOING; public boolean isIncoming() { return (this == INCOMING); } public boolean isConnectingOrConnected() { return (this == INCOMING || this == OUTGOING || this == INCALL); } }该用于表示InCallActivity当前所处的状态,那么这些状态与Call.State(Internal)以及Call.State(TeleService)之间的相应关系又是什么呢?这里又须要我们回到本文开头的那张图。在来电状态变更之后,经过了Telephony Framework和TeleService的处理之后,会将相关信息传递到InCallUI中。
此时,CallList便会处理这些信息并更新InCallState的状态。
不管当前通话是来电或者挂断或者是呼叫保持,这些都可以在CallList中找到与之相应的处理方法,如:onIncoming、onDisconnect、onUpdate。通过这些方法可以完毕对状态信息的处理以及更新,它们的共通特点是都会调用updateCallInMap()方法。
在该方法中完毕对Call(TeleService)对象的创建以及和GsmConnection对象的关联。关键代码例如以下:
private boolean updateCallInMap(Call call) { //... ...省略 if (call.getState() == Call.State.DISCONNECTED) { //... ...省略 mCallMap.put(id, call); } else if (!isCallDead(call)) { mCallMap.put(id, call); //... ...省略 return updated; }这里为什么会提到CallList呢?由于依据时序图我们能够知道在CallList处理之后,便会将消息通知到InCallPresenter.onCallListChange()方法中。正是在这里将我们更新了InCallState的状态,首先看到InCallPresenter.onCallListChange()关键代码:
@Override public void onCallListChange(CallList callList) { if (callList == null) { return; } //将Call.State(TeleService)转换成InCallState InCallState newState = getPotentialStateFromCallList(callList); newState = startOrFinishUi(newState); //... ...省略 }继续查看getPotentialStateFromCallList()方法,例如以下:
public static InCallState getPotentialStateFromCallList(CallList callList) { //InCallState默认状态位NO_CALLS InCallState newState = InCallState.NO_CALLS; //假设calllist为null返回默认状态NO_CALLS if (callList == null) { return newState; } //INCOMING/OUTGOING/INCALL的相应 if (callList.getIncomingCall() != null) { newState = InCallState.INCOMING; } else if (callList.getOutgoingCall() != null) { newState = InCallState.OUTGOING; } else if (callList.getActiveCall() != null || callList.getBackgroundCall() != null || callList.getDisconnectedCall() != null || callList.getDisconnectingCall() != null) { newState = InCallState.INCALL; } return newState; }这里我们主要看下INCOMING、OUTGOING以及INCALL这几个状态是怎样与Call.State(TeleService)相应的。
InCallState. INCOMING
依据前面的代码,首先查看CallList中的getInComingCall()方法,能够看到:public Call getIncomingCall() { Call call = getFirstCallWithState(Call.State.INCOMING); if (call == null) { call = getFirstCallWithState(Call.State.CALL_WAITING); } //... ...省略 return call; } public Call getFirstCallWithState(int state) { return getCallWithState(state, 0); } //在HashMap<Integer, Call> mCallMap中查找valuses //是否有与相应state匹配的Call(TeleService) public Call getCallWithState(int state, int positionToFind) { Call retval = null; int position = 0; for (Call call : mCallMap.values()) { if (call.getState() == state) { if (position >= positionToFind) { retval = call; break; } else { position++; } } } return retval; }代码中所使用的是com.android.services.telephony.common.Call。通过分析能够知道,假设在CallList的mCallMap.valuses中有找到处于Call.State.INCOMING或者Call.State.CALL_WAITING的Call对象,即表示InCallState状态为INCOMING。
InCallState. OUTGOING
public Call getOutgoingCall() { Call call = getFirstCallWithState(Call.State.DIALING); if (call == null) { call = getFirstCallWithState(Call.State.REDIALING); } return call; }由于后面处理过程和前面InCallState.INCOMING类似,这里就不再反复。通过分析能够知道InCallState.OUTGOING与TeleService Common中的Call.State.DIALING和Call.State.REDIALING相应。
InCallState. INCALL
//ACTIVE public Call getActiveCall() { return getFirstCallWithState(Call.State.ACTIVE); } //ONHOLD public Call getBackgroundCall() { return getFirstCallWithState(Call.State.ONHOLD); } //DISCONNECTED public Call getDisconnectedCall() { return getFirstCallWithState(Call.State.DISCONNECTED); } //DISCONNECTING public Call getDisconnectingCall() { return getFirstCallWithState(Call.State.DISCONNECTING); }相同我们能够得出InCallState.INCALL相应于TeleService Common中的:Call.State.ACTIVE、Call.State.ONHOLD、Call.State.DISCONNECTED、Call.State.DISCONNECTING。
InCallState. NO_CALLS
通过前面的分析,我们大致知道了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之间的相应关系,例如以下:
图 2
本文涉及图片以及各资源,免积分下载。点这里。