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

作者:lqh 时间:2022-01-10 23:56:58 

有些手机在电话接通后会有振动提示,这有个好处就是可以等到接通后再放到耳边接听,减少辐射。本文就讲讲如何在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代码

<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 开发的朋友,谢谢大家对本站的支持!

标签:Android,电话,振动提示
0
投稿

猜你喜欢

  • Eclipse项目有红感叹号的解决方法

    2023-02-13 10:54:15
  • Android Studio安装配置方法图文详细教程

    2023-01-08 23:10:16
  • Android自定义滑动解锁控件使用详解

    2022-08-20 05:36:38
  • C#使用Object类实现栈的方法详解

    2021-08-03 17:36:16
  • android canvas使用line画半圆

    2022-01-05 17:58:57
  • java实现字符串四则运算公式解析工具类的方法

    2021-11-03 09:22:23
  • Android Volley框架使用方法详解

    2022-04-07 09:06:49
  • java加密算法分享(rsa解密、对称加密、md5加密)

    2021-08-30 16:22:08
  • Java重写equals及hashcode方法流程解析

    2023-10-14 06:53:13
  • android中TabHost的图标(48×48)和文字叠加解决方法

    2023-05-19 14:13:28
  • Java 多线程传值的四种方法

    2022-02-03 08:16:44
  • MAC上IntelliJ IDEA的svn无法保存密码解决方案

    2022-11-10 13:54:12
  • Android实现背景图滑动变大松开回弹效果

    2022-10-15 10:45:15
  • mybatis-plus之如何实现in嵌套sql

    2023-02-11 14:57:57
  • 一篇文章带你深入了解Java基础(2)

    2023-12-09 21:06:23
  • MyBatis-Plus逻辑删除和字段自动填充的实现

    2023-01-08 03:45:54
  • Java详细分析讲解泛型

    2023-02-05 07:56:02
  • Unity3D实现NavMesh导航网格寻路

    2021-07-29 05:38:18
  • Mybatis中的resultType和resultMap查询操作实例详解

    2022-02-24 17:05:42
  • c#中Winform实现多线程异步更新UI(进度及状态信息)

    2022-08-26 05:54:40
  • asp之家 软件编程 m.aspxhome.com