关于电话来电流程可以参看以下三篇博客:
Android 8.0来电流程分析(一)
Android 8.0来电流程分析(二)
Android 8.0来电流程分析(三)
讲述了从RIL(Radio Interface Layer)层到InCallPresenter的流程。
到了InCallPresenter,就是Incall UI的部分
InCallPresenter
InCallPresenter implements CallList.Listener
在CallList.Listener里都是从通话服务里更新状态的监听回调。
其中
void onIncomingCall(DialerCall call);
void onCallListChange(CallList callList);
这两个是来电和通话有改变时的接口方法。UI的更新显示就是从这里开始的。是的,刚进行通话的这时候Activity还没构建呢。
InCallPresenter的构造使用了单例模式,初始化出现的地方是在setup方法里,而初始化调用的地方是在InCallServiceImpl里。
public void setUp(
@NonNull Context context,
CallList callList,
ExternalCallList externalCallList,
StatusBarNotifier statusBarNotifier,
ExternalCallNotifier externalCallNotifier,
ContactInfoCache contactInfoCache,
ProximitySensor proximitySensor,
FilteredNumberAsyncQueryHandler filteredNumberQueryHandler) {
...
addListener(mStatusBarNotifier);
...
addIncomingCallListener(mStatusBarNotifier);
...
addListener(mProximitySensor);
...
mCallList.addListener(this);
...
}
初始化的时候就是设置了一些监听器。
当有来电的时候监听回调onIncomingCall
,当不是来电,是拨出去的时候监听回调onCallListChange
。这两个方法里都是可以调起IncallActivity
的。
至于状态改变的监听,都是从底层监听传来的
下面分析 onIncomingCall
和 onCallListChange
/** Called when there is a new incoming call. */
@Override
public void onIncomingCall(DialerCall call) {
android.util.Log.i(TAG, "onIncomingCall ");
InCallState newState = startOrFinishUi(InCallState.INCOMING);
InCallState oldState = mInCallState;
mInCallState = newState;
for (IncomingCallListener listener : mIncomingCallListeners) {
listener.onIncomingCall(oldState, mInCallState, call);
}
if (mInCallActivity != null) {
// Re-evaluate which fragment is being shown.
mInCallActivity.onPrimaryCallStateChanged();
}
}
@Override
public void onCallListChange(CallList callList) {
android.util.Log.i(TAG, "onCallListChange ");
if (mInCallActivity != null && mInCallActivity.isInCallScreenAnimating()) {
mAwaitingCallListUpdate = true;
return;
}
if (callList == null) {
return;
}
mAwaitingCallListUpdate = false;
InCallState newState = getPotentialStateFromCallList(callList);
InCallState oldState = mInCallState;
LogUtil.d(
"InCallPresenter.onCallListChange",
"onCallListChange oldState= " + oldState + " newState=" + newState);
newState = startOrFinishUi(newState);
LogUtil.d(
"InCallPresenter.onCallListChange", "onCallListChange newState changed to " + newState);
// Set the new state before announcing it to the world
LogUtil.d(
"InCallPresenter.onCallListChange",
"Phone switching state: " + oldState + " -> " + newState);
mInCallState = newState;
...省略
}
这两个方法里都执行了startOrFinishUi
这个方法;
startOrFinishUi
这个方法顾名思义,就是检测是否需要显示和关闭UI,
private InCallState startOrFinishUi(InCallState newState) {
...省略
boolean showCallUi = InCallState.OUTGOING == newState && mainUiNotVisible;
showCallUi |=
(InCallState.PENDING_OUTGOING == mInCallState
&& InCallState.INCALL == newState
&& !isShowingInCallUi());
showCallUi |= mainUiNotVisible && shouldLaunchMainUiForVideoCall(mInCallState, newState);
showCallUi |=
InCallState.PENDING_OUTGOING == newState
&& mainUiNotVisible
&& isCallWithNoValidAccounts(mCallList.getPendingOutgoingCall());
showCallUi |=
InCallState.WAITING_FOR_ACCOUNT == mInCallState
&& InCallState.INCALL == newState
&& mCallList.getActiveOrBackgroundCall() != null;
if (showCallUi || showAccountPicker) {
LogUtil.i("InCallPresenter.startOrFinishUi", "Start in call UI");
showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */);
} else if (startIncomingCallSequence) {
if (!startUi(newState)) {
return mInCallState;
}
/// @}
} else if (newState == InCallState.NO_CALLS) {
// The new state is the no calls state. Tear everything down.
attemptFinishActivity();
attemptCleanup();
}
return newState;
}
这个方法内容有点多,主要就是通过各种属性的判断,最后判断showCallUi
这个值是不是True
,如果是True
那么就去开启UI
public void showInCall(boolean showDialpad, boolean newOutgoingCall) {
LogUtil.d("InCallPresenter.showInCall", "Showing InCallActivity");
mContext.startActivity(
InCallActivity.getIntent(
mContext, showDialpad, newOutgoingCall, false /* forFullScreen */));
}
showInCall就是去开启InCallActivity
.这样InCallActivity
就开始显示了。
