2. GsmCallTracker类,GsmCall类以及GsmConnection类

需要理解的若干概念: GsmCall—GsmConnection—GsmCallTracker关系,android的register—notify模型,ringingCall,foregroundCall,backgroundCall

这三个类放在一起进行分析的原因并不是因为它们的功能接近,而是因为在Call业务中,这三者之间不仅数据交互较多,而且在上报当前状态或是接收下层消息的过程中都有着密切的联系。

Android Call 功能在各个frameworks层中的结构整理 (二)_第1张图片

GsmCallTracker是Call应用中的通话管理层,它维护了一个最多MAX_CONNECTIONS=7路GsmConnections通话链路的同时,还维护了三种通话状态(ringingCall,foregroundCall,backgroundCall)。

GsmCallTracker、GsmCall以及GsmConnection这三者之间的关系,可以认为后两者是GsmCallTracker维护的对象,同时GsmConnection又依附于GsmCall的存在,有常量MAX_CONNECTIONS_PER_CALL=5,表明处于某一个状态的通话最多可以有几路,也就是说,最多可以有5路通话处于某一个通话状态(foregroundCall,background,ringing)。

GsmConnection继承自Connection类,直观理解,该类主要是用来维护某一路的通话状态的。

Connection.java有个非常重要的枚举成员DisconnectCause。通过获取CallFailedCause.java错误码,可以将底层上报上来的错误号与DisconnectCause所维护的错误原因类型一一对应起来(参照disconnectCauseFromCode @ GsmConnection.java),从而达到让上层APP知晓错误原因的目的。在实际代码调试过程中,也会因为平台的差异对这段代码做一定修正。

此外,Connection.java中存在getState()方法,注意该方法返回的是一个Call实例,也就是说,通过引用该类的这个方法实际上获取的是当前电话维护的Call实例。同时,该类中的isAlive()与isRinging()方法最终都指向Call实例的对应方法,也就是说,Connection的此类状态实际上也是Call上的状态。但不同的是isIncomming()方法,该方法是一个抽象方法,在子类中应该有不同的表现方法。

现在来看子类GsmConnection,android用MO与MT两个通话状态来分别修饰它的构造函数。对于MT而言,GsmConnection的建立需要抽取CLCC上报的DriverCall参数。而对MO而言,GsmConnection的建立则是在dailing时由上层指定字串以及GsmCall实例来决定。

在实际的代码调试过程中,GsmConnection如何被维护可以直观地通过+CLCC看出来。例如:

>AT+CLCC

<+CLCC:1,0,0,0,0,”10086”,129

<+CLCC:2,1,5,0,0,”13810000000”,161

处于某一状态下的某路通话状态一目了然,driverCall上报的值也可以通过CLCC直接查询得出。

GsmConnection依附于GsmCall的存在。在android中,表示某种通话的状态的类即是这个Call.java类和他的子类们。说到Call.java,就不得不说它维护的一个State枚举成员,在通话乃至大多数与通话相关的业务中,这个Call.State实例变量都起到了极大的作用,多数相关的业务执行都需要查询当前的通话状态来获得下一步执行的条件。

这个State将IDLE,ACTIVE,HOLDING,DIALING,ALERTING,INCOMING,WAITING,DISCONNECTED,DISCONNECTING九种通话状态以三种类别进行归纳,即Alive,Ringing,Dialing。需要注意的是,ACTIVIE以及HOLDING状态并未归纳其中。通过方法getState即可以获得当前通话状态。

这个State的值是如何来的?参考DriverCall.java可以看到,ACTIVE、HOLDING、DIALING等六种通话中的状态都是通过CLCC查询后获得的。这同时也从侧面解释了为什么IDLE、DISCONNECTED、DISCONNECTING为什么无法从底层直接获得——因为此时已经不处于通话连接状态了。


通过对stateFromCLCC @ DriverCall.java以及stateFromDCState @ GsmCall.java的调用,将CLCC查询的结果转换为Call.State对应的状态值。这样当前每一路通话链接的通话状态就被frameworks层获取了。

需要指出的是,在Phone.java中同样存在State枚举状态,为IDLE,RINGING,OFFHOOK,不同于Call.State,后者指的是通话状态,而前者指的是电话状态,注意不要混淆了。

一路通话的状态如下图所示:

Android Call 功能在各个frameworks层中的结构整理 (二)_第2张图片

那么GsmCallTracker究竟是做了哪些工作来管理通话过程的呢?回到问题的起点,再来看GsmCallTracker的三个实例变量ringingCall、foregroundCall和backgroundCall。虽然同样都是GsmCall实例化的结果,但这三这个对象被引用的条件并不相同,以ringingCall为例,在GsmCallTracker.java中,ringingCall所引用到的getState()方法,主要与GsmCall.State.INCOMING和GsmCall.State.WAITING相比较,而其回调的State也多是引用isRinging()方法。

而对于foregroundCall而言,其关注的State类型为ACTIVE,IDLE(这个大家都关注)。同样,foregroundCall回调的是State引用的isAlive()方法。

最后再来看backgroundCall,它引用的是GsmCall.State.HOLDING。参与回调方法是isAlive()和isIdle()。

归纳一下,就是:

ForgroundCall为ACTIVE,DIALING,ALERTING

BackgroundCall 为HOLDING

ringingCall为INCOMING,WAITING

与Call.State的分类方式略有不同,ACTIVE状态与Dialing状态群中划归在一起,被认为是“前台”通话状态。这个我简单理解是,处于这个状态下的通话,当前的InCallScreen始终都处于前台状态而已。

至于为什么同样少了IDLE、DISCONNECTED、DISCONNECTING三种状态,原因就与DiverCall同样了。

对于GsmCallTracker的工作机制,还有一个有趣的android概念需要关注,我把它命名为register—notify模型。

Register—notify模型:

这个模型说到底,就是个HandlerMessage的方式。只不过采用了回调的方式后,形式上更加接近嵌入式硬件上“中断”的处理效果

通过在上层进行某个消息A的注册,将A加入到一个泛型列表RegistrantList中。而当底层的某个事件触发这个已经注册的Registrant,执行sendMessage的时候,上层注册的消息A就被回调其handlerMessage方法-,从而响应底层的这个事件。

图大体上可以这么看。

Android Call 功能在各个frameworks层中的结构整理 (二)_第3张图片

所以,简单的说,这个过程就是首先在上层通过对某个消息的注册(声明),从而让系统在底层捕获到某特定动作的时候,可以触发该消息预先设定的“服务”,而后达到一种由“消息”驱动“流程”的结果。

值得说明的一点是android的message驱动事件的工作方式。真正对该项事件注册消息的地方,也就是将其添加到Registrants泛型列表当中的只有一处地方,而之前被层层包裹的原因是因为需要制定不同的tag(msg.what)。从而在底层消息被触发时,能够在不同的软件层次中被捕获,被解析,驱动各个层次中的事件行为。

因此,我本人对这类消息事件的分析方式,一般都是通过register来找到最底层注册的位置,并记录各个中间层包裹tags的地方。再通过最底层注册的方式找到最底层响应的位置,逆序向上,分析各个层次中handler都干了些什么。

在具体的dial(),rejectCall(),acceptCall()以及hangup()的通话流程中,我们可以看到GsmCallTracker对于流程性的控制过程并不难以理解,而为何进行这样的处理,或者说何时进行哪些处理,这还需要对整个android架构和3GPP协议有进一步的分析才行。


更多相关文章

  1. Android 软件盘弹出时把view顶上去的处理方法
  2. android利用WebView与JavaScript交互的方法
  3. Android:android.git.kernel.org 无法访问时下载源代码的解决方法
  4. Android中html.fromhtml的使用方法
  5. Android 5.0 自定义dialog 背景不透明解决方法
  6. android 入门学习笔记 利用bundle实现android,activity间消息的
  7. 笔记:Android消息机制
  8. 一个关于android中ListView的子控件中按钮事件的简单方法

随机推荐

  1. Android核心模块内容概述
  2. Android ContentProvider的使用和理解
  3. Unity 导出 Gradle 工程及问题 (Please s
  4. Android Sensor详解(5)搭建adsp firmware的
  5. Android学习笔记--实现帧动画
  6. Android开机log和常见异常的分析
  7. android:configChanges 横竖屏切换的生命
  8. ListView使用技巧(二):相关设置
  9. Android事件处理第一节(View对Touch事件的
  10. 精通Android