Jul 1

 在SMS数据库中person这个值得到的有人说就是联系人的ID但是实际上这个值是不稳定的,这里要得到联系人信息需要通过address获得的发件人电话号码和ContactsContract.PhoneLookup.CONTENT_FILTER_URI来实现.代码如下

ContactItem getContactByAddr(Context context, final SMSItem sms) { 
    Uri personUri = Uri.withAppendedPath( 
            ContactsContract.PhoneLookup.CONTENT_FILTER_URI, sms.mAddress); 
    Cursor cur = context.getContentResolver().query(personUri, 
            new String[] { PhoneLookup.DISPLAY_NAME }, 
            null, null, null ); 
    if( cur.moveToFirst() ) { 
        int nameIdx = cur.getColumnIndex(PhoneLookup.DISPLAY_NAME); 
        ContactItem item = new ContactItem(); 
        item.mName = cur.getString(nameIdx); 
       cur.close(); 
       return item; 
   } 
   return null; 
}

Apr 4

不能直接访问数据库,只能通过协议来访问数据库了,       
先贴出相关的协议:       
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 (不稳定无法获取联系人ID)
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   

检索数据方法很简单: 

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:"
在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

 

--------------------------------------------------------------------------------


系统连最起码的数据校验都没有做啊,google对程序员也太仁慈了。

看看能不能再挖掘一下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'

 

那么输出的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;

很可惜,只运行了第一条SQL语句,看来在关键问题上,android还是有所控制的。

不过支持--也很不错了,这样可以查询数据库中所有的表,而且还可以多表联查

Sep 10

   好久没有动动blog了,一方面是懒,二方面是一直也没有什么新鲜的东西可以写,最近不知道怎么了,便有了危机感,有了危机感就要在危机来到之前将其化解,要不然就的坐以待毙,为此考虑开始研究android了.说实在的这个东西,现在高出像样的玩意的貌似已经有不少了,现在弄或许晚了,但是我个人觉得还是不晚,现在最多是个初级阶段而已,折腾了好半天连下载SDK带配置环境,总算是弄完了.感觉那个模拟器好慢啊....很多人都知道google指定的IDE是eclipse,而且相关的文章不计其数,从1.5版本开始配置到2.2版本的配置样样都有,可唯独没有见几个netbeans的配置,(顺便说下netbeans越用越顺手,我说的是sun的那个,oracle的6.9.1没感觉有啥变化,仅仅是多了个虚拟终端,现在我已经么有linux了也用不到了=.=)下面说说我的netbeans的配置吧,也许有跟我一样喜欢netbeans而没有找到android环境搭建的朋友呢.

Jun 25

        23种设计模式,是前辈们智慧的结晶,但是很多时候向我这样的新手总是有些难以理解的,偶然发现一个搞笑版本的设计模式解释,虽然搞笑,但确实是设计模式的定义,不妨用这种方式来尝试理解,也许应用的时候会好很多。

May 2

        英语俚语,对于我来说简直就是一件尴尬的事情,因为,无论从字面还是从抽象都得不到正确的意思,当然中文也有让老外尴尬的俚语。但是我是中国人,而且这样的环境导致我必须知道一些英语,多少是些无奈,收集到一些俚语挺好的。

文章来源:微笑

May 2

        已经不知道是从那里看到的文章了,所以是在没有办法把文章来源贴出来。但是看完之后还是有些感触的。

Apr 19

        之前我对我的vim的配置进行了重新修改,但是今天我用他来编译C++的时候发现一个问题,这个问题使我很郁闷,具体情况就是之前的那个配置在对c文件和c++文件进行编译的时候会错误的调用编译器,我已经对他进行了修正,而且修改了配色方案,关于配色方案我就不这在里放置了,大家根据需求自行选择就好了,其他的修改在配置文件顶部都有说明,插件均可在官方下载到。具体配置请大家移步到此处

文章来源:微笑

Apr 8

        用VIM这个超级编辑器的时间应该是从去年开始的,大概记得是因为gedit在某些方面实在无法满足我的需求,但是一直认为vim过于繁琐于是就从未尝试过,后来发现scite用了一段时间感觉还不错,而且配置起来也不是很麻烦,但是时间长了还是发现scite一样不是我想要的那种编辑器,当时又很有意思的看到一篇emacs和vim的文章于是便动了邪念,把Emacs和VIM都装上了,结果vim的小巧直接让我将Emacs打入了冷宫,客观的来说Emacs也是很不错的。后来总是想见识下这个神用的编辑器(Emacs)到底如何,google了一下发现那个配置有点麻烦,向我这样的懒人就放弃了一睹其真风采的想法。于是很专一的在web上寻找vim的配置,也算是配置了个七七八八,能满足需求了,但是心理总是不爽,因为第一次的配置基本是什么都不明白装了一堆的plugin,也许是受到firefox的影响总感觉vim变的很慢,便想重新配置一次VIM但是懒散的我却始终没能拿出勇气,但是因一次不可逆的误操作,使我不得不从新配置他,配置完成了,插件基本用的不多,感觉清爽了很多,心理也不那么别扭了,正好贴出来就当是一个备份好了,有喜欢的朋友也可以拿去进行修改,让他成为你手边的一个编辑利器。

文章来源:微笑

Mar 25

        我还是没能坚持住,在ubuntu10.04bata1的时候对我的系统进行了升级,在某些情况来看这次的升降还是值得的。那么10.04个我们带来了什么呢?

也许这需要大量的截图才能真正让我们知道,但是写这篇文章的时候我正好在Windows下玩游戏,这篇文章也是一时兴起来写的。那就靠我的回忆来说说这个清醒的猞猁给我们带来的惊喜吧。

文章来源:微笑

Mar 16

        人们总是如此,当你生活不让人家的时候你便会怨天尤人,然而你却从来不知道你的生活也是别人羡慕的资本——还有很多不如你的人在比你更悲惨的世界中举步维艰的前行着,也许你曾经看过无数这样的人,也许你也曾同情怜悯过他们,但是你却从来都没有想过:原来我的生活也是如此的美好。

PS.今天很偶然的看到一篇这样的文章,虽然已经临睡,但是这篇文章却让我辗转反侧难以入眠。于是决定把他留下来。