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


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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 家里装修把暖气管道打破了怎么办 冷水管与热水管接错了怎么办 磨砂皮的鞋子打湿变硬了怎么办 等离子淡化热处理层渗不够厚怎么办 寄快递快递公司把东西弄坏了怎么办 寄美国的快递客人拒绝清关怎么办 国际e邮宝几天没物流信息了怎么办 石家庄小学网上报名填错了怎么办 去医院看病不知道挂什么科怎么办 深水井深水泵埋了2米怎么办 请问我捡的手机不是我的指纹怎么办 宝宝把塑料子弹塞到了鼻子里怎么办 坐便池上面的小孔不出水怎么办 还没离职已经找好工作怎么办 因火车晚点而耽误下趟火车怎么办 在广州坐的士丢了东西怎么办 找兼职的话他要求交押金怎么办 08vip不给提现了怎么办 点击订阅号所收到内容字太大怎么办 我的小叶栀子花老是黄叶该怎么办? 联币金融倒闭了我投资的钱怎么办 新单位交养老保险不接收档案怎么办 高铁发车十小时没赶上怎么办 饿了么被阿里收购员工怎么办? 爱疯4s密码忘了怎么办 研究生论文盲审一直不出结果怎么办 查重报告有疑似剽窃观点怎么办 成绩考的不好怎么办读技校有用吗 孩子大学挂科太多家长应该怎么办 中专升大专的入学考没考上怎么办 小孩摔跤额头出了个包怎么办 小孩摔跤后脑勺出了个包怎么办 结婚后疏于关心老婆寒心了怎么办 江苏取消小高考高二学生怎么办 上海学而思家长陪读听不懂怎么办 高考报名的电话号码填错了怎么办 高考报名用的电话号码变换了怎么办 弟媳妇一个月就大闹一次怎么办 丈夫出轨我亲弟媳妇我怎么办 被山西博大泌尿医院坑了怎么办 家长反应孩子学校受欺负老师怎么办