终于到了CallManager.java。我对它的理解是,这个类是frameworks层在Call业务中面对App层的最后一层封装。通过这个类,我们可以对底层的业务做进一步归纳,实际上也是为PhoneApp提供了Call业务的控制接口(CallManager class provides an abstract layer forPhoneApp to access and control calls.)。那么,CallManager都有哪些功用,参考该类的说明文档我们可以得知:
1. 对诸如dial()和hangup()等业务的操作
2. 一些通道的使能操作,比如说CanConference()
3. 消息的注册
由此,对CallManager的几个功能我做了划分如下:
这里举出的方法只占其中的一部分。
在进行下一步分析之前,先要理清一个概念,CalManager所维护的几个泛型数组里放置的,究竟是什么?
从CallManager的构造函数可以看到,CallManager实例化后最重要的就是如下几个数组对象:
- privateCallManager() {
- mPhones= new ArrayList<Phone>();
- mRingingCalls= new ArrayList<Call>();
- mBackgroundCalls = new ArrayList<Call>();
- mForegroundCalls = new ArrayList<Call>();
- mDefaultPhone = null;
- }
回忆一下在CallTracker和Call类讨论时所归纳的结论,当时抽象出来的三种实例变量ringingCall,forgroundCall和backgroundCall在这里终于得以派上用场。对于应用层而言,frameworks层将Call业务的抽象即可用这三种Call实例及其引申出的状态来形容。
Call.state与抽象出的三种不同的Call实例,有如下一一对应关系,画的比较粗糙~
当然,这里并不是说Call.state的几种状态就完全被CallManager.java封装了,在某些情况下,为了精确获取当前Call实例的状态,app层仍然会直接调用Call.state来进行比对。但是一般来说,通过CallManager.java进一步抽象封装后的Call实例更能说明当前维护的通话状态。用一种比较通俗的方法来说,上层所关注的不过就是这么三种情况下的通话:
前台通话(正在拨出以及已经接通了的电话,注意是作为主叫方)
后台电话(前台已经有了一通电话,而被挂起在后台的电话)
响铃电话(正在响铃而尚未被接通的电话,包括存在前台通话时的情况,注意是作为被叫方)
不过有一点需要修正的是,在之前的文章里我认为IDLE、DISCONNECTED、DISCONNECTING这三种状态可以不用考虑。今天又看了一下接口注释,实际上这三种状态对于ringingCall,forgroundCall和backgroundCall也的确没有任何影响——因为处于IDLE、DISCONNECTED状态下时,三种Call实例状态都认为是有效的。而DISCONNECTING确实是不予考虑。
从下图可以看出,针对如上的三种通话状态,有派生出与之相关的Call,Connection以及Phone的状态
一一进行分析:
1. getXXCall& hasXXCall
这部分的方法比较多,稍微整理一下,剔除私有方法可以看到,公共方法中与ForegroundCall,BackgroundCall和RingingCall三种状态相关的,大致上可以分为两类。一类是判断当前Call是否为对应状态下的通话(has),另一种为获取处于对应状态下通话实例(get)。那么对于后者,有人会问,getForegroundCall()与getActiveFgCall()有什么区别,从代码中可以看出,getForegroundCall()通过unmodifiableList方法返回一个前台通话列表,可以用来轮询当前所有的前台通话,而getActiveFgCall()则返回一个具体的前台通话实例。
此外,需要注意的是,由于后台通话可能有多个(比如说多方通话尚未合并时),此时调用getFirstActiveBgCall()获取的是第一通后台电话,同理对于getFirstActiveRingingCall()。
2. getXXPhone
再看对应于ForegroundCall,BackgroundCall和RingingCall三种状态下的getFgPhone,getBgPhone和getRingingPhone,都是取自于Call.getPhone()方法获取对应对象的。追根结底,它们仍然获取的是对应CallTracker维护的Phone实例,这里就不细说了。
值得一提的是私有方法getPhoneBase(),该方法用来消掉代理,指向真正所用到的Phone对象,在需要真正Phone对象作为参数的场合会用到。
3. getXXConnection
对应的方法会返回一个前台/后台状态下的通话链路列表,通过轮询该列表可以拿到当前处于该状态下的所有Connections。
需要注意的是getFgCallLatestConnection(),该方法用来返回最新的一次前台通话Connection,用到的场合一般是需要最新一次前台通话链路的地方,比如说“重拨电话”的时候。
洋洋洒洒说了这么多,其实对于fremework层Call业务而言,我的理解是,掌握其中各个通路状态以及抽象出来的实例含义更为重要,倒是对于其中的四大业务dial,hangupCall,rejectCall以及acceptCall的流程掌握,反倒是水到渠成的事情。