3.3 notifyPreciseCallStateChanged
notifyPreciseCallStateChanged方法是这三个方法中最难分析的一个, GsmCallTracker的notifyPreciseCallStateChanged
方法调用流程图如下,
PhoneBase的notifyPreciseCallStateChangedP方法调用逻辑如下,
1,利用AsyncResult推动着状态往下继续更新,
AsyncResult ar = new AsyncResult(null, this, null);
mPreciseCallStateRegistrants.notifyRegistrants(ar);
2,调用DefaultPhoneNotifier的notifyPreciseCallState方法将状态发送出去,
mNotifier.notifyPreciseCallState(this);
到此,就需要分2路来论述了,首先论述简单的DefaultPhoneNotifier的notifyPreciseCallState方法的调用。
1,notifyPreciseCallState
和上小节的notifyPhoneState方法类似, DefaultPhoneNotifier的notifyPreciseCallState方法逻辑如下,
1,首先获取三路通话,
int subId = sender.getSubId();
Call ringingCall = sender.getRingingCall();
Call foregroundCall = sender.getForegroundCall();
Call backgroundCall = sender.getBackgroundCall();
2,然后将这三路通话的状态分别发送出去,
if (ringingCall != null && foregroundCall != null && backgroundCall != null) {
try {
mRegistry.notifyPreciseCallStateForSubscriber(subId,
convertPreciseCallState(ringingCall.getState()),
convertPreciseCallState(foregroundCall.getState()),
convertPreciseCallState(backgroundCall.getState()));
} catch (RemoteException ex) {
// system process is dead
}
}
在调用TelephonyRegistry的notifyPreciseCallStateForSubscriber方法之前,需要调用convertPreciseCallState方法将
Call.State的状态和PreciseCallState状态进行映射。convertPreciseCallState方法如下,
switch (state) {
case ACTIVE:
return PreciseCallState.PRECISE_CALL_STATE_ACTIVE;
case HOLDING:
return PreciseCallState.PRECISE_CALL_STATE_HOLDING;
case DIALING:
return PreciseCallState.PRECISE_CALL_STATE_DIALING;
case ALERTING:
return PreciseCallState.PRECISE_CALL_STATE_ALERTING;
case INCOMING:
return PreciseCallState.PRECISE_CALL_STATE_INCOMING;
case WAITING:
return PreciseCallState.PRECISE_CALL_STATE_WAITING;
case DISCONNECTED:
return PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED;
case DISCONNECTING:
return PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING;
default:
return PreciseCallState.PRECISE_CALL_STATE_IDLE;
}
因此, Call.State与PreciseCallState的State对应关系如下,
Call.State | PreciseCallState以及对应数值 | |
State.ACTIVE | PRECISE_CALL_STATE_ACTIVE | 1 |
State. DIALING | PRECISE_CALL_STATE_DIALING | 3 |
State. ALERTING | PRECISE_CALL_STATE_ALERTING | 4 |
State. HOLDING | PRECISE_CALL_STATE_HOLDING | 2 |
State. INCOMING | PRECISE_CALL_STATE_INCOMING | 5 |
State. WAITING | PRECISE_CALL_STATE_WAITING | 6 |
State. DISCONNECTED | PRECISE_CALL_STATE_DISCONNECTED | 7 |
State. DISCONNECTING | PRECISE_CALL_STATE_DISCONNECTING | 8 |
State. IDLE | PRECISE_CALL_STATE_IDLE | 0 |
PreciseCallState定义如下,
public class PreciseCallState implements Parcelable {
说明是可以进行跨进程通信的。
TelephonyRegistry的notifyPreciseCallStateForSubscriber方法逻辑如下,
1,首先通过PhoneStateListener的跨进程回调将PreciseCallState发送出去,
mPreciseCallState = new PreciseCallState(ringingCallState, foregroundCallState,
backgroundCallState, DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID);
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE)
&& ((r.subId == subId) || (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID))) {
try {
r.callback.onPreciseCallStateChanged(mPreciseCallState);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
Record是TelephonyRegistry的内部类, callback是PhoneStateListener的binder对象,
这样就通过PreciseCallState 将三路通话的Call状态发送出去了。
2,调用broadcastPreciseCallStateChanged方法将三路通话的Call状态通过广播的形式发送出去,
broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, backgroundCallState,
DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID, subId);
broadcastPreciseCallStateChanged方法如下,
ntent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState);
intent.putExtra(TelephonyManager.EXTRA_DISCONNECT_CAUSE, disconnectCause);
intent.putExtra(TelephonyManager.EXTRA_PRECISE_DISCONNECT_CAUSE, preciseDisconnectCause);
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
}
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
android.Manifest.permission.READ_PRECISE_PHONE_STATE);
因此, TelephonyRegistry类不仅通过回调发送phone的状态,而且还通过广播的形式将phone状态发送出去。
因此,第三方app可以注册并接收相应的广播。
2,状态更新
在GSMPhone 的notifyPreciseCallStateChangedP方法中,会通知phone状态的改变,
AsyncResult ar = new AsyncResult(null, this, null);
mPreciseCallStateRegistrants.notifyRegistrants(ar);
mPreciseCallStateRegistrants也是RegistrantList对象,定义如下,
protected final RegistrantList mPreciseCallStateRegistrants = new RegistrantList();
对于RegistrantList机制,就是一个观察者模式,谁注册就回调谁。
mPreciseCallStateRegistrants是在registerForPreciseCallStateChanged方法中完成注册的,
mPreciseCallStateRegistrants.addUnique(h, what, obj);
在unregisterForPreciseCallStateChanged方法中取消注册的,
mPreciseCallStateRegistrants.remove(h);
现在问题是哪个类会调用GSMPhone的registerForPreciseCallStateChanged方法进行注册,
TelephonyConnection.java中的setOriginalConnection方法会调用,如下,
getPhone().registerForPreciseCallStateChanged(
mHandler, MSG_PRECISE_CALL_STATE_CHANGED, null);
当然,除此之外,还会注册一些很多其他的状态。
因此,一旦GSMPhone 的notifyPreciseCallStateChangedP方法得到调用,必然会向TelephonyConnection的内部
变量mHandler发送MSG_PRECISE_CALL_STATE_CHANGED方法,mHandler的handleMessage方法对该消息处理如下,
updateState();
在TelephonyConnection中, 有比较多的方法会调用updateState方法,例如,当远程挂断时, mHandler会收到MSG_DISCONNECT消息,
也会调用updateState方法。
updateState方法主要逻辑如下,
1,调用GsmConnection的方法获取电话的信息,例如号码,通话的Call状态等
final String number = mOriginalConnection.getAddress();
final Phone phone = mOriginalConnection.getCall().getPhone();
int cause = mOriginalConnection.getDisconnectCause();
final boolean isEmergencyNumber =
PhoneNumberUtils.isLocalEmergencyNumber(TelephonyGlobals. getApplicationContext(), number);
Call.State newState = mOriginalConnection.getState();
对于GMS制式的SIM卡来说,此处的mOriginalConnection就是GsmConnection对象。
getState方法就是获取Call.State的状态。
2,根据Call.State的状态调用不同的方法进行处理,对应的状态和方法如下,
Call.State | 对应的处理方法 | 对应的Connection状态 | 对应的值 |
State.ACTIVE | setActiveInternal | STATE_ACTIVE | 4 |
State. DIALING | setDialing | STATE_DIALING | 3 |
State. ALERTING | |||
State. HOLDING | setOnHold | STATE_HOLDING | 5 |
State. INCOMING | setRinging | STATE_RINGING | 2 |
State. WAITING | |||
State. DISCONNECTED | setDisconnected | STATE_DISCONNECTED | 6 |
State. DISCONNECTING | 不处理 |
|
|
State. IDLE |
例如,拨出电话---接听电话---挂断电话 对应的状态转换如下,
来电---接听电话---挂断电话 对应的状态转换如下,
3,最后更新信息
updateStatusHints();
updateConnectionCapabilities();
updateAddress();
updateMultiparty();
对于上表中的5个方法,现在分别一一论述。
TelephonyConnection的父类Connection的setDialing方法如下,
public final void setDialing() {
checkImmutable();
setState(STATE_DIALING); //调用setState将状态设置为STATE_DIALING
}
TelephonyConnection的父类Connection的setRinging方法如下,
setState(STATE_RINGING); //调用setState将状态设置为STATE_RINGING
setActiveInternal也会调用父类Connection的setActive方法, setActive方法如下,
setState(STATE_ACTIVE); //调用setState将状态设置为STATE_ACTIVE
TelephonyConnection的父类Connection的setOnHold方法如下,
setState(STATE_HOLDING); //调用setState将状态设置为STATE_HOLDING
TelephonyConnection的父类Connection的setDisconnected方法如下,
setState(STATE_DISCONNECTED); //调用setState将状态设置为STATE_DISCONNECTED
•••
for (Listener l : mListeners) {
l.onDisconnected(this, disconnectCause); //调用监听器的onDisconnected方法。
}
由此可知,这5个方法都会调用setState方法设置状态, Connection的setState方法主要逻辑如下,
for (Listener l : mListeners) {
l.onStateChanged(this, state);
}
调用监听器的onStateChanged方法。
根据 远程挂断电话流程分析 这一章节的论述逻辑,Connection的setState方法调用流程图如下,
ConnectionService的内部匿名类的onStateChanged如下,
switch (state) {
case Connection.STATE_ACTIVE:
mAdapter.setActive(id);
break;
case Connection.STATE_DIALING:
mAdapter.setDialing(id);
break;
case Connection.STATE_DISCONNECTED:
// Handled in onDisconnected()
break;
case Connection.STATE_HOLDING:
mAdapter.setOnHold(id);
break;
case Connection.STATE_NEW:
// Nothing to tell Telecom
break;
case Connection.STATE_RINGING:
mAdapter.setRinging(id);
break;
}
就是根据不同的phone状态调用ConnectionServiceAdapter的4个不同方法。STATE_DISCONNECTED 没有在这个地方进行处理,
因为在其他流程中单独处理了。
ConnectionServiceAdapter的4个方法调用流程完全相同, setActive方法调用如下,
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
adapter.setActive(callId);
} catch (RemoteException e) {
}
}
这是一个跨进程的调用,当前在phone进程中, IconnectionServiceAdapter 是Telecom进程的ConnectionServiceWrapper的内部类
Adapter在phone进程中的binder对象。因此,会跨进程调用到Telecom进程当中,入口就是ConnectionServiceWrapper的内部类Adapter。
3,Telecom状态更新
ConnectionServiceWrapper的内部类Adapter的setActive, setDialing, setOnHold, setRinging, setDisconnected等其他跨进程的方法
调用流程图完全相同,
CallsManager的4个方法都会调用setCallState方法设置Call的状态, markCallAsRinging方法如下,
void markCallAsRinging(Call call) {
setCallState(call, CallState.RINGING, "ringing set explicitly");
}
setCallState主要逻辑如下,如果状态有变化,则调用监听器的onCallStateChanged方法,
for (CallsManagerListener listener : mListeners) {
if (Log.SYSTRACE_DEBUG) {
Trace.beginSection(listener.getClass().toString() + " onCallStateChanged");
}
listener.onCallStateChanged(call, oldState, newState);
•••
}
最后的InCallController的updateCall方法逻辑如下,
1,调用toParcelableCall方法将 Call和CallState的状态进行映射,
ParcelableCall parcelableCall = toParcelableCall(call,
videoProviderChanged /* includeVideoProvider */);
2,进行跨进程调用
List<ComponentName> componentsUpdated = new ArrayList<>();
for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
ComponentName componentName = entry.getKey();
IInCallService inCallService = entry.getValue();
componentsUpdated.add(componentName);
try {
inCallService.updateCall(parcelableCall);
当前进程在Telecom中, IInCallService 是Dialer进程的InCallService内部类InCallServiceBinder在Telecom进程中的binder对象。
InCallController的toParcelableCall方法首先调用getParcelableState方法将状态进行映射,
int state = getParcelableState(call);
然后构造ParcelableCall对象并将状态保存在其中。
CallState 和telecom.Call映射的关系如下表,
CallState | telecom.Call |
ABORTED | STATE_DISCONNECTED |
DISCONNECTED | |
ACTIVE | STATE_ACTIVE |
CONNECTING | STATE_CONNECTING |
DIALING | STATE_DIALING |
DISCONNECTING | STATE_DISCONNECTING |
NEW | STATE_NEW |
ON_HOLD | STATE_HOLDING |
RINGING | STATE_RINGING |
SELECT_PHONE_ACCOUNT | STATE_SELECT_PHONE_ACCOUNT |
最后phone状态一路调用,终于进入了Dialer进程,入口方法为InCallService内部类InCallServiceBinder的updateCall方法。