Android Dialer源码分析之通话来电UI显示

关于电话来电流程可以参看以下三篇博客:
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的。
至于状态改变的监听,都是从底层监听传来的
下面分析 onIncomingCallonCallListChange

  /** 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就开始显示了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值