handlePollCalls方法详解
来源:互联网 发布:mac 命令行下载git 编辑:程序博客网 时间:2024/06/16 05:33
当调用getCurrentCalls方法查询Call List当前所有的通话连接,查询的结果是交给handlePollCalls来处理的。handlePollCalls方法比较长,我们把它分解成几部分来分析:
@Overrideprotected void handlePollCalls(AsyncResult ar) { 1.初始化操作,获取Call List。 2.更新通话的相关信息。 2.1 获取conn对象和dc对象。 2.2 通话状态变化。 2.2.1 出现新的通话连接。 2.2.2 通话连接断开。 2.2.3 通话状态发生变化。 3.收尾处理,根据最新的通话状态发出消息。 4.更新手机的状态。}
1.初始化操作,获取Call List。
//声明Call List对象,它将保存RIL查询出的当前Call对象列表 List polledCalls; //RIL返回的消息无异常,即getCurrentCalls查询当前Call List成功 if (ar.exception == null) { //将RIL返回的消息结果对象强制转换成List对象 polledCalls = (List)ar.result; } else if (isCommandExceptionRadioNotAvailable(ar.exception)) { // just a dummy empty ArrayList to cause the loop // to hang up all the calls polledCalls = new ArrayList(); } else { // Radio probably wasn't ready--try again in a bit // But don't keep polling if the channel is closed pollCallsAfterDelay(); return; } Connection newRinging = null; //创建通话连接对象 Connection newUnknown = null; //除了通话连接断开的其他任何通话状态改变的标志 boolean hasNonHangupStateChanged = false; // Any change besides // a dropped connection boolean hasAnyCallDisconnected = false; //是否需要延迟查询Call List的标志 boolean needsPollDelay = false; //是否出现未知通话连接的标志 boolean unknownConnectionAppeared = false;
上面代码中把RILJ发给CDMACallTracker的Handler消息中的result通过强制转换成List对象,然后赋值给polledCalls对象的。
2.更新通话的相关信息。
CDMACallTracker通过Handler消息获取最新的DriverCall List对象列表,然后遍历mConnections保存的通话连接对象列表,通过DriverCall List中对应的DriverCall对象更新CDMACallTracker中的通话相关信息。
2.1 获取conn对象和dc对象。
for (int i = 0, curDC = 0, dcSize = polledCalls.size() ; i < mConnections.length; i++) { //依次获取connections中的对象 CdmaConnection conn = mConnections[i]; DriverCall dc = null; // polledCall list is sparse if (curDC < dcSize) { dc = (DriverCall) polledCalls.get(curDC); //DriverCall对象与connections中对象的关系,通过下标对应 if (dc.index == i+1) { //conn与dc对象匹配成功,下次循环则获取下一个dc对象 curDC++; } else { //conn与dc对象未匹配成功,则不取出dc对象 dc = null; } }if (DBG_POLL) log("poll: conn[i=" + i + "]=" + conn+", dc=" + dc);
根据下标i的值获取mConnections数组中的CdmaConnection对象conn,并且通过curDC的值从polledCalls列表中获取DriverCall对象dc,这两个对象通过dc.index == i+1完成匹配。(因为index 从1开始,而i从0开始的)
2.2 通话状态变化。
2.2.1 出现新的通话连接。
//conn代表旧的通话连接的基本信息,dc代表新的。出现新的通话连接if (conn == null && dc != null) { //主动发起拨号请求后,第一次查询到Call List后,进入这里 // Connection appeared in CLCC response that we don't know about if (mPendingMO != null && mPendingMO.compareTo(dc)) { if (DBG_POLL) log("poll: pendingMO=" + mPendingMO); // It's our pending mobile originating call mConnections[i] = mPendingMO; //把i的值赋值给index mPendingMO.mIndex = i; mPendingMO.update(dc); mPendingMO = null; // Someone has already asked to hangup this call if (mHangupPendingMO) { mHangupPendingMO = false; // Re-start Ecm timer when an uncompleted emergency call ends if (mIsEcmTimerCanceled) { handleEcmTimer(CDMAPhone.RESTART_ECM_TIMER); } try { if (Phone.DEBUG_PHONE) log( "poll: hangupPendingMO, hangup conn " + i); hangup(mConnections[i]); } catch (CallStateException ex) { Rlog.e(LOG_TAG, "unexpected error on hangup"); } // Do not continue processing this poll // Wait for hangup and repoll return; } } else {//接收到新来电 if (Phone.DEBUG_PHONE) { log("pendingMo=" + mPendingMO + ", dc=" + dc); } //通过dc创建新的Connection对象 mConnections[i] = new CdmaConnection(mPhone.getContext(), dc, this, i); Connection hoConnection = getHoConnection(dc); if (hoConnection != null) { // Single Radio Voice Call Continuity (SRVCC) completed mConnections[i].migrateFrom(hoConnection); // Updating connect time for silent redial cases (ex: Calls are transferred // from DIALING/ALERTING/INCOMING/WAITING to ACTIVE) if (hoConnection.mPreHandoverState != CdmaCall.State.ACTIVE && hoConnection.mPreHandoverState != CdmaCall.State.HOLDING) { mConnections[i].onConnectedInOrOut(); } mHandoverConnections.remove(hoConnection); mPhone.notifyHandoverStateChanged(mConnections[i]); } else { // find if the MT call is a new ring or unknown connection //把mConnections对象赋值给newRinging newRinging = checkMtFindNewRinging(dc,i); if (newRinging == null) { unknownConnectionAppeared = true; newUnknown = mConnections[i]; } } checkAndEnableDataCallAfterEmergencyCallDropped(); } hasNonHangupStateChanged = true;}
2.2.2 通话连接断开。
else if (conn != null && dc == null) { //通话连接断开 // This case means the RIL has no more active call anymore and // we need to clean up the foregroundCall and ringingCall. // Loop through foreground call connections as // it contains the known logical connections. int count = mForegroundCall.mConnections.size(); for (int n = 0; n < count; n++) { if (Phone.DEBUG_PHONE) log("adding fgCall cn " + n + " to droppedDuringPoll"); CdmaConnection cn = (CdmaConnection)mForegroundCall.mConnections.get(n); //把旧的conn对象添加到删除通话连接列表中 mDroppedDuringPoll.add(cn); } count = mRingingCall.mConnections.size(); // Loop through ringing call connections as // it may contain the known logical connections. for (int n = 0; n < count; n++) { if (Phone.DEBUG_PHONE) log("adding rgCall cn " + n + " to droppedDuringPoll"); CdmaConnection cn = (CdmaConnection)mRingingCall.mConnections.get(n); mDroppedDuringPoll.add(cn); } mForegroundCall.setGeneric(false); mRingingCall.setGeneric(false); // Re-start Ecm timer when the connected emergency call ends if (mIsEcmTimerCanceled) { handleEcmTimer(CDMAPhone.RESTART_ECM_TIMER); } // If emergency call is not going through while dialing checkAndEnableDataCallAfterEmergencyCallDropped(); // Dropped connections are removed from the CallTracker // list but kept in the Call list //设置旧的通话连接为null mConnections[i] = null;}
2.2.3 通话状态发生变化。
else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */ //通话状态发生变化 // Call collision case if (conn.isIncoming() != dc.isMT) { if (dc.isMT == true){ // Mt call takes precedence than Mo,drops Mo mDroppedDuringPoll.add(conn); // find if the MT call is a new ring or unknown connection newRinging = checkMtFindNewRinging(dc,i); if (newRinging == null) { unknownConnectionAppeared = true; newUnknown = conn; } checkAndEnableDataCallAfterEmergencyCallDropped(); } else { // Call info stored in conn is not consistent with the call info from dc. // We should follow the rule of MT calls taking precedence over MO calls // when there is conflict, so here we drop the call info from dc and // continue to use the call info from conn, and only take a log. Rlog.e(LOG_TAG,"Error in RIL, Phantom call appeared " + dc); } } else { boolean changed; //通过dc对象更新conn对象,返回通话状态是否已经更新的标志 changed = conn.update(dc); hasNonHangupStateChanged = hasNonHangupStateChanged || changed; }}
3.收尾处理,根据最新的通话状态发出消息。
//如果接收到来电请求if (newRinging != null) { mPhone.notifyNewRingingConnection(newRinging);}// clear the "local hangup" and "missed/rejected call"// cases from the "dropped during poll" list// These cases need no "last call fail" reasonfor (int i = mDroppedDuringPoll.size() - 1; i >= 0 ; i--) { CdmaConnection conn = mDroppedDuringPoll.get(i); if (conn.isIncoming() && conn.getConnectTime() == 0) { // Missed or rejected call int cause; if (conn.mCause == DisconnectCause.LOCAL) { cause = DisconnectCause.INCOMING_REJECTED; } else { cause = DisconnectCause.INCOMING_MISSED; } if (Phone.DEBUG_PHONE) { log("missed/rejected call, conn.cause=" + conn.mCause); log("setting cause to " + cause); } mDroppedDuringPoll.remove(i); hasAnyCallDisconnected |= conn.onDisconnect(cause); } else if (conn.mCause == DisconnectCause.LOCAL || conn.mCause == DisconnectCause.INVALID_NUMBER) { mDroppedDuringPoll.remove(i); hasAnyCallDisconnected |= conn.onDisconnect(conn.mCause); }}/* Disconnect any pending Handover connections */for (Iterator<Connection> it = mHandoverConnections.iterator(); it.hasNext();) { Connection hoConnection = it.next(); log("handlePollCalls - disconnect hoConn= " + hoConnection); ((ImsPhoneConnection)hoConnection).onDisconnect(DisconnectCause.NOT_VALID); it.remove();}//(mDroppedDuringPoll中仍然存在通话连接消失的对象,也就是还有远程断开通话连接对象// Any non-local disconnects: determine causeif (mDroppedDuringPoll.size() > 0) { //向RIL层查询最后一次通话连接断开的原因 mCi.getLastCallFailCause( obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE));}if (needsPollDelay) { pollCallsAfterDelay();}// Cases when we can no longer keep disconnected Connection's// with their previous calls// 1) the phone has started to ring// 2) A Call/Connection object has changed state...// we may have switched or held or answered (but not hung up)if (newRinging != null || hasNonHangupStateChanged || hasAnyCallDisconnected) { internalClearDisconnected();}//同步更新Phone.State手机状态updatePhoneState();//出现未知的通话连接if (unknownConnectionAppeared) { mPhone.notifyUnknownConnection(newUnknown);}//非通话连接断开的情况或者是接收到新的来电请求if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) { mPhone.notifyPreciseCallStateChanged();}
4.更新手机的状态。
private void updatePhoneState() { //首先记录之前的状态 PhoneConstants.State oldState = mState; //根据三个mState状态,更新Phone.State手机状态 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 (Phone.DEBUG_PHONE) { log("update phone state, old=" + oldState + " new="+ mState); } //手机状态已经更新,通过Phone对象发出状态变化通知 if (mState != oldState) { mPhone.notifyPhoneStateChanged(); }}
通过Call对象获取其State状态从而更新Phone.State状态,它们之间的状态是保持同步的。
Call.State和Phone.State之间的状态转换过程如下:
可以看到Call.State共有9个状态,Phone.State共有3个状态;Call.State中,除去IDLE和INCOMING之外的7个状态,提炼成Phone.State的OFFHOOK。
- handlePollCalls方法详解
- handlePollCalls方法详解
- 方法详解
- Recordset对象方法详解
- OpenSchema 方法详解
- OpenSolaris安装方法详解
- OpenSchema 方法详解
- JAVA Calendar方法详解
- window.prompt()方法详解
- Python 字符串方法详解
- locate方法详解
- showModalDialog()方法使用详解
- showModalDialog()方法使用详解
- showModalDialog()方法使用详解
- finalize( ) 方法详解
- DataReader方法详解
- 调用Qvod 方法详解
- EntityManager API方法详解
- C++多态
- oj平台上标准输入输出
- 使用JavaWeb项目的路径参数问题总结
- C++中string的用法 string字符串的使用方法
- android项目源码大全
- handlePollCalls方法详解
- BigDecimal.setScale 处理java小数点
- 二 Schema简介
- iOS9适配必看指南
- js实现图片旋转
- 数据库优化之利用索引、避免全表扫描
- fcntl使用及FD_CLOEXEC详解
- Test:开通博客
- css3新属性placeholder兼容ie7/ie8