voice call relevant

 

每次收到底层上报的呼叫状态变化时(UNSOL_RESPONSE_CALL_STATE_CHANGED ),都会去查询变化了的具体内容给modem发的信息是RIL_REQUEST_GET_CALL_LIST.handlePollCalls是用来处理查询之后的结果,分析如下:

 

handlePollCalls(AsyncResult ar) 
        List polledCalls;
	log("****handlepollcalls.....");

        if (ar.exception == null) {
            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(bIsVoice);
            return;
        }

        Connection newRinging = null; //or waiting
        boolean hasNonHangupStateChanged = false;   // Any change besides
                                                    // a dropped connection
        boolean needsPollDelay = false;
        boolean unknownConnectionAppeared = false;
	boolean isSeparateCallConnection = false;

        for (int i = 0, curDC = 0, dcSize = polledCalls.size()
                ; i < connections.length; i++) {
            GsmConnection conn = connections[i];//一个个查询gsmcalltracker里面的连接
            DriverCall dc = null;

            // polledCall list is sparse
            if (curDC < dcSize) {
                dc = (DriverCall) polledCalls.get(curDC);

                if (dc.index == i+1) {
                    curDC++;
                } else if(isSeparateCallConnection) {
		    curDC++;
		    isSeparateCallConnection = false;
		} else {
                    dc = null;
                }
            }

            if (DBG_POLL) log("poll: conn[i=" + i + "]=" +
                    conn+", dc=" + dc);
	    log("****poll: conn[i=" + i + "]=" +
                    conn+", dc=" + dc);

            if (conn == null && dc != null) {//进来一个新的呼叫
                // Connection appeared in CLCC response that we don't know about
                if (pendingMO != null && pendingMO.compareTo(dc)) {

                    if (DBG_POLL) log("poll: pendingMO=" + pendingMO);

                    // It's our pending mobile originating call
                    connections[i] = pendingMO;
                    pendingMO.index = i;
                    pendingMO.update(dc);
                    pendingMO = null;

                    // Someone has already asked to hangup this call
                    if (hangupPendingMO) {
                        hangupPendingMO = false;
                        try {
                            if (Phone.DEBUG_PHONE) log(
                                    "poll: hangupPendingMO, hangup conn " + i);
                            hangup(connections[i]);
                        } catch (CallStateException ex) {
                            Log.e(LOG_TAG, "unexpected error on hangup");
                        }

                        // Do not continue processing this poll
                        // Wait for hangup and repoll
                        return;
                    }
                } else {
                    connections[i] = new GsmConnection(phone.getContext(), dc, this, i);
		    log("****setting connection");
                    // it's a ringing call
                    if (connections[i].getCall() == ringingCall) {
			log("****new ringing connection");
                        newRinging = connections[i];
                    } else {
                        // Something strange happened: a call appeared
                        // which is neither a ringing call or one we created.
                        // Either we've crashed and re-attached to an existing
                        // call, or something else (eg, SIM) initiated the call.

                        Log.i(LOG_TAG,"Phantom call appeared " + dc);

                        // If it's a connected call, set the connect time so that
                        // it's non-zero.  It may not be accurate, but at least
                        // it won't appear as a Missed Call.
                        if (dc.state != DriverCall.State.ALERTING
                                && dc.state != DriverCall.State.DIALING) {
                            connections[i].connectTime = System.currentTimeMillis();
                        }

                        unknownConnectionAppeared = true;
                    }
                }
                <span style="color:#000099;"><strong>hasNonHangupStateChanged = true;</strong></span>
            } else if (conn != null && dc == null) {//modem呼叫断开时走这
                // Connection missing in CLCC response that we were
                // tracking.
		log("****no connection let's drop");
		if(conn.isVoice != bIsVoice) {
		    log("Different call came 1");
		    continue;
		}
                droppedDuringPoll.add(conn);
                // Dropped connections are removed from the CallTracker
                // list but kept in the GsmCall list
                connections[i] = null;
            } else if (conn != null && dc != null && !conn.compareTo(dc)) {
                // Connection in CLCC response does not match what
                // we were tracking. Assume dropped call and new call
		log("****connection not matching let's drop");
		if(conn.isVoice != dc.isVoice) {
		    log("Different call came 2");
		    curDC--;
		    isSeparateCallConnection = true;
		    continue;
		}
		    
                droppedDuringPoll.add(conn);
                connections[i] = new GsmConnection (phone.getContext(), dc, this, i);

                if (connections[i].getCall() == ringingCall) {
                    newRinging = connections[i];
                } // else something strange happened
                hasNonHangupStateChanged = true;
            } else if (conn != null && dc != null) { /* implicit conn.compareTo(dc)有连接且查询到的call也存在,正常外呼走这 */
                boolean changed;
		log("****conn dc both has value");
                changed = conn.update(dc);   //尝试更新连接,如果返回的值位changed,则表明查询前后call的状态有变化
                hasNonHangupStateChanged = hasNonHangupStateChanged || changed;
		log("****hasNonHangupStateChanged = "+hasNonHangupStateChanged);
            }

            if (REPEAT_POLLING) {
                if (dc != null) {
                    // FIXME with RIL, we should not need this anymore
                    if ((dc.state == DriverCall.State.DIALING
                            /*&& cm.getOption(cm.OPTION_POLL_DIALING)*/)
                        || (dc.state == DriverCall.State.ALERTING
                            /*&& cm.getOption(cm.OPTION_POLL_ALERTING)*/)
                        || (dc.state == DriverCall.State.INCOMING
                            /*&& cm.getOption(cm.OPTION_POLL_INCOMING)*/)
                        || (dc.state == DriverCall.State.WAITING
                            /*&& cm.getOption(cm.OPTION_POLL_WAITING)*/)
                    ) {
                        // Sometimes there's no unsolicited notification
                        // for state transitions
                        bIsVoice = dc.isVoice;
                        needsPollDelay = true;
                    }
                }
            }
        }

        // This is the first poll after an ATD.
        // We expect the pending call to appear in the list
        // If it does not, we land here
        if (pendingMO != null) {
            Log.d(LOG_TAG,"Pending MO dropped before poll fg state:"
                            + foregroundCall.getState());

            droppedDuringPoll.add(pendingMO);
            pendingMO = null;
            hangupPendingMO = false;
        }

        if (newRinging != null) {//如果是新进来的呼叫
            phone.notifyNewRingingConnection(newRinging);
        }

        /* clear the "local hangup" and "missed/rejected call"
         cases from the "dropped during poll" list
         These cases need no "last call fail" reason .清除掉一些因本地挂机,以及网络拒绝的原因相关的连接
       */
        
        for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) { //本地原因引起的挂断</span>
            GsmConnection conn = droppedDuringPoll.get(i);
	    log("****welcome to drop call");

            if (conn.isIncoming() && conn.getConnectTime() == 0) {
                // Missed or rejected call
                Connection.DisconnectCause cause;
                if (conn.cause == Connection.DisconnectCause.LOCAL) {//进来的call不接听
                    cause = Connection.DisconnectCause.INCOMING_REJECTED;
                } else {
                    cause = Connection.DisconnectCause.INCOMING_MISSED;
                }

                if (Phone.DEBUG_PHONE) {
                    log("missed/rejected call, conn.cause=" + conn.cause);
                    log("setting cause to " + cause);
                }
                droppedDuringPoll.remove(i);
                conn.onDisconnect(cause);
            } else if (conn.cause == Connection.DisconnectCause.LOCAL) {//主动挂断
                // Local hangup
		log("****local hangup");
                droppedDuringPoll.remove(i);
                conn.onDisconnect(Connection.DisconnectCause.LOCAL);
            } else if (conn.cause ==
                Connection.DisconnectCause.INVALID_NUMBER) {//拨出的号码无效
		log("****invalid hangup");
                droppedDuringPoll.remove(i);
                conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER);
            }
        }

        // Any non-local disconnects: determine cause如果有非本地原因要清除的连接
        if (droppedDuringPoll.size() > 0) {
            //bIsVoice = droppedDuringPoll.get(0).isVoice();
	    log("****dropping call bIsVoice = "+bIsVoice);
	    if(bIsVoice) {
                cm.getLastCallFailCause(//先查找上次失败的原因
                    obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE));
            } else {
                cm.getLastVTCallFailCause(
    		    obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE));
	    }
        }

        if (needsPollDelay) {
	    log("****needspolldelay");
            pollCallsAfterDelay(bIsVoice);
        }

        // 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) {
	    log("****newringing and hasnonhangupstatechanged");
            internalClearDisconnected();
        }

        updatePhoneState();//跟新gsmphone的状态

        if (unknownConnectionAppeared) {
	    log("****unknown connection appeared");
            phone.notifyUnknownConnection();
        }

        if (hasNonHangupStateChanged || newRinging != null) {
	    log("****hasnonhangupstatechanged and newringing");
            phone.notifyPreciseCallStateChanged();
        }

        //dumpState();
    }

 

 

 

 

 

 

GsmCallTracker.java里面维护了三个call对象

    GsmCall ringingCall = new GsmCall(this);
    // A call that is ringing or (call) waiting
    GsmCall foregroundCall = new GsmCall(this);
    GsmCall backgroundCall = new GsmCall(this);

call可以有如下几种状态:

IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING

的但是不是每一个call都可以拥有上面所有的状态.具体一个call对象可以拥有哪些状态可以查看parentFromDcstate函数

private GsmCall parentFromDCState (DriverCall.State state) {
664	        switch (state) {
665	            case ACTIVE:
666	            case DIALING:
667	            case ALERTING:
668	                return owner.foregroundCall;
                             //foreground call can have ACTIVE/DIALING/ALERTING three states
669	            //break;
670	
671	            case HOLDING:
672	                return owner.backgroundCall;
673	            //break;
674	
675	            case INCOMING:
676	            case WAITING:
677	                return owner.ringingCall;
678	            //break;
679	
680	            default:
681	                throw new RuntimeException("illegal call state: " + state);
682	        }
683	    }

 

 

 

三个call对象的介绍如下

ringingCall:(用来管理处于INCOMINGWAITING状态的通话)//刚进来的电话初始化gsmconnection 时,call的状态会变成INCOMING

foregroundCall:(用来管理处于DAILINGALERTINGACTIVE状态的通话)

backgroundCall:(用来管理HOLD的通话)。

往外打的电话可以有DAILING,ALERTING,ACTIVE 三种状态

打进来的电话可以有INCOMING,WAITING,ACTIVE 三种状态

往modem发了挂断命令时call的状态变为DISCONNECTING(正在断开)。

 

手机的状态只有下面三种:IDLE, RINGING, OFFHOOK; 

    /**
     * The phone state. One of the following:<p>
     * <ul>
     * <li>IDLE = no phone activity</li>
     * <li>RINGING = a phone call is ringing or call waiting.
     *  In the later case, another call is active as well 有电话在在打进来或者等待接听</li>
     * <li>OFFHOOK = The phone is off hook. At least one call
     * exists that is dialing, active or holding and no calls are
     * ringing or waiting. 有正在打出去的电话 or 已经接通了的call or 处于hold状态的call</li>
     * </ul>
     */

 

 

一个call对象里面有一个连接数组

 public ArrayList<Connection> connections = new ArrayList<Connection>();

GsmCallTracker里面也有一个connections数组,to record the call list and in GsmConnection ,it have a member  GsmCall parent.

every time poll current call, the connections arry will updata it's state .根据返回的DriverCall.state来选择parent应该是ringing or foreground or background call,如果call的类型没切换,可以是变化了call 的状态.或者DriverCall.state和查询前一样,返回false

所以一个backgroundCall里面其实可以保存多个通话连接,只是暂时挂起。再比如,在开始呼叫时,gsmcalltracker会初始化一个gsmconnection

 

        isIncoming = false;
        isVoice = ct.isMOVoice;
        createTime = System.currentTimeMillis();

        this.parent = parent;//这里的parent就是call。且是foregroundCall。相反呼进来的电话是ringincall
        parent.attachFake(this, GsmCall.State.DIALING);//将这个connection加入到call的connection数组成员中,且将parent的状态设置为DIALING

 

 

 

 

 

gsmcalltracker的构造函数里有

 

cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);


所以当ril.java每次接到底层上报的UNSOL_RESPONSE_CALL_STATE_CHANGED 时,就会给gsmcalltracker 发EVENT_CALL_STATE_CHANGE事件

 

这个事件的处理就是初始化查询当前的call的状态

 

    protected void pollCallsWhenSafe() {
        needsPoll = true;

        if (checkNoOperationsPending()) {
            lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);//当查询完call list的状态后返回到calltracker的事件
            cm.getCurrentCalls(lastRelevantPoll);//调用ril实例查询call的状态
        }
    }


查询完后给gsmcalltracker发的事件EVENT_POLL_CALLS_RESULT,其处理就是 handlePollCalls函数。

 

挂断电话时分不同的call对象,如果电话已经接通了则RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND

如果是挂断正在打进来的电话则用RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND

 

对于MT voice call

在PhoneBase.java文件里有

 mCM.setOnCallRing(this, EVENT_CALL_RING, null);

当ril接到UNSOL_CALL_RING 时,就会报告EVENT_CALL_RING这个事件给GsmPhone 。其处理为notifyIncomingRing

 

    private void notifyIncomingRing() {
        if (!mIsVoiceCapable)
            return;
        AsyncResult ar = new AsyncResult(null, this, null);
        mIncomingRingRegistrants.notifyRegistrants(ar);//通知注册过次事件的模块
    }


在CallManager.java里有 

 

 

phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);

 

在callmanager里的处理也是通知注册次事件的模块

 

                case EVENT_INCOMING_RING:
                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_INCOMING_RING)");
                    // The event may come from RIL who's not aware of an ongoing fg call
                    if (!hasActiveFgCall()) {
                        mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
                    }

 

InCallScreen.java里有

mCM.registerForIncomingRing(mHandler, PHONE_INCOMING_RING, null);

mCM是CallManager的实例

上层如果接听了,则会调用gsmphone里的acceptCall-->gamcalltracker.acceptCall函数来发RIL_REQUEST_ANSWER给modem

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yiqingyang2012

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值