Android_通过ContentObserver监听短信数据变化
1.简单介绍
在小米等一些机型,无法接收系统发出的短信广播。
仅仅能通过观察者ContentObserver,去监听短信数据的变化
2.SMS数据介绍
content://sms/inbox 收件箱
content://sms/sent 已发送
content://sms/draft 草稿
content://sms/outbox 发件箱
content://sms/failed 发送失败
content://sms/queued 待发送列表
在模拟器上Outbox没有查询到数据,在模拟器上找了老半天也没找到发件箱。非常郁闷。
数据库中sms相关的字段例如以下:
_id 一个自增字段。从1開始
thread_id 序号,同一发信人的id同样
address 发件人手机号码
person 联系人列表里的序号,陌生人为null
date 发件日期
protocol 协议,分为: 0 SMS_RPOTO, 1 MMS_PROTO
read 是否阅读 0未读, 1已读
status 状态 -1接收。0 complete, 64 pending, 128 failed
type
ALL = 0;
INBOX = 1;
SENT = 2;
DRAFT = 3;
OUTBOX = 4;
FAILED = 5;
QUEUED = 6;
body 短信内容
service_center 短信服务中心号码编号
subject 短信的主题
reply_path_present TP-Reply-Path
locked
检索数据方法非常easy:
Uri uri = Uri.parse("content://sms/inbox");
Cursor cur = this.managedQuery(uri, null, null, null, null);
if (cur.moveToFirst()) {
do{
for(int j = 0; j < cur.getColumnCount(); j++){
info = "name:" + cur.getColumnName(j) + "=" + cur.getString(j);
Log.i("====>", info);
}
}while(cur.moveToNext());
}
managedQuery终于也要将參数转换为SQL语句向SQLite发送消息,因此參数跟SQL语句非常类似,所以能够在查询字段中增加SQL函数,
比方new String[] projection = new String[]{"count(*) as count"}等等。
managedQuery中的參数依次为uri。
查询字段 查询字段数组,也能够将全部须要查询的字段放入一个字符内
比方new projection[]{"_id", "thread_id"}和new projection[]{"_id,thread_id"}是一致的。跟SQL一样,字段名不区分大写和小写
条件 不带Where的SQL 条件字符,假设有參数则用?替代,比方"_id=?And thread_id = ?
Or type = '1'"
条件中的參数 參数字符数组。跟上述的条件一一相应
排序 不带Order by排序字符串,比方_id desc, type
假设參数为null,SQL中查询字段为“*”,相关的条件为空白
还能够用getContentResolver()获得一个ContentResolver。
getContentResolver().query()相同返回一个Cursor对象,參数跟managedQuery一致。
只是用ContentResolver对象去更新、删除和插入一条数据时报SecurityException。看来没有权限,在Manifest.xml中增加权限:
<uses-permission android:name="android.permission.WRITE_SMS"></uses-permission>
然后删除短信:
this.getContentResolver().delete(Uri.parse("content://sms"), "_id=?", new String[]{"3"});
删除成功。
Url中content://sms 替换成content://sms/ 也成功,可是其他url时程序报错,比方content://sms/inbox
看了一下android的源码,sms支持的协议有:
sURLMatcher.addURI("sms", null, SMS_ALL);
sURLMatcher.addURI("sms", "#", SMS_ALL_ID);
sURLMatcher.addURI("sms", "inbox", SMS_INBOX);
sURLMatcher.addURI("sms", "inbox/#", SMS_INBOX_ID);
sURLMatcher.addURI("sms", "sent", SMS_SENT);
sURLMatcher.addURI("sms", "sent/#", SMS_SENT_ID);
sURLMatcher.addURI("sms", "draft", SMS_DRAFT);
sURLMatcher.addURI("sms", "draft/#", SMS_DRAFT_ID);
sURLMatcher.addURI("sms", "outbox", SMS_OUTBOX);
sURLMatcher.addURI("sms", "outbox/#", SMS_OUTBOX_ID);
sURLMatcher.addURI("sms", "undelivered", SMS_UNDELIVERED);
sURLMatcher.addURI("sms", "failed", SMS_FAILED);
sURLMatcher.addURI("sms", "failed/#", SMS_FAILED_ID);
sURLMatcher.addURI("sms", "queued", SMS_QUEUED);
sURLMatcher.addURI("sms", "conversations", SMS_CONVERSATIONS);
sURLMatcher.addURI("sms", "conversations/*", SMS_CONVERSATIONS_ID);
sURLMatcher.addURI("sms", "raw", SMS_RAW_MESSAGE);
sURLMatcher.addURI("sms", "attachments", SMS_ATTACHMENT);
sURLMatcher.addURI("sms", "attachments/#", SMS_ATTACHMENT_ID);
sURLMatcher.addURI("sms", "threadID", SMS_NEW_THREAD_ID);
sURLMatcher.addURI("sms", "threadID/*", SMS_QUERY_THREAD_ID);
sURLMatcher.addURI("sms", "status/#", SMS_STATUS_ID);
sURLMatcher.addURI("sms", "sr_pending", SMS_STATUS_PENDING);
sURLMatcher.addURI("sms", "sim", SMS_ALL_SIM);
sURLMatcher.addURI("sms", "sim/#", SMS_SIM);
当中,delete方法中支持的协议为:
SMS_ALL 依据參数中的条件删除sms表数据
SMS_ALL_ID 依据_id删除sms表数据
SMS_CONVERSATIONS_ID 依据thread_id删除sms表数据,能够带其他条件
SMS_RAW_MESSAGE 依据參数中的条件删除 raw表
SMS_STATUS_PENDING 依据參数中的条件删除 sr_pending表
SMS_SIM 从Sim卡上删除数据
试一下SMS_CONVERSATIONS_ID:"content://sms/conversations/3 "。删除thread_id="3", _id="5"的数据
在eclipse中的Emulator Control中,以13800给模拟器发送三条数据,然后以13900发送一条
this.getContentResolver().delete(Uri.parse("content://sms/conversations/3"), "_id=?", new String[]{"5"});
成功删除一条数据。在数据库中每一个发送者的thread_id尽管一样,但不是固定的。假设把一个发送者的所有数据删除掉。
然后换一个新号码发送短信时。thread_id是以数据库中最大的id+1赋值的。update支持的协议有非常多:
SMS_RAW_MESSAGE
SMS_STATUS_PENDING
SMS_ALL
SMS_FAILED
SMS_QUEUED
SMS_INBOX
SMS_SENT
SMS_DRAFT
SMS_OUTBOX
SMS_CONVERSATIONS
SMS_ALL_ID
SMS_INBOX_ID
SMS_FAILED_ID
SMS_SENT_ID
SMS_DRAFT_ID
SMS_OUTBOX_ID
SMS_CONVERSATIONS_ID
SMS_STATUS_ID
以SMS_INBOX_ID測试一下:
ContentValues cv = new ContentValues();
cv.put("thread_id", "2");
cv.put("address", "00000");
cv.put("person", "11");
cv.put("date", "11111111");
this.getContentResolver().update(Uri.parse("content://sms/inbox/4"), cv, null, null);
太强了,连thread_id都能够改动。
insert支持的协议:
SMS_ALL
SMS_INBOX
SMS_FAILED
SMS_QUEUED
SMS_SENT
SMS_DRAFT
SMS_OUTBOX
SMS_RAW_MESSAGE
SMS_STATUS_PENDING
SMS_ATTACHMENT
SMS_NEW_THREAD_ID
向sms表插入数据时。type是依据协议来自己主动设置,
假设传入的数据中没有设置date时,自己主动设置为当前系统时间;非SMS_INBOX协议时,read标志设置为1
SMS_INBOX协议时,系统会自己主动查询并设置PERSON
threadId为null或者0时,系统也会自己主动设置
一直为造不了"发送失败"的邮件而发愁。如今来做一个:
content://sms/failed
ContentValues cv = new ContentValues();
cv.put("_id", "99");
cv.put("thread_id", "0");
cv.put("address", "9999");
cv.put("person", "888");
cv.put("date", "9999");
cv.put("protocol", "0");
cv.put("read", "1");
cv.put("status", "-1");
//cv.put("type", "0");
cv.put("body", "@@@@@@@@@");
this.getContentResolver().insert(Uri.parse("content://sms/failed"), cv);
type被设置成了5。thread_id设置为1
看看能不能再挖掘一下sms的功能。先来做一个错误的查询:
getContentResolver().query( Uri.parse("content://sms/") , new String[]{"a"}, "b", null, null);
log输出错误的SQL语句:
SELECT a FROM sms WHERE (b) ORDER BY date DESC
query方法中没有Group by,假设想对短信做统计,对Cursor进行遍历再统计也太慢了。
在SQL语言中group by在Where后面,那就在条件參数中想想办法:
Android组织SQL语句时将条件两端加(),那就拼一个group by出来吧:
getContentResolver().query( Uri.parse("content://sms/") , new String[]{"count(*) as count, thread_id"}, "1=1) group by (thread_id", null, null);
那么输出的SQL= SELECT count(*) as count, thread_id FROM sms WHERE ( 1=1) group by (thread_id ) ORDER BY date DESC
假设想查询URI没有相应的表怎么办呢。比方想知道 mmssms.db数据库中有哪些表,
查询的表是URI定的,再在条件參数中拼凑肯定是不行。那我们把目光往前移,看看在字段參数中能不能凑出来。
要查询其他表,关键要去掉系统固定加入的FROM sms。
用用SQL中的凝视吧,
getContentResolver().query(Uri.parse("content://sms/"), new String[]{" * from sqlite_master WHERE type = 'table' -- "}, null, null, null);
那么输出的SQL=SELECT * from sqlite_master WHERE type = 'table' -- FROM sms ORDER BY date DESC 竟然可以执行。
得寸进尺。再进一步。假设增加“;”也能执行的话,哈哈,那么建表、删除表、更新表也能为所欲为咯。
getContentResolver().query(Uri.parse("content://sms/"), new String[]{" * from sms;select * from thrreads;-- "}, null, null, null);
3.实例
public class SMSContentObserver extends ContentObserver {
private Context mContext;
String[] projection = new String[] { "address", "body", "date", "type", "read" }; public SMSContentObserver(Context context, Handler handler) {
super(handler);
mContext = context;
} @Override
public void onChange(boolean selfChange) {
Uri uri = Uri.parse("content://sms/inbox");
Cursor c = mContext.getContentResolver().query(uri, null, null, null, "date desc");
if (c != null) {
while (c.moveToNext()) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date d = new Date(c.getLong(c.getColumnIndex("date")));
String date = dateFormat.format(d);
StringBuilder sb = new StringBuilder();
sb.append("发件人手机号码: " + c.getString(c.getColumnIndex("address")))
.append("信息内容: " + c.getString(c.getColumnIndex("body")))
.append(" 是否查看: " + c.getInt(c.getColumnIndex("read")))
.append(" 类型: " + c.getInt(c.getColumnIndex("type"))).append(date);
Log.i("xxx", sb.toString());
}
c.close();
}
}
}
Android_通过ContentObserver监听短信数据变化的更多相关文章
- 内容观察者 ContentObserver 监听短信、通话记录数据库 挂断来电
Activity public class MainActivity extends ListActivity { private TextView tv_info; private ...
- android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人
要使用一个ContentProvider,必须要知道的是它所能匹配的Uri及其数据存储的表的结构. 首先想办法找到访问短信及联系人数据的ContentProvider能接受的Uri: 到github上 ...
- Android手机上监听短信的两种方式
Android手机上监听短信有两种方式: 1. 接受系统的短信广播,操作短信内容. 优点:操作方便,适合简单的短信应用. 缺点:来信会在状态栏显示通知信息. AndroidManifest.xml: ...
- android 监听短信数据库,制作短信控制工具,控制别人的手机!!(一)
序言:本程序示例本着简洁易懂的目的,只做了简单的功能实现,需要用户启动应用,收到短信才有效果.作者将会在后面的(二)篇中加入服务后台运行.自动启动功能,实现一个真正的短信控制工具.本文的目的很简单,让 ...
- android 监听短信并发送到服务器
1. 接受系统的短信广播,操作短信内容. 优点:操作方便,适合简单的短信应用. 缺点:来信会在状态栏显示通知信息. 2. 应用观察者模式,监听短信数据库,操作短信内容. 实例如下: SystemE ...
- Android 监听短信(同时监听广播和数据库)
暗扣,强烈谴责这种侵害用户利益的行为... 下面给大家介绍Android暗扣原理....... Android4.4以下的系统玩游戏就要小心了哈 暗扣方式之一:短信订购,即监听--------拦截- ...
- 通过broadcastreceiver 监听短信问题
在mainfest中 订阅 短信到来的广播时候 发现找不到 <action android:name="android.provider.Telephony.SMS_RECEIV ...
- .Net客户端监听ZooKeeper节点数据变化
一个很简单的例子,用途是监听zookeeper中某个节点数据的变化,具体请参见代码中的注释 using System; using System.Collections.Generic; using ...
- Proxy监听对象的数据变化,处理绑定数据很有用
Proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作.一下子让我们对一个对象有了很强的追踪能力,同时在数据绑定方面也很有用处. }; //interceptor 拦截 var ...
随机推荐
- ORACLE 中写入txt文本与从Txt文件中读入数据 修改表结构
--创建一个表 DROP TABLE TEST CASCADE CONSTRAINTS ; CREATE TABLE TEST(A VARCHAR(30),B VARCHAR(30)); --查看具体 ...
- 论文:network embedding
KDD2016: network embedding model: deep walk(kdd 2014): http://videolectures.net/kdd2014_perozzi_deep ...
- IOS 计算密码强度
+ (BOOL) judgeRange:(NSArray*)conditionArr Password:(NSString*)password { NSRange range; BOOL result ...
- [置顶] Android开发实战记录(三)---HelloWorld
1.新建Android项目,选择Android Project,然后Next 2.填写项目名称HelloWorld然后next,这里注意下,Java开发的命名规范 3.选择Android SDK版本, ...
- C#集合-队列
本文来自:http://www.cnblogs.com/yangyancheng/archive/2011/04/28/2031615.html 队列是其元素以先进先出(FIFO)的方式来处理的集合. ...
- 用 oracle vitual box 克隆虚拟机,找不到eth0的解决方案
用 oracle vitual box 克隆虚拟机 当我们需要使用多台虚拟机的时候,如果一台一台的安装,实在是太过麻烦了.所以一般的虚拟机软件都为我们提供了克隆已有虚拟机状态的功能.Oracle vi ...
- PHP反射ReflectionClass、ReflectionMethod 入门教程
PHP反射ReflectionClass.ReflectionMethod 入门教程 作者:SNSGOU 发布于:2014-03-16 16:44:00 分类:PHP 浏览(6145) PHP5 ...
- Android多项目依赖在Eclipse中无法关联源代码的问题解决 Ctril 点不进去的解决方法
1. 使用快捷键:Ctrl+shift+R,在弹出框中输入.classpath 找到被作为library引入的那个.classpath文件. 2.将kind="src" path ...
- iOS 使用NJKWebViewProgress做webview进度条
NJKWebViewProgress地址:https://github.com/ninjinkun/NJKWebViewProgress 导入头文件 #import "NJKWebViewP ...
- java字符串数组进行大小排序
若是将两个字符串直接比较大小,会包:The operator > is undefined for the argument type(s) java.lang.String, java.lan ...