關於電話來電流程可以參看以下三篇博客:
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
就開始顯示了。