标签:
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