所以,GsmCallTracker是Phone对象和RILJ之间通话相关事务的接力者。
synchronized Connection dial (){} void acceptCall () throws CallStateException {} void rejectCall () throws CallStateException {} void switchWaitingOrHoldingAndActive() throws CallStateException {} void clearDisconnected() {} boolean canDial() {} private void updatePhoneState() {} void hangup (GsmConnection conn) throws CallStateException {} void hangup (GsmCall call) throws CallStateException {}从这些方法可以看出,GsmCallTracker的作用主要包括两方面:
public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { mCT = new GsmCallTracker(this); }然后看GsmCallTracker的构造方法:
GsmCallTracker (GSMPhone phone) { this.mPhone = phone; //拿到RILJ mCi = phone.mCi; //监听通话、Radio状态 mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null); mCi.registerForOn(this, EVENT_RADIO_AVAILABLE, null); mCi.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null); }
我们看到,在构造函数中GsmCallTracker拿到了RILJ对象,当需要对当前通话连接操作时,就会直接调用RILJ去实现。同时在构造方法中又注册了通话状态和Radio的状态监听器,用于向其他对象通知当前Radio状态的改变。
synchronized Connection dial (String dialString, int clirMode, UUSInfo uusInfo) throws CallStateException { //清除链接 clearDisconnected(); //条件判断 if (!canDial()) { throw new CallStateException("cannot dial in current state"); } //是否需要切换通话 if (mForegroundCall.getState() == GsmCall.State.ACTIVE) { switchWaitingOrHoldingAndActive(); fakeHoldForegroundBeforeDial(); } //准备新的通话连接 mPendingMO = new GsmConnection(mPhone.getContext(), checkForTestEmergencyNumber(dialString), this, mForegroundCall); mHangupPendingMO = false; if (mPendingMO.mAddress == null || mPendingMO.mAddress.length() == 0 || mPendingMO.mAddress.indexOf(PhoneNumberUtils.WILD) >= 0 ) { mPendingMO.mCause = Connection.DisconnectCause.INVALID_NUMBER; pollCallsWhenSafe(); } else { //设置非静音模式 setMute(false); //向RIL层发送拨号请求 mCi.dial(mPendingMO.mAddress, clirMode, uusInfo, obtainCompleteMessage()); } //更新通话状态 updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); return mPendingMO; }接听动作:
void acceptCall () throws CallStateException { if (mRingingCall.getState() == GsmCall.State.INCOMING) { //向RIL层发送接听的请求 setMute(false); mCi.acceptCall(obtainCompleteMessage()); } else if (mRingingCall.getState() == GsmCall.State.WAITING) { //切换通话 setMute(false); switchWaitingOrHoldingAndActive(); } else { throw new CallStateException("phone not ringing"); } }拒接动作:
void rejectCall () throws CallStateException { if (mRingingCall.getState().isRinging()) { //拒接 mCi.rejectCall(obtainCompleteMessage()); } else { throw new CallStateException("phone not ringing"); } }
以上动作最后都要调用mCi对象来处理,这个对象就是RILJ,他会把请求发送给RIL层来处理。
private void updatePhoneState() { PhoneConstants.State oldState = mState; //获取当前状态 if (mRingingCall.isRinging()) { mState = PhoneConstants.State.RINGING; } else if (mPendingMO != null || !(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) { mState = PhoneConstants.State.OFFHOOK; } else { mState = PhoneConstants.State.IDLE; } if (mState == PhoneConstants.State.IDLE && oldState != mState) { mVoiceCallEndedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); } else if (oldState == PhoneConstants.State.IDLE && oldState != mState) { mVoiceCallStartedRegistrants.notifyRegistrants ( new AsyncResult(null, null, null)); } if (mState != oldState) { //通知GSMPhone进行状态广播 mPhone.notifyPhoneStateChanged(); } }
在这个过程中,最后要通过GSMPhone的notifyPhoneStateChanged()方法来通知其他对象,具体的通知过程将会在接下来的TelephonyRegistry中介绍。
而GsmCallTracker的更新机制核心任务就是维护这些不同线路,包括对各个线路的操作(比如接听、挂断、保持),以及各个线路状态的维护。为了达到这个目的,GsmCallTracker内部创建了两个非常重要的对象:GsmConnection和GsmCall。
GsmConnection mConnections[] = new GsmConnection[MAX_CONNECTIONS];
从这里可以看到,最多可以同时存在MAX_CONNECTIONS,也就是7条线路。
而GsmCall要做的主要功能就是维护不同GsmCall的状态。
mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);这个监听器监听的是RIL层通话的状态,当有新的状态到来时(比如新的来电),就会通过EVENT_CALL_STATE_CHANGE消息通知到GsmCallTracker,然后就会在handleMessage中进行处理:
public void handleMessage (Message msg) { AsyncResult ar; switch (msg.what) { case EVENT_REPOLL_AFTER_DELAY: case EVENT_CALL_STATE_CHANGE: //得到RIL层消息,通话状态有变 pollCallsWhenSafe(); break; } }然后就会调用pollCallsWhenSafe()方法去获取当前最新的通话状态,我们暂时不去分析pollCallsWhenSafe的流程,先来看看其他两个监听器的流程。
mCi.registerForOn(this, EVENT_RADIO_AVAILABLE, null);当Radio的状态上来后,就会在handleMessage中处理:
public void handleMessage (Message msg) { AsyncResult ar; switch (msg.what) { case EVENT_RADIO_AVAILABLE: handleRadioAvailable(); break; } }然后进入handleRadioAvailable()中处理:
protected void handleRadioAvailable() { pollCallsWhenSafe(); }到这里我们发现,接下来的流程和第一个监听器的流程相同。
mCi.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);监听的是Radio的不可用状态,当监听的消息上来后,在handleMessage中处理:
public void handleMessage (Message msg) { AsyncResult ar; switch (msg.what) { case EVENT_RADIO_NOT_AVAILABLE: handleRadioNotAvailable(); break; } }然后会进入handleRadioNotAvailable()的流程:
private void handleRadioNotAvailable() { pollCallsWhenSafe(); }接下来又是pollCallsWhenSafe()的操作,到这里我们发现,在GsmCallTracker构造函数中注册的三个监听器,无论哪一个被触发都会进入pollCallsWhenSafe的流程,接下来的分析我们将会看到,GsmCallTracker将会主动请求最新的通话状态,然后根据当前状态去更新GsmConnection和GsmCall对象。
@CallTracker.java protected void pollCallsWhenSafe() { mNeedsPoll = true; if (checkNoOperationsPending()) { //通过RILJ获取当前的最新通话状态 mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); mCi.getCurrentCalls(mLastRelevantPoll); } }这里看到,在pollCallsWhenSafe中通过RILJ(也就是mCi)去向Modem查询当前的通话状态,并注册了回调的消息EVENT_POLL_CALLS_RESULT,当拿到Modem返回值后,就会再次通过handleMessage()来处理最新的通话状态:
public void handleMessage (Message msg) { AsyncResult ar; switch (msg.what) { case EVENT_POLL_CALLS_RESULT: //拿到最新通话状态 ar = (AsyncResult)msg.obj; if (msg == mLastRelevantPoll) { mNeedsPoll = false; mLastRelevantPoll = null; handlePollCalls((AsyncResult)msg.obj); } break; } }然后将数据拿到后,交由handlePollCalls()来处理,在这个方法里,就需要将当前的Modem通话状态数据进行解析,更新GsmConnection和GsmCall对象:
protected synchronized void handlePollCalls(AsyncResult ar) { List polledCalls; Connection newRinging = null; //or waiting boolean hasNonHangupStateChanged = false; // Any change besides boolean hasAnyCallDisconnected = false; boolean needsPollDelay = false; boolean unknownConnectionAppeared = false; for (int i = 0, curDC = 0, dcSize = polledCalls.size() ; i < mConnections.length; i++) { //拿到当前GsmCallTracker中的通话线路 GsmConnection conn = mConnections[i]; DriverCall dc = null; if (curDC < dcSize) { //拿到当前的Modem中的通话线路状态 dc = (DriverCall) polledCalls.get(curDC); if (dc.index == i+1) { curDC++; } else { dc = null; } } if (conn == null && dc != null) { if (mPendingMO != null && mPendingMO.compareTo(dc)) { //mConnections中没有当前线路,而且当前线路是匹配mPendingMO的,说明是最新发起的呼出线路 mConnections[i] = mPendingMO; mPendingMO.mIndex = i; mPendingMO.update(dc); mPendingMO = null; if (mHangupPendingMO) { //是否在呼出之后用户立刻挂断了线路 mHangupPendingMO = false; try { //挂断这通线路 hangup(mConnections[i]); } catch (CallStateException ex) { } return; } } else { //Modem中有该线路,而GsmConnection中没有该线路,说明有新的通话来临,需要创建新的线路连接 mConnections[i] = new GsmConnection(mPhone.getContext(), dc, this, i); if (mConnections[i].getCall() == mRingingCall) { //新来电 newRinging = mConnections[i]; } else { //异常通话线路 if (dc.state != DriverCall.State.ALERTING && dc.state != DriverCall.State.DIALING) { mConnections[i].onConnectedInOrOut(); if (dc.state == DriverCall.State.HOLDING) { mConnections[i].onStartedHolding(); } } unknownConnectionAppeared = true; } } hasNonHangupStateChanged = true; } else if (conn != null && dc == null) { //Modem中已经没有当前的链接,说明该线路已经被挂断,需要从mConnections中删除(置为null) mDroppedDuringPoll.add(conn); mConnections[i] = null; } else if (conn != null && dc != null && !conn.compareTo(dc)) { //Modem中的链接信息与当前的不匹配,可能发生了掉话或者新的通话 mDroppedDuringPoll.add(conn); //需要创建新的链接 mConnections[i] = new GsmConnection (mPhone.getContext(), dc, this, i); if (mConnections[i].getCall() == mRingingCall) { newRinging = mConnections[i]; } hasNonHangupStateChanged = true; } else if (conn != null && dc != null) { //当前线路与Modem匹配,更新当前的链路信息 boolean changed; changed = conn.update(dc); hasNonHangupStateChanged = hasNonHangupStateChanged || changed; } } //异常 if (mPendingMO != null) { mDroppedDuringPoll.add(mPendingMO); mPendingMO = null; mHangupPendingMO = false; } if (newRinging != null) { //新的来电,需要通知registerForNewRingingConnection的监听者 mPhone.notifyNewRingingConnection(newRinging); } //对于挂断的链接,需要标明挂断的原因 for (int i = mDroppedDuringPoll.size() - 1; i >= 0 ; i--) { GsmConnection conn = mDroppedDuringPoll.get(i); if (conn.isIncoming() && conn.getConnectTime() == 0) { // Missed or rejected call Connection.DisconnectCause cause; if (conn.mCause == Connection.DisconnectCause.LOCAL) { //被拒掉 cause = Connection.DisconnectCause.INCOMING_REJECTED; } else { //未接来电 cause = Connection.DisconnectCause.INCOMING_MISSED; } mDroppedDuringPoll.remove(i); hasAnyCallDisconnected |= conn.onDisconnect(cause); } else if (conn.mCause == Connection.DisconnectCause.LOCAL || conn.mCause == Connection.DisconnectCause.INVALID_NUMBER) { mDroppedDuringPoll.remove(i); hasAnyCallDisconnected |= conn.onDisconnect(conn.mCause); } } if (mDroppedDuringPoll.size() > 0) { mCi.getLastCallFailCause( obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE)); } if (needsPollDelay) { pollCallsAfterDelay(); } if (newRinging != null || hasNonHangupStateChanged || hasAnyCallDisconnected) { internalClearDisconnected(); } //更新通话状态 updatePhoneState(); if (unknownConnectionAppeared) { mPhone.notifyUnknownConnection(); } if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) { mPhone.notifyPreciseCallStateChanged(); } }上面的更新过程中,用从Modem获取到的通话线路信息与mConnections中存储的信息做对比,从而更新mConnections中线路的状态,比如:
private void updatePhoneState() { PhoneConstants.State oldState = mState; if (mRingingCall.isRinging()) { //响铃状态 mState = PhoneConstants.State.RINGING; } else if (mPendingMO != null || !(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) { //通话状态 mState = PhoneConstants.State.OFFHOOK; } else { //待机状态 mState = PhoneConstants.State.IDLE; } if (mState == PhoneConstants.State.IDLE && oldState != mState) { mVoiceCallEndedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); } else if (oldState == PhoneConstants.State.IDLE && oldState != mState) { mVoiceCallStartedRegistrants.notifyRegistrants ( new AsyncResult(null, null, null)); } if (mState != oldState) { //状态有更新,通过Phone对象发送给监听者 mPhone.notifyPhoneStateChanged(); } }其实通知的过程就是通过mPhone的notifyPhoneStateChanged()方法来实现,这里的mPhone,也就是GSMPhone对象,会把该广播发送给监听者们。