转载:https://i-blog.csdnimg.cn/blog_migrate/03c8668cc4ff8d09b4d44fe7613162e9.png
由于近期所做一个项目需要做类似于“来电秀”的功能,所以上网搜索了一些相关资料,加上自己的一些想法,做了一个Demo。一下是我对该功能实现的一些想法,不对的地方欢迎各位指出。最后我会给出Demo 的源代码。
首先,Android系统的手机在监听到有电话呼入的时候会向系统发送电话状态改变的广播(android.intent.action.PHONE_STATE)。要想实现来电秀功能,必须在自己的程序中注册监听该广播。所以我们的程序大致功能就是通过监听该广播,当有电话呼入的时候显示自定义的界面。
以什么样的方式显示自定义的界面呢?主要有两种方式:
1 .以Activity的形式显示界面。
这种方式就是当有来电时启动自己的Activity并使其位于系统来电界面的上方,完全遮住系统界面。这种方式的好处是可以完全根据自己的需求做界面,但是主要面临着以下几个主要问题:
(1) 如何使自己的Activity遮住系统的来电界面:Android系统中系统级的应用有着最高的优先级,自己的应用不可能比系统优先级高,所以我们没办法屏蔽系统来电界面,只能等系统来电界面显示之后再启动我们自己的Activity ,暂时的处理是:在我们的应用接收到来电广播的时候延迟一秒钟启动我们自定义的Activity,这时候系统的来电界面应该已经显示了,这样基本可保证我们的Activity位于系统来电界面之上。
(2) 使用自己的Activity如何接听或挂断电话:Android SDK并没有将系统接听或挂断电话的接口开放出来,但是却以.aidl(Android Interface Definition Language,Android接口定义语言,可以使应用程序跨进程访问其他类的方法)向其他应用开放了(源码位置:frameworks/base/telephony/java/com/android/internal/telephony),我们可以在程序中建立一个同样的.aidl文件,并在程序中以反射的方式获取所需要的方法,主要的就是endCall方法(拒接或挂断电话)和answerRingingCall方法(接听电话)。但是另外一个问题是调用answerRingingCall方法需要权限(android.permission.MODIFY_PHONE_STATE , 该权限可以使应用程序改变电话的状态) ,但是该权限在android2.3及以后的版本中被隐藏,只有系统级应用才能拿到,这样我们只能通过模拟手机插上耳机时通过耳机上的按钮接听电话的操作来接听电话(具体实现看http://yk8900.blog.163.com/blog/static/123183544201272835550952/ )。
(3) 按下接听键前实时从网络取数据:在2G网络(GSM, GPRS,EDGE)情况下,来电的时候一般会断网(没有详细测试)。在3G(CDMA2000[电信],WCDMA[移动],TD-CDMA[移动])或WIFI情况下来电的时候是不会断网的,所以如果要从网络取数据,必须是在3G或WIFI情况下使用来电秀。
(4) 兼容性问题:由于使用自定义的Activity涉及到比较多的android底层未开放的接口,而各大手机厂商为了生产有自己个性的手机都会在一定程度上修改android底层源码,所以各种ROM的情况不一样, 我们无法做到适配所有android手机(目前该方法在三星和魅族手机上测试正常)。
2.以系统级弹框形式显示界面。
这种方式是当有来电时弹出一个窗口浮于系统所有界面之上的形式。也就是和360显示来电归属地的方式一样。使用这种方式实现同样需要考虑的问题设置为全屏还是半屏:如果设置为全屏,那么需要自己实现接电话的流程,那么就和使用Activity显示界面面临同样问题。如果设置为半屏,需要面对的问题是:一般来说弹窗和主界面的焦点不能兼得,如果能够很方便地就使用户既能操作弹窗内部的控件又不影响用户点击来电主界面上的各个按钮,那么用这种方式无疑是最好的。
当然不管采用哪种方式我们都需要面对很多比较特殊的情况,比如,在接听电话过程中有另一个电话进来怎么处理;在双卡双待的情况下会不会出现问题;用耳麦上的按钮接听电话,在接听电话过程中拔出耳麦会不会有影响等等,以及一些其他的不可预见的情况。
3.Demo运行的效果:
( 程序主界面可以选择以什么方式显示来电秀,并可以自定义)。
(选择弹窗的形式显示“来电秀”,高度设置了为75%)
(选择以Activity的形式显示来电秀)。