Default phone and system dialer
Android受到极大欢迎的一个重要原因是,Android的个性化程度非常高,比如用户可以更换一个用户喜欢的通话软件,有如用户可以更换一个用户喜欢的短信软件;有如用户可以更换一个用户喜欢的浏览器。而这些在iPhone等众多手机上是做不到的。但由于通话是一个敏感的功能,为了限制一些非法的软件使用通话功能,Android对只有设备用户设置了default phone的软件才可以使用通话功能。本文将对Android是如何实现让用户可以更换通话软件的机制进行阐述。本文更加适合对Telecom、Telephony有认识的读者。
通话是手机的一个基本功能,且从上层到底层,到modem,到网络,是一个非常复杂的过程,要实现通话软件的可更换性,就需要做到上层软件的独立性。如下图是通话的架构图:
如上图,在整个通话的架构中,通话的UI显示是非常独立的,只有一个通道与Telecom模块保持联系,而这个通道就是framework的InCallService.java,所有的通话软件都可以通过这个service维护通话UI的显示,更新和关闭。就因为InCallService这个通道,为通话软件的更换可行性提供了基本的保障。
进入Settings –> apps –> advance setting(右上角) –> Default Apps –> Phone app。如下图:
在第一章节中,提到通话软件和系统通话模块只有唯一一个通道,这个通道就是InCallService.java,当通话软件发起呼叫,这个请求会被发送到Telecom模块,Telecom会对发起者进行合法性检测,即是否是默认phone应用。如果是,才会继续向底层发起通话业务,否则,驳回呼叫请求。同理,当系统接受到来电,只会向默认的phone应用传送来电信息。
在这里,引入一个新的概念,System Dialer,什么是System Dialer?System Dialer是系统预装的phone应用。当设备用户没有安装任何第三方的phone应用,System Dialer将会成为唯一的default phone。Default phone的管理在telecom模块,涉及ContactsProvider模块。主要涉及以下java代码:
android.telecom.DefaultDialerManager.java
android.telecom. TelecomManager.java
com.android.server.telecom. TelecomServiceImpl.java
TelecomManager向上层暴露接口,涉及获取和设置当前default phone,实现代码如下:
DefaultDialerManager作为default phone的策略中心,自然图3和图4通过DefaultDialerManager的接口获取或设置当前的default phone,继续往下看DefaultDialerManager如何获取default phone。
先通过SettngsProvider获取secure xml中保存的DIALER_DEF-AULT_APPLICATION数据,接着调用getInstalledDialerApplications获取当前设备中安装的phone软件,系统会通过Intent.ACTION_DIAL的action过滤所有install的app。如果getInstalledDialerApplications的返回值中包含DIALER_DEFAULT_APPLICATION表明当前用户设置了
default phone。如果DIALER_DEFAULT_APPLICATION的返回值是空,或者getInstalledDialerApplications中没有包含DIALER_DEFAULT_-APPLICATION的数据,将会调用getSystemDialerPackage获取系统的phone,即dialer,如果getInstalledDialerApplications中包含system dialer,即返回system dialer。获取system dialer的实现代码在TelecomServiceImpl的定义如下:
图6和图7的代码非常简单,这里不再赘述。
获取default phone到这里基本结束,设置default phone的实现过程是不是大同小异呢?接下来详细看看这个过程。同理,设置default phone和获取default phone的接口同在TelecomManager中,如下图
理所当然地调用了DefaultDialerManager的setDefaultDialer-Application接口,这里设置成功后会发送一个ACTION_DEFAULT_-DIALER_CHANGED的广播。继续看setDefaultDialerApplication的实现逻辑。
这个过程非常简单,和获取default phone的步骤刚好相反,同样调用getInstalledDialerApplications获取系统的install的phone应用,然后调用putStringForUser设置到SettingsProvider的secure的xml中。到这里,default phone的机制已赘述完毕,整过过程逻辑简单,代码量少,非常好理解。
到这里,读者可能会有一个疑问,系统怎样控制非default phone的应用管理通话?在第一章节中,学会到了phone和系统的唯一的通信通道InCallService,这个InCallService对应系统的另外一段接口InCallController,在InCallController中对非法的phone软件进行过滤,如下:
通过queryIntentServices查询实现InCallService的service,然后调用getDefaultDialerApplication判断是否是default phone,如果不是,过滤掉。
在系统开发中,可能需要替换掉原来system dialer的情况,虽然phone应用是非常独立的一个模块,是不是意味着可以随意替换system dialer呢?答案是否定的。虽然系统提供了更换让用户可以设置default phone,但是对于一些敏感的通话,系统还是会保留的,如emergency call,建立emergency call只能是system dialer才能完成;有如在encrypt mode的模式,在android min framework中只能是core app的phone应用才能建立emergency call。
保持和原system dialer一致的包名的替换是最简单的,几乎不用修改系统什么代码,但是需要注意app必须是core app。
有时可能还需要完全改变了包名,那么必须修改系统的代码让替换的phone应用升级为system dialer。在上文中default phone的机理中可知,需要修改图7中的包名即可。另外,替换的phone应用也必须是core app。如果这个phone应用,除了InCallService的实现通道需要和系统保持协调,在call settings中也有部分接口需要和系统匹配。