Android 实现手机接通电话后振动提示的功能
有些手机在电话接通后会有振动提示,这有个好处就是可以等到接通后再放到耳边接听,减少辐射。本文就讲讲如何在Android手机中实现这种接通电话后的振动提示功能,这里主要针对拨出的电话。
AndroidSDK提供的通话状态
很明显,要在电话接通的时候产生振动提示,首先需要知道电话在何时被接通。而AndroidSDK并没有给出直接读取这种状态的方法。下面是AndroidSDK的电话服务类TelephonyManager提供的三种电话状态:
CALL_STATE_IDLE 空闲状态
CALL_STATE_OFFHOOK摘机状态
CALL_STATE_RINGING 响铃状态
这几个状态很容易理解:摘机状态即拿起话筒(对于座机电话而言的动作),但这个状态可能发生在拨入电话接通时,也可能是拨出电话时,但是却不能说明拨出电话接通时。通过以上3种状态我们仅能组合出挂机和来电接通这两个状态。而今天我们要实现的功能却无法做到。
看来我们需要寻找其他方法来实现了,SDK靠不住啊……
Android运行log分析
还好Android在运行时会有大量的log产生,看看我们能不能从这上面找到突波口呢?我们选择Android的Radio模块的日志来分析。首先我们需要写一段代码来读取Radio相关的log,读取log就不得不用到logcat了。
Processprocess; InputStreaminputstream; BufferedReaderbufferedreader; try{ process=Runtime.getRuntime().exec("logcat-vtime-bradio"); inputstream=process.getInputStream(); InputStreamReaderinputstreamreader=newInputStreamReader( inputstream); bufferedreader=newBufferedReader(inputstreamreader); Stringstr=""; while((str=bufferedreader.readLine())!=null){ log.i("mLogcat",str); } }catch(Exceptione){ }
另外,要让程序能够读取系统log需要指定权限,在AndroidManifest.xml文件中加入一下内容。
XML/HTML代码
<uses-permissionandroid:name="android.permission.READ_LOGS"></uses-permission>
通过上面这段代码我们就可以将Radio的log输出到了,这样我们就可以通过在DDMS中查看这些log,分析其中的通话过程。具体抓到的log就不贴出来了,大家可以自己编写程序通过上面的代码来抓取和分析。我只说一下我的分析结果。
通过分析log发现了一些蛛丝马迹。其中有几条日志很有用:
GET_CURRENT_CALLS id=1,DIALING
GET_CURRENT_CALLS id=1,ALERTING
GET_CURRENT_CALLS id=1,ACTIVE
由于log较长我只拿了每条log的开头部分,真实的会多很多内容。当我们拨出电话的时候,会输入这么几条log。
拨号->提醒->活动
大致是这么个过程。经过几次测试发现,电话接通时会进入活动状态,并会输出:GET_CURRENT_CALLS id=1,ACTIVE 这条log,至此我们已经接近成功了。
不过之后我又发现在拨号开始到电话接通这段时间内会经过多次的“拨号->提醒->活动”这样的状态变化,仅当话筒中嘟声响起后GET_CURRENT_CALLS这条日志会锁定在ALERTING。在电话接通前便不再出现GET_CURRENT_CALLS日志了。
可能上面的这段表述大家不是很清楚,换句话说在通话接通之前会出现多次的GET_CURRENT_CALLSACTIVE这样的日志,而仅有一次是电话接通产生的。这就给我们造成了麻烦。不能只是单纯的抓取GET_CURRENT_CALLSACTIVE这样的信息来判断了。
我们只能通过一些逻辑上的判断来实现了。
实例代码讲解
下面看我的代码:
classTestThreadimplementsRunnable{ //振动器 VibratormVibrator; //电话服务 TelephonyManagertelManager; publicTestThread(VibratormVibrator,TelephonyManagertelManager){ this.mVibrator=mVibrator; this.telManager=telManager; } @Override publicvoidrun(){ //获取当前话机状态 intcallState=telManager.getCallState(); Log.i("TestService","开始.........."+Thread.currentThread().getName()); //记录拨号开始时间 longthreadStart=System.currentTimeMillis(); Processprocess; InputStreaminputstream; BufferedReaderbufferedreader; try{ process=Runtime.getRuntime().exec("logcat-vtime-bradio"); inputstream=process.getInputStream(); InputStreamReaderinputstreamreader=newInputStreamReader( inputstream); bufferedreader=newBufferedReader(inputstreamreader); Stringstr=""; longdialingStart=0; booleanenableVibrator=false; booleanisAlert=false; while((str=bufferedreader.readLine())!=null){ //如果话机状态从摘机变为空闲,销毁线程 if(callState==TelephonyManager.CALL_STATE_OFFHOOK &&telManager.getCallState()==TelephonyManager.CALL_STATE_IDLE){ break; } //线程运行5分钟自动销毁 if(System.currentTimeMillis()-threadStart>300000){ break; } Log.i("TestService",Thread.currentThread().getName()+":" +str); //记录GSM状态DIALING if(str.contains("GET_CURRENT_CALLS") &&str.contains("DIALING")){ //当DIALING开始并且已经经过ALERTING或者首次DIALING if(!isAlert||dialingStart==0){ //记录DIALING状态产生时间 dialingStart=System.currentTimeMillis(); isAlert=false; } continue; } if(str.contains("GET_CURRENT_CALLS") &&str.contains("ALERTING")&&!enableVibrator){ longtemp=System.currentTimeMillis()-dialingStart; isAlert=true; //这个是关键,当第一次DIALING状态的时间,与当前的ALERTING间隔时间在1.5秒以上并且在20秒以内的话 //那么认为下次的ACTIVE状态为通话接通. if(temp>1500&&temp<20000){ enableVibrator=true; Log.i("TestService","间隔时间....."+temp+"....." +Thread.currentThread().getName()); } continue; } if(str.contains("GET_CURRENT_CALLS")&&str.contains("ACTIVE") &&enableVibrator){ mVibrator.vibrate(100); enableVibrator=false; break; } } Log.i("TestService","结束.........." +Thread.currentThread().getName()); }catch(Exceptione){ //TODO:handleexception } } }
我的这个方法比较牵强,是通过判断第一次DIALING与每一次ALERTING之间的间隔,如果间隔大于1.5秒,那么认为已经进入了“嘟”声提示的时候了,那么下一个ACTIVE将是电话接通。这个1.5秒是通过分析日志得出的。但是这种方法我始终觉得不太靠谱。如果大家有好的方法可以交流交流。
剩下的就是让这个线程在电话拨出时触发,并且常驻在电话中时候准备这就可以了。可以采用Service配合Receiver来实现。Service来实现常驻,Receiver来实现监听拨出电话。基本就可以完成我们想要的功能了。
以上代码我都测试过,99%有效,哈哈。这里面提到了一些Android的基础内容,像logcat、Service、Receiver,这些如果大家不了解的话可以找相关文章资料学习下。
通过此文希望能帮助Android开发的朋友,谢谢大家对本站的支持!