Android项目:手机安全卫士(13)—— 通讯卫士之电话拦截与挂断
2016-03-17 17:19
756 查看
Android项目:手机安全卫士(13)—— 通讯卫士之电话拦截与挂断
1 介绍
上一节我们讲了黑名单数据的存储等 CRUD 操作,今天,就到了它们发挥作用的时候了,通讯卫士功法终于要练成了。我们实现了手机的短信、电话拦截功能。关于项目相关文章,请访问:
Android 项目:手机安全卫士(7)—— 手机防盗功能
Android 项目:手机安全卫士(8)—— 管理员权限
Android 项目:手机安全卫士(9)—— 手机号码归属地查询
Android 项目:手机安全卫士(10)—— 电话归属地显示
Android 项目:手机安全卫士(11)—— 归属地提示框拖拽效果
Android 项目:手机安全卫士(12)—— 通讯卫士之电话、短信黑名单设置与拦截
项目源码地址(实时更新):https://github.com/xwdoor/MobileSafe
2 添加拦截服务的设置菜单
在设置界面,添加一个 Item,用于设置是否开启黑名单拦截服务,效果如下:聪明如你,不知道有没有发现,我们的设置界面已经越来越完善了,Item 也越来越多咯,哈哈。这里给出它的后台代码:
/** 初始化黑名单设置 */ private void initBlackNumber() { final SettingItemView sivBlackNumber = (SettingItemView) findViewById(R.id.siv_black_number); // 根据服务是否运行来更新checkbox boolean serviceRunning = ServiceStatusUtils.isServiceRunning(this, "net.xwdoor.mobilesafe.service.BlackNumberService"); sivBlackNumber.setChecked(serviceRunning); sivBlackNumber.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sivBlackNumber.setChecked(!sivBlackNumber.isChecked()); Intent service = new Intent(getApplicationContext(), BlackNumberService.class); if(sivBlackNumber.isChecked()){ startService(service); }else { stopService(service); } } }); }
每次进入设置界面都会初始化,判断拦截服务是否开启,从而设置选中状态。然后根据用户的设置情况,实时开启或停止服务。当然,再次之前,咱们需要创建一个 Service:BlackNumberService,这个工作比较简单,使用 Android Studio 的“自动化服务”开始创建:
/** * 黑名单服务 * * Created by XWdoor on 2016/3/17 017 13:41. * 博客:http://blog.csdn.net/xwdoor */ public class BlackNumberService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); //拦截短信 // 拦截电话 } @Override public void onDestroy() { super.onDestroy(); //停止监听短信 // 停止监听来电 } }
BlackNumberService 主要用于黑名单的电话与短信拦截,下面就来一一讲解。
3 黑名单短信拦截
先来做短信拦截的服务,这个比较简单,我记得,前面实现手机防盗功能的时候,我们也用了短信监听与拦截功能,这次的代码差不多,我们只要稍作修改,符合业务需求即可。创建广播 BlackNumberSmsReceiver:/** * 监听短信广播:黑名单监听 * * Created by XWdoor on 2016/3/17 017 14:03. * 博客:http://blog.csdn.net/xwdoor */ public class BlackNumberSmsReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Object[] pdus = (Object[]) intent.getExtras().get("pdus"); for (Object pdu : pdus) { SmsMessage message = SmsMessage.createFromPdu((byte[]) pdu); String address = message.getOriginatingAddress(); String msg = message.getMessageBody(); BlackNumberDao mNumberDao = BlackNumberDao.getInstance(context); boolean exist = mNumberDao.find(address); if (exist) {// 在黑名单中 // 1, 2, 3 int mode = mNumberDao.findMode(address);// 获取拦截模式 if (mode > 1) {// 2, 3才拦截 abortBroadcast(); } } mNumberDao = null; } } }
哈哈,也就几行代码嘛,这里我们只做了最简单的拦截,就是根据电话号码进行拦截:若短信号码存在黑名单中,则拦截短信。还有一个问题,就是 abortBroadcast() 方法可能在高版本中就不够用了,还需要查询存储短信的数据库,然后删除数据库中的数据。
有了 BlackNumberSmsReceiver 广播,就可以在服务 BlackNumberService 中实现骚扰短信的拦截功能,在 onCreate() 方法中添加以下代码:
//拦截短信 IntentFilter filter = new IntentFilter(); filter.addAction("android.provider.Telephony.SMS_RECEIVED"); filter.setPriority(Integer.MAX_VALUE); mSmsReceiver = new BlackNumberSmsReceiver(); // 同等条件下, 动态注册的广播比静态注册的更先获取广播内容 registerReceiver(mSmsReceiver,filter);
服务开启的时候开启短信拦截服务,同样的,在服务停止的时候,需要关闭短信拦截服务,在 onDestroy() 方法中添加以下代码:
//停止监听短信 unregisterReceiver(mSmsReceiver); mSmsReceiver = null;
4 黑名单电话拦截与挂断
接下来就是本文的重点了,实现了短信拦截,就轮到电话拦截了。首先在 BlackNumberService 服务中实现电话监听的功能,在 onCreate() 方法中添加以下代码:// 拦截电话 mTM = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); mPhoneListener = new BlackNumberPhoneListener(this); mTM.listen(mPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
同时,在 onDestroy() 方法中添加以下代码,用于停止监听电话:
// 停止监听来电 mTM.listen(mPhoneListener,PhoneStateListener.LISTEN_NONE);
监听电话需要传入一个 PhoneStateListener 对象,这里我们创建一个类 BlackNumberPhoneListener,继承自 PhoneStateListener,同时复写它的 onCallStateChanged() 方法,代码如下:
@Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); switch (state){ case TelephonyManager.CALL_STATE_RINGING://电话铃响 boolean exist = mNumberDao.find(incomingNumber); if(exist){//黑名单中有该号码 int mode = mNumberDao.findMode(incomingNumber); if (mode == 1 || mode == 3) { //拦截该号码:挂断电话 endCall(); } } break; case TelephonyManager.CALL_STATE_OFFHOOK://电话摘机 break; case TelephonyManager.CALL_STATE_IDLE://电话空闲 break; } }
当监听到需要拦截的电话时,就需要挂断电话,这个功能实现起来比较复杂,先说思路:在 android 1.X 版本中的 TelephonyManager 有一个 api 接口:endCall(),调用它就可以直接挂断电话,但是马上,google 在 2.X 以上的版本中隐藏了这个 api,因为这个操作太敏感了,这里需要注意,是隐藏 api,而不是删除哦,我们的办法就是想方设法的调用 endCall() 这个方法。至于怎么调用,你先看看代码:
/** 挂断电话 需要权限:android.permission.CALL_PHONE */ private void endCall() { try { // TelephonyManager.endCall(); // IBinder b = ServiceManager.getService(ALARM_SERVICE); // IAlarmManager service = IAlarmManager.Stub.asInterface(b); // ServiceManager 被隐藏了,需要通过反射来调用 // IBinder b = ServiceManager.getService(TELEPHONY_SERVICE); Class<?> aClass = Class.forName("android.os.ServiceManager");//通过反射找到ServiceManager Method method = aClass.getMethod("getService", String.class);//找到ServiceManager的静态方法getService IBinder b = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);//调用getService()方法,得到IBinder对象 ITelephony service = ITelephony.Stub.asInterface(b);//得到TelephonyManager接口 service.endCall(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } }
每句代码我都写了注释,以免以后查阅。通过查看 android 的源代码得知,每次我们调用 getSystemService() 方法时,系统都是通过调用 ServiceManager 类的静态方法 getService() 得到 IBinder 对象,从而得到相应的服务。所以,我们就按照这个思路走,首先,我们通过 java 的反射机制找到 ServiceManager 对象;然后通过 getMethod() 方法找到 getService() 方法;然后调用该方法得到对应的 IBinder 对象,从而得到 TelephonyManager 中的 ITelephony 对象;最后就是调用 endCall() 方法了。
需要声明一下,关于 IBinder、ITelephony、Stub 什么的,我目前也不太懂,相信随着学习的加深,以后肯定会接触的。还有一点就是,使用 IBinder、ITelephony 等接口类需要用到两个 AIDL 文件,这两个文件我的项目中有,需要说明的是,它们的存放位置有点技巧,需要存放在 aidl 目录中,且该目录是与 java 同一级别的目录,说的有点抽象,看看下面的图片就一目了然了,注意,创建了很多 package 哦:
接下的工作就是…什么,你觉得这就结束了吗,不可能,哪有这么简单。以上代码不仅需要权限:
<uses-permission android:name="android.permission.CALL_PHONE" />,测试后还发现,虽然电话成功拦截了,但是打开通话记录,还能看到被拦截的电话的记录,所以自己挖的坑,还得自己填,我们需要删除通话记录。
5 删除通话记录
调用 endCall() 方法后,传入一个观察者:BlackNumberLogObserver,继承自 ContentObserver,注册观察者的代码如下:// 注册内容观察者,观察通话记录表的变化 mObserver = new BlackNumberLogObserver(new Handler(), incomingNumber); mContext.getContentResolver().registerContentObserver( Uri.parse("content://call_log/calls"), true, mObserver);
类 BlackNumberLogObserver 需要重写 onChange() 方法,用于删除通讯录,以及注销观察者:
// 表的数据发生变化会回调此方法 @Override public void onChange(boolean selfChange) { super.onChange(selfChange); deleteCallLog(number); // 注销观察者 mContext.getContentResolver().unregisterContentObserver(mObserver); } /** * 删除通话记录 * * 需要权限: * <uses-permission android:name="android.permission.READ_CALL_LOG" /> * <uses-permission android:name="android.permission.WRITE_CALL_LOG" /> * * @param number 电话 */ private void deleteCallLog(String number) { // 和联系人是一个数据库 mContext.getContentResolver().delete(Uri.parse("content://call_log/calls"), "number = ?", new String[]{number}); }
到此,我们的电话拦截才告一段落,可以轻松一下了。
6 总结
今天的内容我认为全是干货啊,特别是电话拦截挂断的功能,以后可以直接拿来用了,省去了不少事。关于项目相关文章,请访问:
Android 项目:手机安全卫士(7)—— 手机防盗功能
Android 项目:手机安全卫士(8)—— 管理员权限
Android 项目:手机安全卫士(9)—— 手机号码归属地查询
Android 项目:手机安全卫士(10)—— 电话归属地显示
Android 项目:手机安全卫士(11)—— 归属地提示框拖拽效果
Android 项目:手机安全卫士(12)—— 通讯卫士之电话、短信黑名单设置与拦截
项目源码地址(实时更新):https://github.com/xwdoor/MobileSafe
相关文章推荐
- Android设计模式-常用模式
- android lint选项含义
- 《Android和PHP最佳实践》官方站
- Android6.0源码分析—— Zygote进程分析(补充)
- Android的布局Layout
- Android-Universal-Image-Loader 源码 浅析
- Android设计模式-MVC模式设计
- Android自定义时间选择器
- 手把手教你实现百度基础地图+定位功能+设置中心点+添加Marker
- 【Android技巧】通过am完成发送开机广播等操作
- Android文件下载任务
- Android 创建指定位置和大小的PopupWindow,带进入和退出动画
- android设备信息获取
- 对多线程下载文件的理解和使用ksoap2-android调用WebService的操作步骤
- android 提前知道textview的宽度
- View的事件分发
- android textview 显示表情和文字 表情带超链接
- android 自定义组件中常用的方法
- android 自定义组件中常用的方法
- GitHub 上排名前 100 的 Android 开源库进行简单的介绍