码迷,mamicode.com
首页 > 移动开发 > 详细

手机卫士06_挂电话拦截短信,资产目录_来电去电_自定义吐司

时间:2016-06-15 23:48:04      阅读:416      评论:0      收藏:0      [点我收藏+]

标签:

1.1 反射调用系统隐藏api挂掉电话

Android 1.5之前可以通过 TelephonyManager,tm.endCall();//但是列表找不到

谷歌认为挂掉电话是危及手机根本功能的动作,所以隐藏了这个api

1.5之后,要通过反射调用这一api才能实现

 

两个网站

www.greocide.com //搜索源码的网站

搜索TelephonyManager,查找版本最低的版本即可(越低越容易理解)

这个api被隐藏掉了,不能直接获取到TelephonyManager.对象.

②通过getSystemService(参数) //获取的是代理人对象的包装.连代理对象都不能直接拿到.

一般情况直接用代理人对象的代理人对象就行,但是特殊情况就需要代理人对象

Call()方法,endCall()方法,都可以通过代理人对象调用

 

1.2 实现步骤:

 ①通过反射获取ServiceManager(这个类被系统隐藏了)

Class clazz = getClassLoader().loadClass("android.os.ServiceManager");

Method method = clazz.getDeclaredMethod(方法名(getService),参数字节码(String.class));

//获取公开的方法

IBinder ibinder =Method.invoke(null(静态方法可以为null),Context.TELEPHONY_SERVICE(参数));

//返回的是一个代理人对象,记得要强转,

 

远程绑定服务,需要拷贝aidl及其对应的包名称

② 网站二,androidxref.com//可以获取所有的安卓源码,把上面的路径下aidl文件拷贝出来

拷贝代码中的包名,在项目下创建

③ITelephony代码报错,导包不存在NeihboringCallInfo,同样在网站上可以找到这个aidl文件代码.

④ITelephony itelephony = ITelephony.Stub.asInterface(iBinder);

itelephony.endCall()可以挂断电话

⑤CALL_PHONY 的权限声明

 

1.3, 即使拦截了黑名单号码,但是通话记录上可以查询(因为只是黑名单号码被挂断了,还是有记录)

目标:删除黑名单号码对应的通话记录.

呼叫记录在contectz2.db数据库中(com.android.providers.contacts包),通过工具打开它

映射表报错,不用管它

查看对应的通话记录表:calls表 列type 1,呼入,2打出去,3未接电话;列number,电话号码.

通过内容提供者获取

①获取联系人的内容提供者,ContentResolver resolver = getContentResolver()

//获取内容提供者解析器

②//uri:   content://源码的清单文件CallLogProvider中主机名//查看CallLogProvider中的uri匹配器,获得想要查找表的匹配名.

 

 Resolver.delete(URI,选择语句,对应参数);

<provider android:name="CallLogProvider"

            android:authorities="call_log"

            android:syncable="false" android:multiprocess="false"

            android:readPermission="android.permission.READ_CONTACTS"

            android:writePermission="android.permission.WRITE_CONTACTS">

        </provider>

③WRITE_CALL_LOG,READ_CALL_LOG //添加两个权限读写通话记录权限

额外:无法删除新的呼叫记录,删除的是上一条黑名单呼叫记录

因为endCall()调用的是系统底层的服务挂断电话,是通过另一个服务,而通过内容提供者另一个底层服务去删除,两个动作并不是在同一时刻完成的,可能会出现删除动作执行完了,呼叫记录才生成.

可以通过sleep(xxx秒)去延迟操作,但是无法确定用户手机的反应速度,所以通过内容观察者去监视.

④resolver.registerContentObserver(uri,this,new ContentObserver(){重写onChanger(

在这里删除记录即可

)});

 

1.4 短信拦截的功能实现

通过代码注册广播接收者,用户可以控制这个广播接收者.

①在拦截骚扰服务类中,定义一个内部的广播接收者(不需要配置清单文件)(这样服务启动,广播接收者存在,服务关闭,广播接收者不存在,就不会一直在后台监听短信事件了.)

②在服务类的onCreate方法中.

定义意图过滤器,addAction(),setPriorty(优先级IntentFilter.SYSTEM_HIGH_PRIORITY)

registerReceiver(需要注册的广播接收者对象,意图过滤器);

③在服务停止的方法中取消注册即可unregisterReceiver(对象),对象=null,即可

这样服务内部广播接收者就能和服务共存亡了,23333

④在广播接收者中,获取到

intent.getExtra.get(“pdus”)//Object[]的数组,遍历转换成SmsMessage对象

SmsMessage.getOriginatingAddress();//获取原始发件人

判断它是否在黑名单数据库,是否匹配上了拦截模式,最后拦截掉它

额外:①即使短信被拦截掉了,也应该被存储下来,因为用户有时候还是想看到的.

创建一个表,保存拦截的短信即可(保存发送者和短信体即可)

②关键字拦截:判断短信体中是否保存被拦截的关键字.然后拦截即可..

中文辣鸡短信的拦截原理:分词技术:java分词框架 lucence

 

1.5 拦截骚扰的其它需求

①修改黑名单拦截状态:长按条目出现对话框,出现修改拦截模式的条目

(点击事件,持续XX秒后弹出对话框,对话框还要自定义,干脆改成圆角得了,卧槽)

②白名单模式:正好与黑名单相反,这个....就算了吧,懒得实现.

 

2.常用工具界面:CommomTools

界面工具:号码归属地查询,占位2,占位3,参考设置中心的界面(直接Copy啊)

①home界面条目点击事件的跳转

2.1号码归属地查询的数据库(淘宝上几块钱就能买到)

不过买到的可能是纯文本,可以写一段java代码全部写到数据库表中.

号码归属地通过号码的前七位就可以判断出来.

2.2 数据库中有两个表,一个号码表(号码前七位+类别),一个归属地对照表(通过类别判断),

2.3 外部数据库的拷贝代码实现:

①在CommonTools工具大全界面中,点击条目跳转到号码查询的界面

参考ui

②数据库的拷贝,把.db数据库放到assets(资产目录),该目录下,可以放置一些别的文件,这些文件当做资产放在资产目录下.

查看.apk中的文件,可以发现资产文件打包的时候,就是原封不动的放在assets文件夹下

③getAssets()(获取资产目录).open(资产文件名)//返回一个输入流

④通过输入流把文件通过输出流写到私有目录下(getFIleDir(),文件名);

⑤流对接把资产文件写到自己的私有目录下.

//模板代码,可以考虑抽取出来做成工具

额外:①这种拷贝文件到系统目录的操作可能会比较耗时:放到子线程

②这一操作属于数据的初始化,可以放到splash代码中,在拷贝之前判断文件是否存在且长度大于0;

 

2.4 查询代码的实现

外部数据库的使用,不再需要openHelper,直接定义dao类即可.

①打开数据库,SQLiterDatabase.openDatabase(path(文件路径),游标工厂,打开方式(可读可写))

//返回一个数据库对象.

②执行 SQL语句查询,对号码进行截取前七位,返回结果(这里通过rawQuery写sql语句比较灵活,可以一次查询两个表,而不用先获取类型,再查询另一个表)

参考select * from data2 where id = (select outkey(类型) from data1 where id = ?(电话前七位))

额外:固定号码的查询异常:因为设置的是前七位,固定号码没有七位,或者有区号就查询不出来了.

解决方式:在Dao查询的方法里添加判断

①判断是否是手机号码

正则:^1[34578]\\d{9}$ //1[34578]+9位数字

不是手机号就根据对应的长度获取

3位110,119,120

4位 模拟器

5位 商业客服电话

7位 本地电话

8位 本地电话

②Default:位数大于0位,并且以0开始 的看做长途电话 表中的对照data2表area属性可以查询到长途电话的归属地(但是不区分联通,移动)

查询的时候记得截取从第一位开始,不要截取0 //前三位和前四位各查询一次.

查询的结果把运营商截取掉,因为区分不了(当然如果数据库能区分最好)

 

2.5 用户体验的优化

①用户输入文本后,就直接显示,而不是点击按钮

//注册文本变化的监听器

Et_number.addTextChangedListener(new TextWatcher(){

onTextchanged(CharSequence s,int start,int before,int count)//文本发生变化调用的方法

//优化:当字符串长度大于10才做判断

s就是变化的字符队列,toString() 转换成字符串.

beforeTextChanged()//变化之前调用

afterTextChanger()//变化之后调用s

});

 

②当数值为空的时候,点击查询只是显示查无此号,用户体验不好

查看系统自带的api demo>>Views/Animation/Shake 如果内容为空,点击查询的话,框框会抖动.

系统自带了很多高端的api demo,可以复制使用

③复制api demo的源码即可

导入api demo的源码>>创建Android Project from Existing Code导入即可

导入会报错:样式文件出错,把报错的删掉就可以了.

快速定位代码:eclipst ctrl+h 全部搜索,搜索文件中的内容(搜索想要的效果上特殊文本)

这里会找到布局文件,然后搜索它的id就行了,然后会发现最重要的逻辑就是一个动画,拷贝它!

拷贝一下这个动画anim文件夹下的文件,报错:缺少另一个资源,把它也拷贝过来即可.

最后调用即可,这里的另一个资源代表抖动的次数

 

3.0 来电号码归属地的显示

需求希望在接收到电话之后,响铃界面会显示出来号码归属地.

本质是在响铃界面显示一条吐司,它能显示在所有页面最上方.

①在设置中心的增加一条设置,就是开关号码归属地显示.

②这一行为需要在后台长期运行,来电就被启动,故而创建一个服务类,参考拦截骚扰的服务类.

判断状态,回显开关,开启,关闭服务.

③获取电话状态的监听服务,在销毁的方法里取消监听.

④在监听器的继承类中,重写onCallStateChanged()方法,调用归属地的数据库,查询归属地.

最后通过吐司显示出来.

 

4.0 拨打号码归属地的实现

上面的方式是无法显示拨打号码的归属地,因为监听器的功能并没有那么强大.

它监听的是响铃,空闲,和通话状态.

所以通过外播电话的广播事件开发,接收这个广播,然后显示归属地即可.

①这个广播接收者定义在来电显示的服务类中,然后通过代码注册即可.

intentfilter.addAction(Intent.Action_NEW_OUTGOING_CALL);

服务销毁,反注册广播接收者

②广播接收者生效的时候,getResultData()获取号码,最后显示吐司

③记得加权限PXXXX_AUTOGOING_CALL

 

5.自定义吐司

查看吐司源代码:

按住ctrl + k 可以快速定义代码出现的下一个位置

可以发现吐司中的mtn继承了一个远程服务的对象

INotificationManager //通知管理的服务

WindowManager //窗体管理器的接口 mwm

mwn.addView(添加一个view到窗体上),removeView(在窗体上删除一个view)

定义一个方法:自定义吐司的显示

①需要往窗体上显示内容,定义一个窗体管理器WindowManager wm

Wm = context . getSystemService(WINDOW_SERVICE);//返回窗体的服务

②定义一个view对象,设置好参数

③wm.addView(view,LayoutParams布局参数)

系统吐司是通过窗体管理器获取LayoutParams(),可以拷贝它的params参数

额外:通过判断通话状态来addView()和removeView();移除的时候判断是否为空,移除之后=null;.

拷贝的时候不要漏行了,会报异常WindowManager&BadTokenException:Unable to add window token null is not for an application.

参考如下

WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);

WindowManager.LayoutParams params = new LayoutParams();

   params.height = WindowManager.LayoutParams.WRAP_CONTENT;

           params.width = WindowManager.LayoutParams.WRAP_CONTENT;

           params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE

                   | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE

                   | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;

           params.format = PixelFormat.TRANSLUCENT;

           params.type = WindowManager.LayoutParams.TYPE_TOAST;

wm.addView(stv,params );

 

 

 

 

 

 

手机卫士06_挂电话拦截短信,资产目录_来电去电_自定义吐司

标签:

原文地址:http://www.cnblogs.com/adventurer/p/5589334.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!