热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

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

本文主要介绍Android实现手机接通电话后振动提示的功能,这里整理了详细的相关资料,并附有示例代码,有需要的朋友可以参考下

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

       Android SDK提供的通话状态

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

       CALL_STATE_IDLE         空闲状态

       CALL_STATE_OFFHOOK 摘机状态

       CALL_STATE_RINGING   响铃状态

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

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

       Android运行log分析

       还好Android在运行时会有大量的log产生,看看我们能不能从这上面找到突波口呢?我们选择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代码

  

       通过上面这段代码我们就可以将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 开发的朋友,谢谢大家对本站的支持!


推荐阅读
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
  • Vue 2 中解决页面刷新和按钮跳转导致导航栏样式失效的问题
    本文介绍了如何通过配置路由的 meta 字段,确保 Vue 2 项目中的导航栏在页面刷新或内部按钮跳转时,始终保持正确的 active 样式。具体实现方法包括设置路由的 meta 属性,并在 HTML 模板中动态绑定类名。 ... [详细]
  • 本文探讨了如何通过最小生成树(MST)来计算严格次小生成树。在处理过程中,需特别注意所有边权重相等的情况,以避免错误。我们首先构建最小生成树,然后枚举每条非树边,检查其是否能形成更优的次小生成树。 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • 本文介绍了如何利用JavaScript或jQuery来判断网页中的文本框是否处于焦点状态,以及如何检测鼠标是否悬停在指定的HTML元素上。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • 如何在WPS Office for Mac中调整Word文档的文字排列方向
    本文将详细介绍如何使用最新版WPS Office for Mac调整Word文档中的文字排列方向。通过这些步骤,用户可以轻松更改文本的水平或垂直排列方式,以满足不同的排版需求。 ... [详细]
  • 理解存储器的层次结构有助于程序员优化程序性能,通过合理安排数据在不同层级的存储位置,提升CPU的数据访问速度。本文详细探讨了静态随机访问存储器(SRAM)和动态随机访问存储器(DRAM)的工作原理及其应用场景,并介绍了存储器模块中的数据存取过程及局部性原理。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
  • 几何画板展示电场线与等势面的交互关系
    几何画板是一款功能强大的物理教学软件,具备丰富的绘图和度量工具。它不仅能够模拟物理实验过程,还能通过定量分析揭示物理现象背后的规律,尤其适用于难以在实际实验中展示的内容。本文将介绍如何使用几何画板演示电场线与等势面之间的关系。 ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • MySQL中枚举类型的所有可能值获取方法
    本文介绍了一种在MySQL数据库中查询枚举(ENUM)类型字段所有可能取值的方法,帮助开发者更好地理解和利用这一数据类型。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
author-avatar
那年冬天2502861741
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有