最近做一个关于来去电监听然后挂断发短信功能的项目,碰到不知如何判断去电是否接通的问题,多方查询,网上的答案不一而足,最后 ,在借鉴网上的答案和自己的修改后,得出解决方案记录如下:

判断来电是否接通

这个好判断。
1. 当为来电时,电话状态首先进入TelephonyManager.CALL_STATE_RINGING 也就是 响铃 状态
2. 接通时 进入 TelephonyManager.CALL_STATE_OFFHOOK 状态,也就是接通状态
3. 当挂断时,进入TelephonyManager.CALL_STATE_IDLE 状态 ,也就是挂断状态。

所以,我们只需判断电话状态由 RINGING—>OFFHOOK时,就可以知道电话接通了。

但是当我们是拨出电话时,一拨的时候电话就会处于OFFHOOK状态,接通之后也是OFFHOOK状态,那咋办呢??

判断去电是否接通

多方查询,最后通过查询 calllog 也就是通话记录的方法,来判断电话是否拨通!

  • 本来我也对 calllog了解不多,这里给个传送门,不太了解的同学可以看看关于这方面的API 。
  • 因为android平台上的通话记录是以Content Provider的形式存储在手机上的,因此你需要使用ContentResolver来查询通话记录,返回Cursor接口。
  • 然后通过这个contentresolver 来查询通话记录的数据库 ,得到一个游标 cursor,然后通过这个游标得到我们想要的通话记录
  • 然后就可以查询到通话记录中的duration ,这就是最关键的,当duration>0的时候就说明电话接通了哈哈哈是不是也不难?!

    光说不练假把式 且看代码!

下面给出我整个类的代码,里面关于数据库啊什么的,各位就不用深究,关键看如何得到去电是否接通。
注释也较详细,各位有不懂,欢迎留言或私信

public class EndCallReceiver extends BroadcastReceiver {private RefuseComeMsgDao refuseComeMsgDao;private String content;@Overridepublic void onReceive(final Context context, Intent intent) {//获取来电号码final String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);TelephonyManager tm = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);int phoneState = tm.getCallState();switch (phoneState) {//如果电话的状态是来电响铃case TelephonyManager.CALL_STATE_RINGING:LogUtil.log("响铃!!!!");// 这里保存的是如果是来电响铃 则说明当前是来电 保存为TRUEcontext.getSharedPreferences("blacklist", MODE_PRIVATE).edit().putBoolean("iscome", true).commit();context.getSharedPreferences("blacklist", MODE_PRIVATE).edit().putBoolean("offhook", false).commit();//这里设置匹配黑名单号码  或者此时是否处于拒接时间段if (isInBlackList(number, context) || DateUtil.isRefuse(context)) {Class<TelephonyManager> telephonyManagerClass = TelephonyManager.class;try {//通过反射获取getITelephony方法Method method = telephonyManagerClass.getDeclaredMethod("getITelephony", new Class[0]);//设置该方法可访问method.setAccessible(true);//调用getITelephony方法获取ITelephony的实例ITelephony itelephony = (ITelephony) method.invoke(tm, new Object[]{});//挂断电话itelephony.endCall();//由黑名单或者拒接时间段挂断的电话,存储状态以防止重复发送短信//这里储存的状态true 表示 是主动拒接的!context.getSharedPreferences("refuseTime", MODE_PRIVATE).edit().putBoolean("dorefuse", true).commit();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (RemoteException e) {e.printStackTrace();}}break;case TelephonyManager.CALL_STATE_IDLE: //电话状态 挂断, 在这里发送 来去电短信LogUtil.log("挂断!!");//如果是来电  发送当前来电模版短信SharedPreferences preferences = context.getSharedPreferences("blacklist", MODE_PRIVATE);SharedPreferences preferences2 = context.getSharedPreferences("refuseTime", MODE_PRIVATE);boolean iscome = preferences.getBoolean("iscome", false);//是否为来电if (iscome) { //------------------------如果是来电----------------------------//--------如果是通过黑名单或者时间段拒绝的 发送拒接短信-------if (preferences2.getBoolean("dorefuse", false)) { //这个if里判断是否为主动拒接!!//先得到当前设置的拒接短信DaoSession daoSession = DBUtil.initDb(new GreenDaoContext());refuseComeMsgDao = daoSession.getRefuseComeMsgDao();RefuseComeMsg refuse1 = refuseComeMsgDao.queryBuilder().where(RefuseComeMsgDao.Properties.Type.eq("refuse")).build().unique();if (refuse1 == null) {content = "";} else {content = refuse1.getContent();}//发送拒接短信if (!content.equals("") && !content.equals("不发送")) {sendSMS(number, content, context);}// 拒接状态恢复preferences2.edit().putBoolean("dorefuse", false).commit();} else { // ---------否则发送来电短信---------String content = doGetComeMsg();//得到当前的来电回复短信if (!content.equals("不发送")) {sendSMS(number, content, context);}preferences.edit().putBoolean("iscome", false).commit();}} else if (!iscome) {//--------------------如果是去电 发送去电短信--------------------///*休眠一秒 等待通话记录写入数据库* 如果不休眠这一秒 直接查询数据库 会查询不到当前打的这个电话的记录* 因为在系统将通话记录写入数据库之前就开始查询操作 所以查到的最近的记录实际上是上一次拨打的记录* 因此休眠一秒   可能在性能垃圾的手机上1s不够 ? 不至于把 !* */new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000);boolean callLogState = getCallLogState(context,number);if (callLogState) {//----------------去电接通 执行发送去电短信操作!--------------------String content = doGetOutMsg(); //得到当前的去电回复短信if (!content.equals("") && !content.equals("不发送")) {sendSMS(number, content, context);}}} catch (InterruptedException e) {e.printStackTrace();}}}).start();}break;case TelephonyManager.CALL_STATE_OFFHOOK:LogUtil.log("OFFHOOK");break;}}/*** 获得当前的去电回复短信* @return 当前设置的去电回复模板*/private String doGetOutMsg() {String string;DaoSession daoSession = DBUtil.initDb(GreenDaoContext.getInstance());Database database = daoSession.getDatabase();CurrentTemplateDaoDao currentTemplateDaoDao = daoSession.getCurrentTemplateDaoDao();currentTemplateDaoDao.createTable(database, true); //无表就建表//查询数据库中type为out的数据CurrentTemplateDao out = currentTemplateDaoDao.queryBuilder().where(CurrentTemplateDaoDao.Properties.Type.eq("out")).build().unique();if (out != null) {string = out.getContent();} else {string = "不发送";}return string;}/*** 获得当前的来电回复短信* @return 当前设置的来电模板内容*/private String doGetComeMsg() {String string;DaoSession daoSession = DBUtil.initDb(GreenDaoContext.getInstance());Database database = daoSession.getDatabase();CurrentTemplateDaoDao currentTemplateDaoDao = daoSession.getCurrentTemplateDaoDao();currentTemplateDaoDao.createTable(database, true); //无表就建表//查询数据库中type为come的数据CurrentTemplateDao come = currentTemplateDaoDao.queryBuilder().where(CurrentTemplateDaoDao.Properties.Type.eq("come")).build().unique();if (come != null) {string = come.getContent();} else {string = "不发送";}return string;}//判断号码是否在黑名单中private boolean isInBlackList(String number, Context context) {List<BlackList> blackLists = DBUtil.getBlackListDao().loadAll();for (BlackList blackList : blackLists) {if (blackList.getNumber().equals(number)) {//匹配成功return true;}}return false;}private void sendSMS(String phoneNum, String message, Context context) {//在这里判断此号码在设置重复时段内是否重复//获取短信管理器android.telephony.SmsManager smsManager = android.telephony.SmsManager.getDefault();//拆分短信内容(手机短信长度限制)List<String> divideContents = smsManager.divideMessage(message);for (String text : divideContents) {/*** 参数4和5:* sentIntent——如果不为空,当消息成功发送或失败这个PendingIntent就广播。结果代码是Activity.RESULT_OK表示成功,或RESULT_ERROR_GENERIC_FAILURE、RESULT_ERROR_RADIO_OFF、RESULT_ERROR_NULL_PDU之一表示错误。对应RESULT_ERROR_GENERIC_FAILURE,sentIntent可能包括额外的“错误代码”包含一个无线电广播技术特定的值,通常只在修复故障时有用。* 每一个基于SMS的应用程序控制检测sentIntent。如果sentIntent是空,调用者将检测所有未知的应用程序,这将导致在检测的时候发送较小数量的SMS。* deliveryIntent——如果不为空,当消息成功传送到接收者这个PendingIntent就广播。*/smsManager.sendTextMessage(phoneNum, null, text, null, null);//将发送的信息添加到 发送记录 数据库中DBUtil.initDb(new GreenDaoContext()).getSendRecordDao().insert(new SendRecord(null, phoneNum, DateUtil.getDate(), message));}}private boolean getCallLogState(Context context,String number) {boolean isLink = false;ContentResolver cr = context.getContentResolver();PermissionChecker.checkSelfPermission(context, Manifest.permission.READ_CALL_LOG);final Cursor cursor = cr.query(CallLog.Calls.CONTENT_URI,new String[]{CallLog.Calls.NUMBER,CallLog.Calls.TYPE,CallLog.Calls.DURATION},CallLog.Calls.NUMBER +"=?",new String[]{number},CallLog.Calls.DATE + " desc");int i = 0;while(cursor.moveToNext()){if (i == 0) {//第一个记录 也就是当前这个电话的记录int durationIndex = cursor.getColumnIndex(CallLog.Calls.DURATION);long durationTime = cursor.getLong(durationIndex);
//                Log.d("test", "getCallLogState: -----------------duration= " + durationTime);if(durationTime > 0){LogUtil.log("到这里了 这是if里 durationTime = "+durationTime);isLink = true;} else {LogUtil.log("到这里了 这是else里");isLink = false;}}i++;
//            int durationIndex = cursor.getColumnIndex(CallLog.Calls.DURATION);
//            long durationTime = cursor.getLong(durationIndex);}return isLink;}}

**代码中的获取电话状态是通过AIDL实现的。
代码不是啥完美的代码,有瑕疵也欢迎吐槽。
以上。**

android 高级之旅 (十三) 真! 如何判断去电是否接通? 已解决!相关推荐

  1. JS判断浏览器版本(已解决IE11版本为Mozilla问题)

    兼容IE11的判断方式 var getExplorer = (function() {var explorer = window.navigator.userAgent,compare = funct ...

  2. android 哪个服务提示 存储设备空间不足,请释放一些空间,[已解决]Android手机上的存储空间不足怎么办?...

    第2部分:5解决方案以解决存储空间不足的错误 我的手机说存储空间不足,但我的设备上有空间.不过,我一直在手机上"存储空间不足".过了一段时间,当我意识到我无法管理设备的内部存储时. ...

  3. 我的Android进阶之旅------gt;Android字符串资源中的单引號问题error: Apostrophe not preceded by 的解决的方法...

    刚刚在string字符串资源文件里,写了一个单引號.报错了,错误代码例如以下 error: Apostrophe not preceded by \ (in OuyangPeng's blog ) 资 ...

  4. Android 高级面试

    一. Android 性能优化 1. 如何对 Android 应用进行性能分析 2. 什么情况下会导致内存泄露 3. 如何避免 OOM 异常 4. Android 中如何捕获未捕获的异常 5. ANR ...

  5. Android高级终端开发学习笔记(《疯狂Android讲义》第11章-第17章)

    Android高级终端开发笔记 2021/6/19 下午 13:34开始 多媒体应用开发 Android支持的音频格式有:MP3 WAV 3GP等.支持的视频格式有MP4 3GP等. 多媒体数据既可以 ...

  6. 我的Android进阶之旅------经典的大客推荐(排名不分先后)!!

    今天看到一篇文章,收藏了很多大牛的博客,在这里分享一下(转载于:http://blog.csdn.net/wujxiaoz/article/details/8237096) Android中文Wiki ...

  7. 我的Android进阶之旅:经典的大牛博客推荐

    Android中文Wiki AndroidStudio-NDK开发-移动开发团队 谦虚的天下 - 博客园 gundumw100博客 - android进阶分类文章列表 - ITeye技术网站 CSDN ...

  8. Android进阶之旅:经典的大牛博客推荐

    Android中文Wiki AndroidStudio-NDK开发-移动开发团队 谦虚的天下 - 博客园 gundumw100博客 - android进阶分类文章列表 - ITeye技术网站 CSDN ...

  9. android高级面试题,有难度

    作者:Focusing 链接:https://juejin.im/post/5c984e926fb9a070c975a9b4 Android进阶延伸点 1.如何进行单元测试,如何保证App稳定 ? 参 ...

最新文章

  1. 手把手教你看懂并理解Arduino PID控制库——调参改变
  2. HttpWebRequest WebResponse 对象简单了解
  3. 用费曼技巧自学编程,香不香?
  4. 10-4 5-4 查询至少生产三种不同速度PC的厂商 (20 分)
  5. P6240 好吃的题目(分治+背包)
  6. 获取url参数值(可解码中文值)
  7. 搜索算法(二)--DFS/BFS求解炸弹人问题(JAVA )
  8. Redis管理及监控工具treeNMS
  9. 2013Esri全球用户大会QA之Esri公司概况及未来发展
  10. 软考-系统分析师-论文写作-备考总结笔记
  11. 规范完整APP开发制作流程
  12. C/C++程序设计与算法第十一周:零点定理求方程的根
  13. 第二周——学习内存取证神器volatility的使用
  14. 首台android手机号码,国内首批手机Android 12尝鲜列表已公布,华为与荣耀不在名单之上...
  15. 力扣K神图解算法数据结构解析04
  16. 知识图谱推理:现代的方法与应用
  17. 【日记】 使用 zip4j 实现压缩包加密
  18. src中的 “/”、“./”与“../”
  19. Linux 下 find(文件查找)命令的用法总结
  20. Halcon读图出错怎么办?ReadImage常见错误与处理方法(C++)

热门文章

  1. 引气管理计算机失效,A320飞机解码排故应用之发动机引气失效
  2. 我对锤子ROM 功能的看法——功能篇——高效整理桌面图标
  3. 移动端 H5 相关疑难总结
  4. 程序员兼职的几大网站--点赞收藏
  5. Coderforces 字符串水题合集
  6. 软件包ipython没有可安装候选_解决python 自动安装缺少模块的问题
  7. 华瑞IT教育|校园成人礼满满的青春味
  8. Hyperledger Fabric 通道配置文件和容器环境变量详解
  9. 遭卡巴斯基查杀 致大量瑞星卡卡用户无法升级
  10. vanilla js_本周我们的雷达上:黑色星期五赠品和Vanilla JS