Android M Dialer完全总结
来源:互联网 发布:今日赌运测试php 编辑:程序博客网 时间:2024/06/10 12:00
作为Dialer Owner,作一下基于M版本的总结吧。
在线源码阅读:http://androidxref.com
总体轮廓
手机之所以被称为手机,是因为它是一个通讯工具,而完成这一核心功能的软件模块,即为Telephony。
Telephony包含的范围非常广泛,单拿上层来说,大致可以划分成五大部分:Telephony应用(Dialer
、Contacts
、Mms
),service Telephony和service Telecomm,framework Telephony和framework Telecomm。
现在这一架构的主要变化是从L版本开始的,相较旧版的主要变迁可以参考:Android 4.4 Kitkat Phone工作流程浅析(十二)__4.4小结与5.0概览
图片资料
本文只关注Dialer,那么先看几张Nexus 6p的实机截图来个感性的认识:
架构分析
Dialer主要涉及的包有:
1)/packages/apps下 Dialer
,InCallUI
,ContactsCommon
,PhoneCommon
,VoiceDialer
凭借makefile,分包可以非常的自由随意,看如下片断:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
Dialer
,InCallUI
,PhoneCommon
,ContactsCommon
全都在src_dirs路径下了,于是最终的Dialer.apk由这四个包下的代码编译生成。
VoiceDialer
提供语音相关功能,入口看下图:
但是,此功能侵略性过强,在天朝是基本残废的,在海外多数运营商也不喜欢表示要去除,所以不予关注。
2)/packages/services下 Mms
,Telephony
,Telecomm
,生成MmsService.apk,Telecom.apk与TeleService.apk,对Dialer来说是提供通话菜单功能的。
应该说不管从逻辑还是物理上,切分出来都是大有好处,这样才能让Android能够良好支持第三方通讯类应用。
3)/packages/providers下 TelephonyProvider
,ContactsProvider
,数据创建及查询,当然也是要切分的部分。
4)frameworks/opt和frameworks/base下 telephony
等和上面类似的眼熟名字,具体关系到各种功能点如MmiCode,Clear Code,Number match,Number format,DTMF,FDN等等等等。
具体分析
看完整体架构之后,单单一个Dialer包的定位也变得很清晰了:它就只是一个拨号器而已。
1.层次结构
Dialer的UI是否美观是个见仁见智的问题,我个人还是挺喜欢的。
这里我们只谈其实现原理。
这是Dialer的主layout dialtacts_activity.xml
:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
虽然不同情况下显示的部分不同,但总得来说以z轴从大到小做一个侧向剖面图排列的话,主要元素是这样的:
- FAB button(FloatingActionButton)
layout中R.id.floating_action_button_container
位置即是,并不是真正的FloatingActionButton
,Google工程师手搓了一个看上去有着类似效果的控件而已。用来控制Dialpad的展开和收起。 - Dialpad(Fragment)
实现类为xref: /packages/apps/Dialer/src/com/android/dialer/dialpad/DialpadFragment.java,填充进R.id.dialtacts_container
中,自带号码输入条,按下拨号钮后会构造相应Intent
然后启动service Telecomm中的不可见Activity如UserCallActivity
(L中对应为CallActivity,M中为实现AFW,Android for Work模式引入)开始拨号处理流程。 SearchUI(Fragment)
填充在R.id.dialtacts_frame
中,注意展开与收起Dialpad时,虽然肉眼感知不到,但却会使用不同的Fragment来提供搜索结果页面。一个是SmartDialSearchFragment,另一个是RegularSearchFragment。
这是因为,其在设计上还支持更强大的搜索功能,能使用输入法进行输入:
国内的一般都把这功能直接做掉了-_-||。Content pages(Fragment)
实现类为xref: /packages/apps/Dialer/src/com/android/dialer/list/ListsFragment.java,填充进R.id.dialtacts_frame
,因为时间上肯定比SearchUI要早,所以在其下面。ListsFragment中使用ViewPager
又组织着三个Fragment作为之前图示中的三个Tab页(当满足情况时,第四个页面会出现)。这样的嵌套是否是一个好的设计值得商榷。
2.拨号盘
实现代码为/packages/apps/Dialer/src/com/android/dialer/dialpad/DialpadFragment.java
拨号盘分三个,全都使用了PhoneCommon包中的同一套资源:
- Dialer中一个
- InCallUI中一个
- KeyGuard中有个“紧急呼叫”按钮,会调用到service Telephony中的一个弱化版拨号盘
关于UI:Google原生设计上这三处使用了一致的UI,所以直接复用即可。但是,其他手机设计有很多都是不一样的,所以这里是一个客制化比较麻烦的点。
关于双卡拨号:Google对于双卡的支持就是:选择默认卡->Dialer中按下拨号->使用默认卡拨号。国内很多厂商的做法却都是在Dialpad上提供两个按钮,如卡一“中国移动”卡二“中国联通”,需要按哪个键就用哪张卡进行拨号。其实在拨号流程中的service Telecomm中的一环有使用一个关键值PhoneAccountHandle
来进行判定使用哪张SIM卡,所以实现的方法也就只是很简单地Intent
传值、取值、处理即可。L中拨号流程为CallActivity#processOutgoingCallIntent
->CallReceiver#processOutgoingCallIntent
->CallsManager#startOutgoingCall
,M中略有变动,开始的变为了UserCallActivity
,往下找即可。
关于长按数字键快速拨号:
如设置2键拨号119,则长按2能够立即进行拨号。这个功能很长一段时间以来由MTK的MTK Plugin提供,然而在L版本中Google提供了SpeedDial,即Dialer_示例1
中的Tab页面,对联系人收藏之后就变成了这个样子,多了一个小卡片可以直接点击呼叫:
虽然本身完全不是同一个东西,但MTK表示此功能将废弃。
如果要自行实现的话,实现原理大略是这样:遵循Fragment寄宿于Activity的思路写一个类似组件,关键回调中调用同名方法。建立一个数据库,用户设置相应键位的快速拨号时,如果是设置号码,那就简单保存号码;如果设置的是联系人,那么置标志位,保存联系人条目的主键,每次拨号或显示时之前,使用该主键查询数据库获取所需信息。
3.设置
设置页的UI非常糟糕,毫无设计可言,而且层次多得不像话,以下演示的是如何进行通话帐户设置:
示例5跟6都只是简单罗列多行单调的文字,而且风格还不统一,一个有分隔线另一个没有(示例5在Dialer包中,示例6则在services/Telephony中,可以推断不是同一拨人做的,而且没有沟通好,于是出现了如此明显的差异),只有示例7看出了点儿Material Design的影子,但是只有一个分类的话Category又变得没有意义了。
我期待的设置页是层次合理,有分类带说明文字的,下图来自于我的开源练习之作PureNote:
示例5的页面由Dialer
中的DialerSettingsActivity.java
提供,并且,会根据单双卡而添加不同的Header,而往后的通话设置则主要由service Telephony提供支持,参见如下代码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
单卡为CallFeaturesSetting
,双卡为PhoneAccountSettingsActivity
,PhoneAccountSettingsActivity
只是显示两行卡名,如行一中国移动行二中国联通,然后点击后再复用CallFeaturesSetting
。
4.数据获取
有Dialer
特色的自然就是CallLog部分还有SearchUI部分了。
关于SearchUI,可以参考这篇文章Android拨号搜索机制源码分析(原)。
对于CallLog,其数据查询与更新采用的是AsyncQueryHandler
+ContentObserver
,Google应该考虑用Loader
来取代它们。
参考Android4.4 Telephony流程分析——拨号应用(Dialer)的通话记录加载过程、Handler官方范例AsyncQueryHandler源码解析
我只想说:读CallLog的代码(这里指得是数据获取+内容显示),不啻于去地狱走一遭,一坨一坨的极为恐怖。
代码细节
Dialer中的一些代码细节。
组合模式
设置监听器分两种情况:setOnXXXListener
,addOnXXXListener
,通常来讲,后者要优于前者,所以许多类都增加了add
方法而废弃了set
方法。可假如说你使用的这个类现在只有set
方法可得怎么办呢?只需要使用组合模式即可达成效果,具体使用场景可以参考ListsFragment
。以下代码为一个示例:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
异步设置TextWatcher
DialpadFragment
中为了实现i18n号码处理,需要给号码输入条添加一个TextWatcher
,Google工程师是这样做的,其中mDigits为TextView
:
- 1
跟踪代码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
合一
王自如评价三星手机内置应用时说“不同的产品经理也许从来都没有交流过,所以才会做出风格这么不统一的产品”,这话放在Android M的Dialer与Contacts身上也是十分贴切啊,肉眼可辨的坑爹啊,强迫症能忍么?
从功能上来讲,你会发现与Dialer相比较,Contacts的存在感简直弱爆了,它能做到的事情,Dialer全都能做。而且因为Contacts只能操作联系人数据,几乎让人没有想点它的兴趣。
实际上,在4.2版本中Contacts与Dialer就是同一个应用Contacts.apk,只不过分出了两个应用入口来而已。当然,虽然实际上是同一个应用,但在用户感受上则是两个。
而国内UI如MIUI还有锤子Rom都很明智地对这两个应用进行了代码与用户感受上的“合一”,只不过小米是保留了两个入口,但启动的都是同一个应用;而锤子是只提供Dialer应用,给你两个应用的功能。华为最残暴,大手一挥把联系不太大的Mms
都合了,号称“三合一”(不过,最新版本的EMUI又只有二合一了):
如何达到这一效果?不复用原生代码的话,自己刷刷刷开写可以解决问题,但这实在是费力。复用原生代码的同时达到这一效果,主要就三点,一是前面提到过的makefile的修改,删除两个makefile,修改最后一个makefile让它们编译出一个应用来;二是修改manifest,善用alias让应用能正常被使用;最后则是应用重构想办法让它一个顶仨了。
推荐阅读
- http://blog.csdn.net/yihongyuelan?viewmode=contents
- http://blog.csdn.net/xiashaohua?viewmode=contents
- Android M Dialer完全总结
- Android M Dialer完全总结
- Android M Dialer完全总结
- Android Dialer,Mms,Contacts源码修改笔记
- android源码分析--Mms、Contacts、Dialer
- Android:MTK的Dialer模块联系人搜索
- Android:MTK的Dialer模块联系人搜索
- android N 导入批量联系人 dialer崩溃
- Android Dialer,Mms,Contacts源码修改笔记
- Android 完全退出应用程序总结
- android 完全退出应用总结
- Android Volley完全解析总结
- android中的动画完全总结
- Android为拨号盘dialer定制声音DTMF Tones
- Android为拨号盘dialer定制声音DTMF Tones
- Android为拨号盘dialer定制声音DTMF Tones
- Android为拨号盘dialer定制声音DTMF Tones
- Android为拨号盘dialer定制声音DTMF Tones
- Linux 常用目录及其作用
- 第2章 主机规划与磁盘分区
- 2个方法解决LINODE VPS无法发送邮件的问题
- Java 异常处理的误区和经验总结
- 非常详细的shell知识
- Android M Dialer完全总结
- 刚刚!没参加饭局的马云用iDST的语音技术买了张地铁票,竟然没说唤醒词
- Window下PHP三种运行方式图文详解
- 上海华瑞银行面试
- 银行卡格式化(每四位空格,删除添加,更变等)
- 线程池参数解析
- java 网络编程三要素之协议(TCP协议):
- Informix-4gl数据库的dbexport导出与dbimport还原
- 理解linux的硬链接与软链接