注:MO跟MT获取到DriverCall. State后的处理方式一样,但是MO更直观一些,当用户发起MO的时候就开始与modem开始交互
这里简单的分析一下重要的log信息:
01-05 06:02:13.788099 1596 1596 D RILJ : [0118]> DIAL [SUB1]
01-05 06:02:13.806830 746 758 D AT : AT> ATD13611936864;
这表示发起DIAL请求,紧接着执行ATD即AT拨号指令:
可以根据serial号查看AT指令的配对,Log中的“>”表示request,“<”表示response
根据AT指令的serial号”0118”我们可以在后面找到对应的response:
01-05 06:02:13.822931 1596 1811 D RILJ : [0118]< DIAL [SUB1]
这表明整个拨号的request和response已经完成,在此期间Modem主动返回了以下信息:
该条AT指令+ECPI是MTK添加的,在标准AT指令中查询不到,具体含义如下:
+ECPI:<call_id>,<msg_type>,<is_ibt>,<is_tch>,<dir>,<call_mode>,[<number>,<type>],[<disc_cause>]
对应着这个表我们来梳理一下以上log重要信息如下:
call_id:1,call id 为1;
msg_type:130,表示CSMCC_CALL_ID_ASSIGN_MSG,也就是Dialing;
dir:0,CLCC_MO_CALL,表示MO操作;
call_mode:0,CLCC_VOICE_CALL,表示普通语音拨号;
number:138001380000,表示主叫号码;
type:129,National call,也就是本国电话,如果是145则表示国际电话;
在Modem完成DIAL操作之后,紧接着返回了以下log:
01-05 07:10:05.482199 1596 1811 D RILJ : [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [SUB1]
接下来我们直接以MT的流程为例研究一下状态从Modem上传到InCallUI的过程
以上log是一条UnSolicited response消息,处理方法是RIL.java中的processUnsolicited(),类型为:UNSOL_RESPONSE_CALL_STATE_CHANGED 。
GsmCallTracker.java (frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm)
@Override
protected synchronized void handlePollCalls(AsyncResult ar) {
// 当状态改变之后便会通过GsmPhone的notifyPreciseCallStateChanged()方法发起响应
mPhone.notifyPreciseCallStateChanged();
}
@Override
protected synchronized void handlePollCalls(AsyncResult ar) {
if (conn == null && dc != null) {
// Connection appeared in CLCC response that we don't know about
if (mPendingMO != null && mPendingMO.compareTo(dc)) {
// It's our pending mobile originating call
mConnections[i] = mPendingMO;
mPendingMO.mIndex = i;
//GsmConnection根据DriverCall更新GsmCall (MO流程获取状态方式)
mPendingMO.update(dc);
mPendingMO = null;
}
} else if (conn != null && dc != null && !conn.compareTo(dc)) {
//根据DriverCall新建GsmConnection对象,并根据DriverCall状态获取对应的GsmCall对象(MT流程获取状态方式)
mConnections[i] = new GsmConnection (mPhone.getContext(), dc, this, i);
}
从以上代码可以看出,针对MT和MO流程采用了不同的方式获取Call.State。
MO流程使用GsmConnection的update()方法来获取Call.State(internal),关键代码如下:
1)、GsmConnection.java (frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm)
// Returns true if state has changed, false if nothing changed
/*package*/ boolean
update (DriverCall dc) {
GsmCall newParent;
boolean changed = false;
boolean wasConnectingInOrOut = isConnectingInOrOut();
boolean wasHolding = (getState() == GsmCall.State.HOLDING);
//... ...省略
//根据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;
}
if (wasConnectingInOrOut && !isConnectingInOrOut()) {
onConnectedInOrOut();
}
if (changed && !wasHolding && (getState() == GsmCall.State.HOLDING)) {
// We've transitioned into HOLDING
onStartedHolding();
}
return changed;
}
2)、我们看到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,如下图:
3)、在根据DriverCall.State获取GsmCall对象之后,便根据GsmCall的detach()、attach()、update()方法来更新Call.State,而更新代码的关键是stateFromDCState(),关键代码如下:
Call.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)
public 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)的映射。
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的对应关系如下:
前者根据Call.State(Internal)获取对应状态,后者根据Phone.State获取对应状态。
Phone.State,其使用IDLE、RINGING、OFFHOOK来表示当前Phone的状态,这些状态将提供给TelephonyManager并暴露给三方应用。
在GsmCallTracker的handlePollCalls()中,经过了DriverCall.State的获取与Call.State(internal)的获取之后,通过updatePhoneState()来更新PhoneConstants.State,关键代码如下:
GsmCallTracker.java (frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm)
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));
}
if (mState != oldState) {
//通知三方应用
mPhone.notifyPhoneStateChanged();
}
}
通过代码我们可以很清楚的看到,PhoneConstants.State是由Call.State(internal)决定的,分别根据fgCall、bgCall、ringingCall来获取Call.State(internal)的状态。简单的分析下它们之间的对应关系。
根据前面的代码,我们需要查看Call.java中的isRinging()方法的返回值,如下:
Call.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)
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。
这里就需要查看mPendingMO对象是否为null以及fgCall和bgCall的isIdle()方法的返回值,如下:
GsmCallTracker.java (frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm)
//如果mPendingMO不为null,则表示当前是MO流程。
//后面的判断表示只要fgCall或者bgCall其中之一不是IDLE状态,则是Phone状态为OFFHOOK
private void updatePhoneState() {
if (mPendingMO != null ||
!(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) {
mState = PhoneConstants.State.OFFHOOK;
}
}
Call.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)
//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.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的过度,整个过程关键代码如下:
// GsmCallTracker updatePhoneState()方法中调用
private void updatePhoneState() {
if (mState != oldState) {
mPhone.notifyPhoneStateChanged();
}
}
// GSMPhone.java (frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm)
void notifyPhoneStateChanged() {
mNotifier.notifyPhoneState(this);
}
//DefaultPhoneNotifier.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)
@Override
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 {
if (mRegistry != null) {
//将Phone状态通知给所有注册了PhoneStateChange的Listener
//根据conertCallState方法将PhoneConstants.State转换为TelephonyManager.CALL_STATE
mRegistry.notifyCallStateForPhoneInfo(phoneId, phoneType, subId,
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;
}
// Phone.State转化为TelephonyManager.CallState
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之间的对应关系,如下:
注:
PhoneConstants.State.OFFHOOK 摘机状态,至少有个电话活动。该活动或是拨打(dialing)或是通话,或是 on hold。并且没有电话是ringing or waiting
PhoneConstants.State.IDLE 空闲状态,没有任何活动。
PhoneConstants.State.RINGING 来电状态,电话铃声响起的那段时间或正在通话又来新电,新来电话不得不等待的那段时间。
Call.java (packages\apps\incallui\src\com\android\incallui)
private void updateFromTelecommCall() {
// 实现了 Call.State(Internal)和Call.State(TeleService)的映射
setState(translateState(mTelecommCall.getState()));
setDisconnectCause(mTelecommCall.getDetails().getDisconnectCause());
mChildCallIds.clear();
for (int i = 0; i < mTelecommCall.getChildren().size(); i++) {
mChildCallIds.add(
CallList.getInstance().getCallByTelecommCall(
mTelecommCall.getChildren().get(i)).getId());
}
}
private static int translateState(int state) {
//Call.State(Internal)与Call.State(TeleService)对应关系
switch (state) {
case android.telecom.Call.STATE_NEW:
case android.telecom.Call.STATE_CONNECTING:
return Call.State.CONNECTING;
case android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT:
return Call.State.SELECT_PHONE_ACCOUNT;
case android.telecom.Call.STATE_DIALING:
return Call.State.DIALING;
case android.telecom.Call.STATE_RINGING:
return Call.State.INCOMING;
case android.telecom.Call.STATE_ACTIVE:
return Call.State.ACTIVE;
case android.telecom.Call.STATE_HOLDING:
return Call.State.ONHOLD;
case android.telecom.Call.STATE_DISCONNECTED:
return Call.State.DISCONNECTED;
case android.telecom.Call.STATE_DISCONNECTING:
return Call.State.DISCONNECTING;
default:
return Call.State.INVALID;
}
}
在经过以上处理之后,Call.State(Internal)就成功的转化为Call.State(TeleService)了,Call.State(TeleService)总共有13个状态,如下:
通过查找我们可以在packages/apps/InCallUI/src/com/android/incallui/InCallPresenter.java中找到InCallState的定义,如下:
/**
* All the main states of InCallActivity.
*/
public enum InCallState {
// 没有电话
NO_CALLS,
// 来电
INCOMING,
// 正在通话中
INCALL,
//等待用户输入然后再呼出
WAITING_FOR_ACCOUNT,
// 预备拨出界面(UI is starting up but no call has been initiated yet.The UI is waiting for Telecomm to respond)
PENDING_OUTGOING,
// 拨出电话
OUTGOING;
public boolean isIncoming() {
return (this == INCOMING);
}
public boolean isConnectingOrConnected() {
return (this == INCOMING ||
this == OUTGOING ||
this == INCALL);
}
}
该用于表示InCallActivity当前所处的状态,那么这些状态与Call.State(Internal)以及Call.State(TeleService)之间的对应关系又是什么呢?我们回到MT流程中,在来电状态变更之后,经过了Telephony Framework和TeleService的处理之后,会将相关信息传递到InCallUI中。此时,CallList便会处理这些信息并更新InCallState的状态。
无论当前通话是来电或者挂断或者是呼叫保持,这些都能够在CallList中找到与之对应的处理方法,如:onIncoming、onDisconnect、onUpdate。通过这些方法可以完成对状态信息的处理以及更新,它们的共通特点是都会调用updateCallInMap()方法。在该方法中完成对Call(TeleService)对象的创建以及和GsmConnection对象的关联,关键代码如下:
private boolean updateCallInMap(Call call) {
boolean updated = false;
if (call.getState() == Call.State.DISCONNECTED) {
// update existing (but do not add!!) disconnected calls
if (mCallById.containsKey(call.getId())) {
// For disconnected calls, we want to keep them alive for a few seconds so that the
// UI has a chance to display anything it needs when a call is disconnected.
// Set up a timer to destroy the call after X seconds.
final Message msg = mHandler.obtainMessage(EVENT_DISCONNECTED_TIMEOUT, call);
mHandler.sendMessageDelayed(msg, getDelayForDisconnect(call));
mPendingDisconnectCalls.add(call);
mCallById.put(call.getId(), call);
/// M:add for plug in. @{
mCallMap.put(call.getId(), call.getTelecommCall());
/// @}
mCallByTelecommCall.put(call.getTelecommCall(), call);
updated = true;
}
} else if (!isCallDead(call)) {
mCallById.put(call.getId(), call);
/// M:add for plug in. @{
mCallMap.put(call.getId(), call.getTelecommCall());
/// @}
mCallByTelecommCall.put(call.getTelecommCall(), call);
updated = true;
}
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()方法,如下:
/**
* Given the call list, return the state in which the in-call screen should be.
*/
public InCallState getPotentialStateFromCallList(CallList callList) {
InCallState newState = InCallState.NO_CALLS;
if (callList == null) {
return newState;
}
//INCOMING/OUTGOING/INCALL的对应
if (callList.getIncomingCall() != null) {
newState = InCallState.INCOMING;
} else if (callList.getWaitingForAccountCall() != null) {
newState = InCallState.WAITING_FOR_ACCOUNT;
} else if (callList.getPendingOutgoingCall() != null) {
newState = InCallState.PENDING_OUTGOING;
} 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;
}
if (newState == InCallState.NO_CALLS) {
if (mBoundAndWaitingForOutgoingCall) {
return InCallState.OUTGOING;
}
}
return newState;
}
这里我们主要看下INCOMING、OUTGOING以及INCALL这几个状态是如何与Call.State(TeleService)对应的。
根据前面的代码,首先查看CallList中的getInComingCall()方法,可以看到:
public Call getIncomingCall() {
Call call = getFirstCallWithState(Call.State.INCOMING);
if (call == null) {
call = getFirstCallWithState(Call.State.CALL_WAITING);
}
return call;
}
/**
* Returns first call found in the call map with the specified state.
*/
public Call getFirstCallWithState(int state) {
return getCallWithState(state, 0);
}
//在HashMap mCallMap中查找valuses
//是否有与对应state匹配的Call(TeleService)
public Call getCallWithState(int state, int positionToFind) {
Call retval = null;
int position = 0;
for (Call call : mCallById.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。
同样我们需要查看CallList中的getOutgoingCall()方法,关键代码如下:
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对应。
查看getActiveCall()、getBackgroundCall()、getDisconnectedCall()、getDisconnectingCall()方法,关键代码如下:
//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。
如果不满足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来说,会有自己单独的处理,因此也不属于NO_CALLS。
(1). DriverCall.State;
将Modem返回的通话状态转换成最基本的Call状态,DriverCall.State包含ACTIVE、HOLDING、INCOMING、WAITING 、DIALING、ALERTING、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种类型。
(3). PhoneConstants.State;
在Android 4.0以及之前叫做Phone.State,用于描述手机在通话过程中的状态,其状态更新来源于Call.State(internal)。根据Call.State(internal)的状态划分为三类:IDLE、RINGING、OFFHOOK。这些状态供系统以及系统级APP使用。
(4). TelephonyManager.CALL_STATE_XX;
(5). Call.State(TeleService);
在Android 4.4中,Phone模块被划分为InCallUI和TeleService两部分,而这里的Call.State(TeleService)正是通话状态在TeleService中的表现,同时该状态也将为后面的InCallState提供参考基准。Call.State(TeleService)包含了基本的13种类型:ACTIVE、ONHOLD、DIALING、REDIALING、INCOMING、CALL_WAITING、DISCONNECTED、DISCONNECTING、IDLE、CONFERENCE、INVALID、PENDING_OUTGOING(预备拨出)、WAITING_FOR_ACCOUNT(等待用户输入)。
我们知道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所处状态,其包含类型为6种:NO_CALLS、INCALL、OUTGOING、INCOMING、PENDING_OUTGOING(预备拨出)、WAITING_FOR_ACCOUNT(等待用户输入)。该类型是首次出现在Android Telephony中,InCallUI的显示则依赖于此状态。
特别注意:InCallState.INCALL等价于Call.State(TeleService)的ACTIVE、ONHOLD、DISCONNECTING、DISCONNECTED;而PhoneConstants.State.OFFHOOK对应于Call.State(TeleService)的ACTIVE、ONHOLD、DIALING、REDIALING。
1)、Android 6.0 中 Telephony架构中各种State的映射关系
2)、Android 6.0 中,Telephony Framework Call.State 之间的转换关系如下图所示
1)、一个Phone可以有多个Call。而每一个Call都对应着9种状态,分别是IDLE,ACTIVE,HOLDING,DIALING,ALERTING,INCOMING,WAITING,DISCONNECTED,DISCONNECTING。一般Phone启动时创建了3个Call,根据状态的不同,3个Call可以成为RingCall,ForegroundCall以及BackgroundCall和IdleCall。其中RingCall,ForegroundCall唯一,BackgroundCall你自己算下就知道最多2个,当一个电话都没有时3个Call都为Idle状态成为IdleCall。每个Call,最多有5个connections,但同时3个Call合起来不能超过7个connections。
这里就存在着三类状态,Connection的状态、CallState和PhoneState。Connection的状态更新CallState,而CallState更新PhoneState。
2)、从Call的9种状态来看,同一时刻三个Call只能有一个RingCall(INCOMING或WAITING状态),一个ForegroundCall(ACTIVE状态)一个BackgroundCall(HOLDING状态),可以同时有多个IDLE状态。
这里需要联想到实际的电话:假设有一个超级大忙人,
a)首先,有一通电话Call_1进入,Ring~~Ring,接之,此时这个Call_1由Ring变为Active状态,成为ForegroundCall;
b)接Call_1的过程中,又来了一通电话Call_2,接之,此时Call_1状态转化为HOLD成为BackgroundCall,而Call_2由Ring变为Active成为ForegroundCall
c)两通电话同时存在时应该还是可以切换的(多方通话),也就是说ForegroundCall和BackgroundCall可以互相转换,CallManager也确实提供了这样的一个函数;
d)此时又来第三通电话,再接之,BackgroundCall数量加1,ForegroundCall变为BackgroundCall。
以上分析可以得出结论就是:一个Phone对应多个Call。
private CallManager() {
mPhones = new ArrayList();
mRingingCalls = new ArrayList<Call>();
mBackgroundCalls = new ArrayList<Call>();
mForegroundCalls = new ArrayList<Call>();
mDefaultPhone = null;
}
参考博文:
http://blog.csdn.net/yihongyuelan/article/details/29187281