内容观察者 ContentObserver 监听短信、通话记录数据库 挂断来电
Activity
public class MainActivity extends ListActivity {private TextView tv_info;private SMSContentObserver smsContentObserver;private CallLogObserver callLogObserver;private PhoneStateReceiver myReceiver;@SuppressLint("HandlerLeak")private Handler mHandler = new Handler() {public void handleMessage(Message msg) {String msgBody = (String) msg.obj;tv_info.setText(msg.obj + ":" + msgBody);}};protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);String[] array = { "注册短信数据库变化的观察者", "收件箱数据库……", "删除新来电的通话记录", "监听新来电通话记录的详细信息", "取消注册Observer",//"注册电话状态改变的广播,当有来电时立即挂断电话", "取消注册广播", };for (int i = 0; i < array.length; i++) {array[i] = i + "、" + array[i];}ListAdapter mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>(Arrays.asList(array)));tv_info = new TextView(this);// 将内容显示在TextView中tv_info.setTextColor(Color.BLUE);tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);tv_info.setPadding(20, 10, 20, 10);getListView().addFooterView(tv_info);setListAdapter(mAdapter);myReceiver = new PhoneStateReceiver();}@Overrideprotected void onListItemClick(ListView l, View v, int position, long id) {switch (position) {case 0:smsContentObserver = new SMSContentObserver(mHandler, this, SMSContentObserver.MSG_SMS_WHAT);getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, smsContentObserver);// boolean notifyForDescendents(后裔):若为true,则监视所有以指定的Uri开头的Uri;若为false,则只精确的监视指定的URIbreak;case 1:smsContentObserver = new SMSContentObserver(mHandler, this, SMSContentObserver.MSG_SMS_INBOX_WHAT);getContentResolver().registerContentObserver(Uri.parse("content://sms/inbox"), true, smsContentObserver);break;case 2:callLogObserver = new CallLogObserver(mHandler, this, CallLogObserver.MSG_CALLLOG_DELETE_WHAT);getContentResolver().registerContentObserver(Uri.parse("content://call_log/calls"), true, callLogObserver);break;case 3:callLogObserver = new CallLogObserver(mHandler, this, CallLogObserver.MSG_CALLLOG_QUERY_WHAT);getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URI, true, callLogObserver);//等价于【Uri.parse("content://call_log/calls")】break;case 4:if (smsContentObserver != null) getContentResolver().unregisterContentObserver(smsContentObserver);if (callLogObserver != null) getContentResolver().unregisterContentObserver(callLogObserver);break;case 5:registerReceiver(myReceiver, new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED));break;case 6:try {unregisterReceiver(myReceiver);} catch (Exception e) {}break;}}/*** 利用aidl及反射自动挂断来电。注意,不能通过ContentResolver监听通话记录数据库来挂断电话,估计是因为电话已接通,不能再挂掉了*/public void endCall() {// IBinder iBinder = ServiceManager.getService(TELEPHONY_SERVICE);//希望调用的方法,但此方法被系统隐藏了try {Class<?> clazz = Class.forName("android.os.ServiceManager");//利用反射拿到其字节码文件Method method = clazz.getDeclaredMethod("getService", String.class);//获取ServiceManager类的getService(String s)方法IBinder ibinder = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);//参数为:调用此方法的对象,此方法的参数ITelephony telephony = ITelephony.Stub.asInterface(ibinder);//把上面getService(String s)得到的IBinder对象转化成【ITelephony】对象boolean isSuccess = telephony.endCall();//调用ITelephony挂断电话的方法mHandler.sendMessage(Message.obtain(mHandler, 5, "是否成功挂断电话:" + isSuccess));} catch (Exception e) {mHandler.sendMessage(Message.obtain(mHandler, 5, "异常啦" + e.getMessage()));e.printStackTrace();}}/**监听来电状态的广播*/class PhoneStateReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {if (intent != null) {if (TelephonyManager.EXTRA_STATE_RINGING.equalsIgnoreCase(intent.getStringExtra(TelephonyManager.EXTRA_STATE))) {//来电状态endCall();}}}}}
短信数据库的ContentObserver
/**监听或获取手机短信内容的两种方式* 方式一:通过注册广播监听短信* 这种方式只对新收到的短消息有效,并且系统的这个广播是有序广播,现在在一些定制的系统或是有安全软件的情况下,往往短消息都被截取到,并被干掉。* 方法二:通过监听短信数据库的变化获取短信* 这种方式可以获取手机上所有的短信,包括已读未读的短信,并且不受其它程序干扰* ContentObserver的使用类似与设计模式中的观察者模式,ContentObserver是观察者,被观察的ContentProvider是被观察者。* 当被观察者ContentProvider的数据发生了增删改的变化,就会及时的通知给ContentProvider,ContentObsserver做出相应的处理。*/public class SMSContentObserver extends ContentObserver {private Handler mHandler;private Context mContext;/**观察类型:所有内容或仅收件箱*/private int observerType;/**观察所有内容*/public static final int MSG_SMS_WHAT = 1;/**仅观察收件箱*/public static final int MSG_SMS_INBOX_WHAT = 2;public SMSContentObserver(Handler handler, Context context, int observerType) {super(handler);this.mHandler = handler;this.mContext = context;this.observerType = observerType;}@Overridepublic void onChange(boolean selfChange) {super.onChange(selfChange);if (observerType == MSG_SMS_WHAT) {Uri uri = Uri.parse("content://sms");Cursor cursor = mContext.getContentResolver().query(uri, new String[] { "_id", "address", "body", "type", "date" }, null, null, "date desc");if (cursor != null) {if (cursor.moveToFirst()) { //最后收到的短信在第一条. This method will return false if the cursor is emptyint msgId = cursor.getInt(cursor.getColumnIndex("_id"));String msgAddr = cursor.getString(cursor.getColumnIndex("address"));String msgBody = cursor.getString(cursor.getColumnIndex("body"));String msgType = cursor.getString(cursor.getColumnIndex("type"));String msgDate = cursor.getString(cursor.getColumnIndex("date"));String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date(Long.parseLong(msgDate)));String msgObj = "收件箱\nId:" + msgId + "\n号码:" + msgAddr + "\n内容:" + msgBody + "\n类型:" + msgType + "\n时间:" + date + "\n";mHandler.sendMessage(Message.obtain(mHandler, MSG_SMS_WHAT, msgObj));}cursor.close();}} else if (observerType == MSG_SMS_INBOX_WHAT) {Uri uri = Uri.parse("content://sms/inbox");Cursor cursor = mContext.getContentResolver().query(uri, null, "read = 0", null, "date desc");//Passing null will return all columns, which is inefficient.//等价于附加条件 if (cursor.getInt(cursor.getColumnIndex("read")) == 0) //表示短信未读。这种方式不靠谱啊,建议用上面的方式!if (cursor != null) {StringBuilder sb = new StringBuilder("未读短信\n");while (cursor.moveToNext()) {String sendNumber = cursor.getString(cursor.getColumnIndex("address"));String body = cursor.getString(cursor.getColumnIndex("body"));sb.append("号码:" + sendNumber + "\n内容:" + body + "\n");}mHandler.obtainMessage(MSG_SMS_INBOX_WHAT, sb.toString()).sendToTarget();cursor.close();}}}}
利用反射及aidl调用系统隐藏的方法
目的:利用反射及aidl调用系统隐藏的ServiceManager的getService方法,获取ITelephony后调用其挂电话的方法步骤:1、copy android源代码【com.android.internal.telephony】包中的【ITelephony.aidl】到自己的项目为什么要copy这个文件呢?这是因为接听/挂断电话的方法在接口ITelephony.java里面,而这个接口是隐藏的(@hide),我们没权限调用。2、由于ITelephony.aidl关联了【android.telephony】包下的【NeighboringCellInfo.aidl】,所以也需把它拷贝过来。上面完成之后,就会在你的gen目录下自动生成 ITelephony.java接口文件
3、然后我们就可以利用反射机制来取得ITelephony对象。为什么要用反射呢?因为 ITelephony是一个系统服务,要通过【ServiceManager】来获取,但是ServiceManager同样也是隐藏的。所以,我们首先要通过反射机制拿到系统隐藏的ServiceManager对象然后调用ServiceManager的【getService(String)】方法来取得远程的【ITelephony】对象, 最后调用ITelephony的endCall()方法挂掉电话权限:<uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.CALL_PHONE" />
通话记录数据库的Observer
/*** 拨号记录的内容观察者。*/public class CallLogObserver extends ContentObserver {/**观察到记录改变后的处理方式*/private int type;/**删除最近的一条通话记录*/public static final int MSG_CALLLOG_DELETE_WHAT = 3;/**查询某一个联系人最近的通话记录*/public static final int MSG_CALLLOG_QUERY_WHAT = 4;public static final String NUMBER = "17084143285";private Handler mHandler;private Uri uri = CallLog.Calls.CONTENT_URI;//等价于【Uri.parse("content://call_log/calls")】private ContentResolver resolver;public CallLogObserver(Handler handler, Context context, int type) {super(handler);this.mHandler = handler;this.type = type;resolver = context.getContentResolver();}@Overridepublic void onChange(boolean selfChange) {Cursor cursor;switch (type) {case MSG_CALLLOG_DELETE_WHAT://删除最近的一条通话记录resolver.unregisterContentObserver(this);//注意:增删改通话记录后由于数据库发生变化,所以系统会在修改后再发一条广播,这时会重新回调onChange方法//最终导致的结果就是:一次来电后删除了多条甚至全部通话记录。为防止这种循环启发,必须在更改前就取消注册!事实上,注册的代码应该放在广播接收者中。cursor = resolver.query(uri, null, null, null, "_id desc limit 1");//按_id倒序排序后取第一个,即:查询结果按_id从大到小排序,然后取最上面一个(最近的通话记录)if (cursor != null) {if (cursor.moveToFirst()) {int num = resolver.delete(uri, "_id=?", new String[] { cursor.getInt(cursor.getColumnIndex("_id")) + "" });mHandler.sendMessage(Message.obtain(mHandler, MSG_CALLLOG_DELETE_WHAT, "删除的记录数量:" + num));}cursor.close();}break;case MSG_CALLLOG_QUERY_WHAT://查询某一个联系人最近的通话记录String[] projection = new String[] { "_id", CallLog.Calls.TYPE, CallLog.Calls.NUMBER, CallLog.Calls.CACHED_NAME, CallLog.Calls.DATE, CallLog.Calls.DURATION };String selection = "number=? and (type=1 or type=3)";String[] selectionArgs = new String[] { NUMBER };String sortOrder = CallLog.Calls.DEFAULT_SORT_ORDER;//按时间排序【date DESC】cursor = resolver.query(uri, projection, selection, selectionArgs, sortOrder);if (cursor != null) {if (cursor.moveToFirst()) {int _id = cursor.getInt(cursor.getColumnIndex("_id"));int type = cursor.getInt(cursor.getColumnIndex("type"));//通话类型,1 来电 .INCOMING_TYPE;2 已拨 .OUTGOING_;3 未接 .MISSED_String number = cursor.getString(cursor.getColumnIndex("number"));// 电话号码String name = cursor.getString(cursor.getColumnIndex("name"));//联系人long date = cursor.getLong(cursor.getColumnIndex("date"));//通话时间,即可以用getString接收,也可以用getLong接收String formatDate = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(new Date(date));int duration = cursor.getInt(cursor.getColumnIndex("duration"));//通话时长,单位:秒String msgObj = "\nID:" + _id + "\n类型:" + type + "\n号码:" + number + "\n名称:" + name + "\n时间:" + formatDate + "\n时长:" + duration;mHandler.sendMessage(Message.obtain(mHandler, MSG_CALLLOG_QUERY_WHAT, msgObj));}cursor.close();}break;}}}
清单文件
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.itheima.ipdail"android:versionCode="1"android:versionName="1.0" ><uses-permission android:name="android.permission.RECEIVE_SMS" /><uses-permission android:name="android.permission.READ_SMS" /><uses-permission android:name="android.permission.READ_CALL_LOG" /><uses-permission android:name="android.permission.WRITE_CALL_LOG" /><uses-permission android:name="android.permission.CALL_PHONE" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-sdkandroid:minSdkVersion="17"android:targetSdkVersion="17" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name=".MainActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>
附件列表
内容观察者 ContentObserver 监听短信、通话记录数据库 挂断来电的更多相关文章
- Android_通过ContentObserver监听短信数据变化
1.简单介绍 在小米等一些机型,无法接收系统发出的短信广播. 仅仅能通过观察者ContentObserver,去监听短信数据的变化 2.SMS数据介绍 content://sms/inbox ...
- Android手机上监听短信的两种方式
Android手机上监听短信有两种方式: 1. 接受系统的短信广播,操作短信内容. 优点:操作方便,适合简单的短信应用. 缺点:来信会在状态栏显示通知信息. AndroidManifest.xml: ...
- android 监听短信并发送到服务器
1. 接受系统的短信广播,操作短信内容. 优点:操作方便,适合简单的短信应用. 缺点:来信会在状态栏显示通知信息. 2. 应用观察者模式,监听短信数据库,操作短信内容. 实例如下: SystemE ...
- android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人
要使用一个ContentProvider,必须要知道的是它所能匹配的Uri及其数据存储的表的结构. 首先想办法找到访问短信及联系人数据的ContentProvider能接受的Uri: 到github上 ...
- android 监听短信数据库,制作短信控制工具,控制别人的手机!!(一)
序言:本程序示例本着简洁易懂的目的,只做了简单的功能实现,需要用户启动应用,收到短信才有效果.作者将会在后面的(二)篇中加入服务后台运行.自动启动功能,实现一个真正的短信控制工具.本文的目的很简单,让 ...
- Android 监听短信(同时监听广播和数据库)
暗扣,强烈谴责这种侵害用户利益的行为... 下面给大家介绍Android暗扣原理....... Android4.4以下的系统玩游戏就要小心了哈 暗扣方式之一:短信订购,即监听--------拦截- ...
- 通过broadcastreceiver 监听短信问题
在mainfest中 订阅 短信到来的广播时候 发现找不到 <action android:name="android.provider.Telephony.SMS_RECEIV ...
- 越狱的 ios 如何 获取 读取 提取 手机上的 短信 通话记录 联系人 等信息
http://willson.sinaapp.com/2011/12/iphone 获取短信脚本.html Iphone获取短信脚本http://bbs.9ria.com/thread-209349 ...
- (转)[Android实例] 关于使用ContentObserver监听不到删除短信会话的解决方案
最近做通讯录的项目,需要实时监听短信的删除,就用到了观察者ContentObserver,怪异的事情就此发生,当我删除一条短信的时候,可以监听到,但是,当我删除整条短信的时候,就无法监听到,查了很多资 ...
随机推荐
- 关于.net 对excel操作的方法
asp.net打印文件用的最多的一般2种,word和excel,今天在这里整洁一下关于打印excel的几种方式及优缺点 第一种:直接打印html代码,然后将输出类型伪装成excel文件(excel是可 ...
- 【C++学习之路】派生类的构造函数(三)
三.多层继承的派生类 1.多层继承的派生类只需在构造函数的初始化列表中写出直接基类的构造函数即可 class student { public: student(int n, string nam) ...
- ubuntu11.10(TQ210)下移植boa服务器
平台:ubuntu11.10 一.下载源码包www.boa.org boa-0.94.13.tar.gz 二.解压,在其src目录下生产makefile #tar xvfz boa-0.94.1 ...
- 最简单的ASP动态页面生成伪静态方法
目前网站制作中很多网站都采用生成静态页的方法,原因是这样访问速度会得到提高(服务器端CPU利用率很低),另外也容易被搜索引擎收录,但是这带来的一个问题就是需要足够大的空间存放这些静态页面,如果你的空间 ...
- iOS开发之UIWebView自动滑动到顶部-备
但可以通过subview来操作. 通常用UIWebView加载网页,有时候需要点击一个按钮,或者页面的某个部位,使页面自动滚动到顶部,但是UIWebView不像UIScrollView那么方便. ...
- 完全教程 Aircrack-ng来PJ---WEP、WPA-PSK--加密利器
恩,先说明一下,本章的内容适用于目前市面所有主流品牌无线路由器或AP如Linksys.Dlink.TPLink.BelKin等.涉及内容包括了WEP加密及WPA-PSK加密的无线网络的破解操作实战. ...
- spark 监控--WebUi、Metrics System
Spark 监控相关的部分有WebUi 及 Metrics System; WebUi用于展示Spark 资源状态.Metrics System 整合的指标信息. Ui相关流程 Spark集群启动之后 ...
- MySQL 学习笔记 (它执行的步骤)
基本步骤是 : (不是很准,请看完这篇) 1.from 2.join on 3.where 4.group by 5.having 6.order by 7.select 8.distinct ,su ...
- 使用AlertDialog创建对话框的大致步骤
1.创建AlertDialog.Builder对象,该对象是AlertDialog的创建器.2.调用AlertDialog.Builder的方法为对话框设置图标.标题.内容等.3.调用AlertDia ...
- C语言#pragma预处理
在所有的预处理指令中,#pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma 指令对每个编译器给出了一个方法,在保持与C 和C ++语言完全 ...

