来电界面以及响铃分析

本文详细解析了来电界面的启动流程与响铃机制,包括如何根据来电状态调用不同方法来展示来电界面,以及响铃的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2,来电界面以及响铃

来电时,除了有来电界面,还有响铃。

2.1 来电界面

在前面已经论述过,也是调用InCallController的onCallAdded方法启动来电界面,

大体流程和去电界面相同。不同的是CallList之后的onCallAdded方法,调用流程图如下,


CallList之后的onCallAdded方法如下,

public void onCallAdded(android.telecom.Call telecommCall) {
      Trace.beginSection("onCallAdded");
      Call call = new Call(telecommCall);
      Log.d(this, "onCallAdded: callState=" + call.getState());
      if (call.getState() == Call.State.INCOMING ||
             call.getState() == Call.State.CALL_WAITING) {
         onIncoming(call, call.getCannedSmsResponses());
      } else {
         onUpdate(call);
      }
      Trace.endSection();
}

根据call的状态判断是否是来电,如果是来电就调用onIncoming方法,否则就调用onUpdate方法, onIncoming方法如下,

for (Listener listener : mListeners) {
       listener.onIncomingCall(call);
}

onIncomingCall方法如下,

public void onIncomingCall(Call call) {
      InCallState newState = startOrFinishUi(InCallState.INCOMING);
      InCallState oldState = mInCallState;

      Log.i(this, "Phone switching state: " + oldState + " -> " + newState);
      mInCallState = newState;

      for (IncomingCallListener listener : mIncomingCallListeners) {
          listener.onIncomingCall(oldState, mInCallState, call);
      }

      if (InCallServiceImpl.isDsdaEnabled() && (mInCallActivity != null)) {
          mInCallActivity.updateDsdaTab();
      }
}

首先会调用startOrFinishUi方法启动界面,

然后调用InCallActivity界面的各个view的Presenter 的onIncomingCall方法,展现来电界面。

和前面的监听器完全相同, mIncomingCallListeners保存着view注册的监听器,

private final List<IncomingCallListener> mIncomingCallListeners = new CopyOnWriteArrayList<>();

IncomingCallListener也是InCallPresenter的内部接口。通过调用addIncomingCallListener方法进行注册,

public void addIncomingCallListener(IncomingCallListener listener) {
     Preconditions.checkNotNull(listener);
     mIncomingCallListeners.add(listener);
}

在IncallUI结构中,

InCallPresenter控制着InCallActivity界面的显示;

AnswerPresenter控制着AnswerFragment的显示,是InCallActivity界面的一部分;

VideoCallPresenter控制着VideoCallFragment的显示,是InCallActivity界面的一部分;

CallCardPresenter控制着CallCardFragment的显示,是InCallActivity界面的一部分;

CallButtonPresenter控制着CallButtonFragment的显示,是InCallActivity界面的一部分;

这些Presenter一般会实现InCallPresenter的IncomingCallListener监听器。

CallCardPresenter的onIncomingCall方法如下,

public void onIncomingCall(InCallState oldState, InCallState newState, Call call) {
     // same logic should happen as with onStateChange()
     onStateChange(oldState, newState, CallList.getInstance());
}

onStateChange方法会根据当前的call状态控制view的显示。其他Presenter的过程几乎一样,在此就不论述了。

2.2 响铃分析

在来电流程中论述过, 调用Ringer的onCallAdded方法响铃。响铃过程都是在services telecom中,并没有跨进程的调用。

调用流程图如下,


Ringer的onCallAdded方法如下,

public void onCallAdded(final Call call) {
     if (call.isIncoming() && call.getState() == CallState.RINGING) {
         if (mRingingCalls.contains(call)) {
             Log.wtf(this, "New ringing call is already in list of unanswered calls");
         }
         mRingingCalls.add(call);
         updateRinging(call);
     }
}

startRingingOrCallWaiting方法主要逻辑如下,

1,获取响铃歌曲,调用AsyncRingtonePlayer的play方法响铃,

mRingtonePlayer.play(foregroundCall.getRingtone());

2,调用Vibrator的vibrate方法振动,

mVibrator.vibrate(VIBRATION_PATTERN, VIBRATION_PATTERN_REPEAT,
 VIBRATION_ATTRIBUTES);

AsyncRingtonePlayer的play方法如下,

void play(Uri ringtone) {
     Log.d(this, "Posting play.");
     postMessage(EVENT_PLAY, true /* shouldCreateHandler */, ringtone);
}

新建一子线程,子线程中的handleMessage方法对EVENT_PLAY消息处理如下,

handlePlay((Uri) msg.obj);

handlePlay主要逻辑如下,

1,根据ringtoneUri构造Ringtone对象,

if (mRingtone == null) {
    mRingtone = getRingtone(ringtoneUri);

2,调用handleRepeat方法发送EVENT_REPEAT消息并调用Ringtone的play接口响铃,

handleRepeat();

handleRepeat方法如下,

if (mRingtone.isPlaying()) {
    Log.d(this, "Ringtone already playing.");
} else {
    mRingtone.play();//响铃
    Log.i(this, "Repeat ringtone.");
}
// Repost event to restart ringer in {@link RESTART_RINGER_MILLIS}.
synchronized(this) {
  if (!mHandler.hasMessages(EVENT_REPEAT)) {//发送EVENT_REPEAT消息
     mHandler.sendEmptyMessageDelayed(EVENT_REPEAT, RESTART_RINGER_MILLIS);
  }
}

handleMessage方法对EVENT_REPEAT消息处理如下,

case EVENT_REPEAT:
    handleRepeat();//重复响铃
    break;

当然停止响铃是调用AsyncRingtonePlayer的stop方法,和play方法几乎完全相同,在此就不论述了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值