无论数本地主动挂断还是远程挂断,最后都会finish通话界面。
在远程挂点电话流程分析已论述, CallsManager的setCallState方法会更新界面,在此就是finish通话界面。
同样的,消息流也会从services telecom走到InCallUI。
CallsManager的setCallState方法调用流程图如下,
CallsManager的setCallState方法中有关电话挂断的代码如下,
listener.onCallStateChanged(call, oldState, newState);
在InCallController方法中,比较多的方法会调用updateCall方法,该方法如下,
for (Map.Entry entry : mInCallServices.entrySet()) {
ComponentName componentName = entry.getKey();
IInCallService inCallService = entry.getValue();
componentsUpdated.add(componentName);
try {
inCallService.updateCall(parcelableCall);
} catch (RemoteException ignored) {
}
}
IinCallService指向的是dialer进程中的是InCallService的内部类InCallServiceBinder。
InCallService的内部类InCallServiceBinder的updateCall方法如下,
public void updateCall(ParcelableCall call) {
mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget();
}
mHandler变量的handleMessage方法对MSG_UPDATE_CALL消息处理如下,
case MSG_UPDATE_CALL:
mPhone.internalUpdateCall((ParcelableCall) msg.obj);
break;
Phone的internalUpdateCall方法调用流程图如下,
Phone的internalUpdateCall方法如下,
final void internalUpdateCall(ParcelableCall parcelableCall) {
Call call = mCallByTelecomCallId.get(parcelableCall.getId());
if (call != null) {
checkCallTree(parcelableCall);
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
}
}
Call的fireStateChanged方法如下,
private void fireStateChanged(final int newState) {
for (CallbackRecord record : mCallbackRecords) {
final Call call = this;
final Callback callback = record.getCallback();
record.getHandler().post(new Runnable() {
@Override
public void run() {
callback.onStateChanged(call, newState);
}
});
}
}
mCallbackRecordslist中保存了回调的CallbackRecord对象,
是在registerCallback方法中注册的,
public void registerCallback(Callback callback, Handler handler) {
unregisterCallback(callback);
// Don't allow new callback registration if the call is already being destroyed.
if (callback != null && handler != null && mState != STATE_DISCONNECTED) {
mCallbackRecords.add(new CallbackRecord(callback, handler));
}
}
在InCallUI的Call.java中的构造方法中,会调用Telecom Call的registerCallback进行注册,
public Call(android.telecom.Call telecommCall) {
mTelecommCall = telecommCall;
mId = ID_PREFIX + Integer.toString(sIdCounter++);
updateFromTelecommCall();
mTelecommCall.registerCallback(mTelecomCallCallback);
}
注意, Telecom Call是services telecom对外提供的接口,phone系统中有好几个名为Call的类,当然,还有一些其他的同名类,
看代码时千万不要混淆。
mTelecomCallCallback变量的onStateChanged方法如下,
private android.telecom.Call.Callback mTelecomCallCallback =
new android.telecom.Call.Callback() {
@Override
public void onStateChanged(android.telecom.Call call, int newState) {
Log.d(this, "TelecommCallCallback onStateChanged call=" + call + " newState="
+ newState);
update();
}
•••
mTelecomCallCallback变量的大部分方法都会调用update方法,
update方法如下,
private void update() {
Trace.beginSection("Update");
int oldState = getState();
updateFromTelecommCall();
if (oldState != getState() && getState() == Call.State.DISCONNECTED) {
CallList.getInstance().onDisconnect(this);
/* Disconnect the QTI IMS service */
mQtiImsInterfaceImpl.stopQtiImsInterface();
} else {
CallList.getInstance().onUpdate(this);
}
Trace.endSection();
}
在很多情况下会更新call,
如果当前的状态是断开(DISCONNECTED),那就调用CallList的onDisconnect方法;
其他情况下,例如远程接听,会调用CallList的onUpdate方法。
在此,接听的更新就不论述了,和onDisconnect方法调用流程几乎相同。
CallList的onDisconnect方法如下,
public void onDisconnect(Call call) {
if (updateCallInMap(call)) {
Log.i(this, "onDisconnect: " + call);
// notify those listening for changes on this specific change
notifyCallUpdateListeners(call);
// notify those listening for all disconnects
notifyListenersOfDisconnect(call);
}
}
notifyListenersOfDisconnect方法如下,
private void notifyListenersOfDisconnect(Call call) {
for (Listener listener : mListeners) {
listener.onDisconnect(call);
}
}
InCallPresenter的onDisconnect方法如下,
public void onDisconnect(Call call) {
maybeShowErrorDialogOnDisconnect(call);
// We need to do the run the same code as onCallListChange.
onCallListChange(mCallList);// finish activity
if (isActivityStarted()) {
mInCallActivity.dismissKeyguard(false);
}
wakeUpScreen();//屏幕唤醒
}
InCallPresenter的attemptFinishActivity方法如下,
if (doFinish) {
mInCallActivity.setExcludeFromRecents(true);
mInCallActivity.finish();
直接调用InCallActivity的finish方法。
这样,通话界面就finish了。整个通话过程也结束了。
另外,在InCallPresenter 的onCallListChange方法中,调用startOrFinishUi方法之后,
for (InCallStateListener listener : mListeners) {
Log.d(this, "Notify " + listener + " of state " + mInCallState.toString());
listener.onStateChange(oldState, mInCallState, callList);
}
会调用监听器的onStateChange方法,和来电时的onIncomingCall 监听方法类似,
VideoCallPresenter/CallCardPresenter/CallButtonPresenter等会实现onStateChange方法,更新界面。