欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 实现手机接通电话后振动提示的功能

程序员文章站 2024-03-05 22:39:13
有些手机在电话接通后会有振动提示,这有个好处就是可以等到接通后再放到耳边接听,减少辐射。本文就讲讲如何在android手机中实现这种接通电话后的振动提示功能,这里主要针对拨...

有些手机在电话接通后会有振动提示,这有个好处就是可以等到接通后再放到耳边接听,减少辐射。本文就讲讲如何在android手机中实现这种接通电话后的振动提示功能,这里主要针对拨出的电话。

       android sdk提供的通话状态

       很明显,要在电话接通的时候产生振动提示,首先需要知道电话在何时被接通。而android sdk并没有给出直接读取这种状态的方法。下面是android sdk的电话服务类telephonymanager提供的三种电话状态:

       call_state_idle         空闲状态

       call_state_offhook 摘机状态

       call_state_ringing   响铃状态

       这几个状态很容易理解:摘机状态即拿起话筒(对于座机电话而言的动作),但这个状态可能发生在拨入电话接通时,也可能是拨出电话时,但是却不能说明拨出电话接通时。通过以上3种状态我们仅能组合出挂机和来电接通这两个状态。而今天我们要实现的功能却无法做到。

       看来我们需要寻找其他方法来实现了,sdk靠不住啊……

       android运行log分析

       还好android在运行时会有大量的lo*生,看看我们能不能从这上面找到突波口呢?我们选择android的radio模块的日志来分析。首先我们需要写一段代码来读取radio相关的log,读取log就不得不用到logcat了。

 process process; 
  inputstream inputstream; 
  bufferedreader bufferedreader; 
  try { 
   process = runtime.getruntime().exec("logcat -v time -b radio"); 
   inputstream = process.getinputstream(); 
   inputstreamreader inputstreamreader = new inputstreamreader( 
     inputstream); 
   bufferedreader = new bufferedreader(inputstreamreader); 
 string str = ""; 
while ((str = bufferedreader.readline()) != null) { 
  log.i("mlogcat",str); 
} 
} catch (exception e) { 
    
  } 

另外,要让程序能够读取系统log需要指定权限,在androidmanifest.xml文件中加入一下内容。

xml/html代码

<uses-permission android: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_calls active 这样的日志,而仅有一次是电话接通产生的。这就给我们造成了麻烦。不能只是单纯的抓取get_current_calls active 这样的信息来判断了。

       我们只能通过一些逻辑上的判断来实现了。

       实例代码讲解

       下面看我的代码:

class testthread implements runnable { 
 //振动器 
 vibrator mvibrator; 
 //电话服务 
 telephonymanager telmanager; 
 public testthread(vibrator mvibrator, telephonymanager telmanager) { 
  this.mvibrator = mvibrator; 
  this.telmanager = telmanager; 
 } 
 @override 
 public void run() { 
  //获取当前话机状态 
  int callstate = telmanager.getcallstate(); 
  log.i("testservice", "开始.........." + thread.currentthread().getname()); 
  //记录拨号开始时间 
  long threadstart = system.currenttimemillis(); 
  process process; 
  inputstream inputstream; 
  bufferedreader bufferedreader; 
  try { 
   process = runtime.getruntime().exec("logcat -v time -b radio"); 
   inputstream = process.getinputstream(); 
   inputstreamreader inputstreamreader = new inputstreamreader( 
     inputstream); 
   bufferedreader = new bufferedreader(inputstreamreader); 
   string str = ""; 
   long dialingstart = 0; 
   boolean enablevibrator = false; 
   boolean isalert = 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) { 
      
     long temp = 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 (exception e) { 
   // todo: handle exception 
  } 
 } 
} 

      我的这个方法比较牵强,是通过判断第一次dialing与每一次alerting之间的间隔,如果间隔大于1.5秒,那么认为已经进入了“嘟”声提示的时候了,那么下一个active将是电话接通。这个1.5秒是通过分析日志得出的。但是这种方法我始终觉得不太靠谱。如果大家有好的方法可以交流交流。

       剩下的就是让这个线程在电话拨出时触发,并且常驻在电话中时候准备这就可以了。可以采用service配合receiver来实现。service来实现常驻,receiver来实现监听拨出电话。基本就可以完成我们想要的功能了。

        以上代码我都测试过,99%有效,哈哈。这里面提到了一些android的基础内容,像logcat、service、receiver,这些如果大家不了解的话可以找相关文章资料学习下。

        通过此文希望能帮助android 开发的朋友,谢谢大家对本站的支持!