handlePollCalls方法详解

来源:互联网 发布:mac 命令行下载git 编辑:程序博客网 时间:2024/06/16 03:11

当调用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对象的。


http://blog.csdn.net/linyongan


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。

5 0
原创粉丝点击