android學習筆記25————–短信的各種操作操作

1.註冊廣播接收器

[java]
<receiver android:name="SMSReceiver"> 
            <intent-filter> 
                <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 
            </intent-filter> 
        </receiver> 
<receiver android:name="SMSReceiver">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>
[java]
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.os.Bundle; 
import android.telephony.SmsMessage; 
import android.widget.Toast; 
 
public class SMSReceiver extends BroadcastReceiver { 
     
    public static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED"; 
     
    @Override 
    public void onReceive(Context context, Intent intent) { 
        if (SMS_RECEIVED.equals(intent.getAction())) { 
            Bundle bundle = intent.getExtras(); 
            if (bundle != null) { 
                Object[] pdus = (Object[]) bundle.get("pdus"); 
                final SmsMessage[] messages = new SmsMessage[pdus.length]; 
                String msg = ""; 
                for (int i = 0; i < pdus.length; i++) { 
                    messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]); 
                    msg += messages[i].getMessageBody(); 
                } 
                Toast.makeText(context, msg, Toast.LENGTH_LONG).show(); 
            } 
        } 
    } 
 

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;

public class SMSReceiver extends BroadcastReceiver {
   
    public static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
   
    @Override
    public void onReceive(Context context, Intent intent) {
        if (SMS_RECEIVED.equals(intent.getAction())) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                Object[] pdus = (Object[]) bundle.get("pdus");
                final SmsMessage[] messages = new SmsMessage[pdus.length];
                String msg = "";
                for (int i = 0; i < pdus.length; i++) {
                    messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
                    msg += messages[i].getMessageBody();
                }
                Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
            }
        }
    }

}

2.添加權限

[java]
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission> 
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>

二、讀取收件箱中的短信

1.從數據庫中讀取,URI為"content://sms/inbox"

[java]
import android.app.Activity; 
import android.content.ContentResolver; 
import android.database.Cursor; 
import android.net.Uri; 
import android.os.Bundle; 
import android.widget.TextView; 
 
public class MySMSManager extends Activity { 
     
    private TextView textview; 
    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
        textview = (TextView) findViewById(R.id.textview); 
        readShortMessage(); 
    } 
     
    public void readShortMessage() { 
        ContentResolver cr = getContentResolver(); 
        Cursor cursor = cr.query(Uri.parse("content://sms/inbox"), null, null, null, null); 
        String msg = ""; 
        while(cursor.moveToNext()) { 
            int phoneColumn = cursor.getColumnIndex("address");   
            int smsColumn = cursor.getColumnIndex("body");   
            msg += cursor.getString(phoneColumn) + ":" + cursor.getString(smsColumn) + "\n"; 
        } 
        textview.setText(msg); 
    } 

import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.widget.TextView;

public class MySMSManager extends Activity {
   
    private TextView textview;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        textview = (TextView) findViewById(R.id.textview);
        readShortMessage();
    }
   
    public void readShortMessage() {
        ContentResolver cr = getContentResolver();
        Cursor cursor = cr.query(Uri.parse("content://sms/inbox"), null, null, null, null);
        String msg = "";
        while(cursor.moveToNext()) {
            int phoneColumn = cursor.getColumnIndex("address"); 
            int smsColumn = cursor.getColumnIndex("body"); 
            msg += cursor.getString(phoneColumn) + ":" + cursor.getString(smsColumn) + "\n";
        }
        textview.setText(msg);
    }
}

2.添加權限

[java]
<uses-permission android:name="android.permission.READ_SMS"></uses-permission> 
<uses-permission android:name="android.permission.READ_SMS"></uses-permission>

 附:其它短信的URI和數據庫表字段

[java]
String SMS_URI_ALL =  "content://sms/";  
String SMS_URI_INBOX = "content://sms/inbox"; 
String SMS_URI_SENT = "content://sms/sent";     
String SMS_URI_DRAFT = "content://sms/draft";      
String SMS_URI_OUTBOX = "content://sms/outbox";     
String SMS_URI_FAILED = "content://sms/failed";      
String SMS_URI_QUEUED = "content://sms/queued"; 
String SMS_URI_ALL =  "content://sms/";
String SMS_URI_INBOX = "content://sms/inbox";
String SMS_URI_SENT = "content://sms/sent";   
String SMS_URI_DRAFT = "content://sms/draft";    
String SMS_URI_OUTBOX = "content://sms/outbox";   
String SMS_URI_FAILED = "content://sms/failed";    
String SMS_URI_QUEUED = "content://sms/queued";

 

content://sms/inbox 收件箱
content://sms/sent 已發送
content://sms/draft 草稿
content://sms/outbox 發件箱
content://sms/failed 發送失敗
content://sms/queued 待發送列表

檢索數據方法很簡單:
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());
}

 

——————————————————————————–

 

 

[java]
/*
_id => 短消息序號 如100  
thread_id => 對話的序號 如100  
address => 發件人地址,手機號.如+8613811810000  
person => 發件人,返回一個數字就是聯系人列表裡的序號,陌生人為null  
date => 日期  long型。如1256539465022  
protocol => 協議 0 SMS_RPOTO, 1 MMS_PROTO   
read => 是否閱讀 0未讀, 1已讀   
status => 狀態 -1接收,0 complete, 64 pending, 128 failed   
type => 類型 1是接收到的,2是已發出   
body => 短消息內容   
service_center => 短信服務中心號碼編號。如+8613800755500  
*/ 
/*
_id => 短消息序號 如100 
thread_id => 對話的序號 如100 
address => 發件人地址,手機號.如+8613811810000 
person => 發件人,返回一個數字就是聯系人列表裡的序號,陌生人為null 
date => 日期  long型。如1256539465022 
protocol => 協議 0 SMS_RPOTO, 1 MMS_PROTO  
read => 是否閱讀 0未讀, 1已讀  
status => 狀態 -1接收,0 complete, 64 pending, 128 failed  
type => 類型 1是接收到的,2是已發出  
body => 短消息內容  
service_center => 短信服務中心號碼編號。如+8613800755500 
*/

 

其中,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賦值的。

 

 

三、打開發送短信界面

[java]
Uri uri = Uri.parse("smsto:13800138000"); 
        Intent it = new Intent(Intent.ACTION_SENDTO, uri); 
        it.putExtra("sms_body", "The SMS text"); 
        startActivity(it); 
Uri uri = Uri.parse("smsto:13800138000");
        Intent it = new Intent(Intent.ACTION_SENDTO, uri);
        it.putExtra("sms_body", "The SMS text");
        startActivity(it);
四、發送短信

1.通過SmsManager的sendTextMessage(destinationAddress, scAddress, text, sentIntent, deliveryIntent)方法發送

[java]
String msg ="hello";  
        String number = "1234565678";  
        SmsManager sms = SmsManager.getDefault();  
        PendingIntent pi = PendingIntent.getBroadcast(this,0,new Intent(),0);  
        sms.sendTextMessage(number,null,msg,pi,null); 
String msg ="hello";
        String number = "1234565678";
        SmsManager sms = SmsManager.getDefault();
        PendingIntent pi = PendingIntent.getBroadcast(this,0,new Intent(),0);
        sms.sendTextMessage(number,null,msg,pi,null);

2.添加權限

[java]
<uses-permission android:name="android.permission.SEND_SMS"></uses-permission> 
<uses-permission android:name="android.permission.SEND_SMS"></uses-permission>

 

五、直接向數據庫寫短信

[java]
ContentResolver cr = getContentResolver(); 
        ContentValues cv = new ContentValues(); 
        cv.put("address", "13800138000"); 
        cv.put("body", "hello!"); 
        cr.insert(Uri.parse("content://sms/inbox"), cv); 
ContentResolver cr = getContentResolver();
        ContentValues cv = new ContentValues();
        cv.put("address", "13800138000");
        cv.put("body", "hello!");
        cr.insert(Uri.parse("content://sms/inbox"), cv);

權限:

[java]
<uses-permission android:name="android.permission.WRITE_SMS"></uses-permission> 
<uses-permission android:name="android.permission.WRITE_SMS"></uses-permission>

六、監聽短信數據庫變化

使用ContentObserver ,觀察"content://sms"的變化,調用重寫的onChange方法,可以監聽到短信記錄的

變化,這樣可以監聽發短信,同樣也是可以監聽收短信的。

[java]
import android.database.ContentObserver; 
import android.os.Handler; 
import android.util.Log; 
 
public class SMSObserver extends ContentObserver { 
 
    public SMSObserver(Handler handler) { 
        super(handler); 
    } 
     
    @Override 
    public void onChange(boolean selfChange) { 
        Log.i("sms", "sms"); 
    } 
 

import android.database.ContentObserver;
import android.os.Handler;
import android.util.Log;

public class SMSObserver extends ContentObserver {

    public SMSObserver(Handler handler) {
        super(handler);
    }
   
    @Override
    public void onChange(boolean selfChange) {
        Log.i("sms", "sms");
    }

}

然後在Acitivty或Service裡註冊這個觀察者

[java]
getContentResolver().registerContentObserver(Uri.parse("content://sms"), 
                                true, new SMSObserver(new Handler())); 
getContentResolver().registerContentObserver(Uri.parse("content://sms"),
                                true, new SMSObserver(new Handler()));

Smsmessage.getTimestampMillis() 獲得短信發送時間
System.currentTimeMillis()獲得系統當前時間
一般短信軟件都是獲取當前時間
System.currentTimeMillis()改為Smsmessage.getTimestampMillis()
就能讀到短信發送時間。

在做讀取短信的時候,讀取到date字段,需要轉換成例如7/21 或者 8:21這種格式,不用手動轉換 通過調用相應的類來實現

SimpleDateFormat sfd = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");// 這裡我們可以指定可是 例如 MM-DD就是隻顯示月和日  。。。。

Date date = new Date(Long.parseLong(cursor.getString(cursor.getColumnIndex("date"))));//從短信中獲得時間

String time = sfd.format(date); //轉換完成的字符串 很簡單

dataTextView.setText(time); //顯示出來就行瞭

使用前:

 

使用後:

 

/**
* 通過電話號碼獲取姓名
*/ 
 
    public String getContactNameFromPhoneNum(Context context, String phoneNum) 
    { 
        String contactName = ""; 
        ContentResolver cr = context.getContentResolver(); 
        Cursor pCur = cr.query( 
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, 
                ContactsContract.CommonDataKinds.Phone.NUMBER + " = ?", 
                new String[] 
                { phoneNum }, null); 
        if (pCur.moveToFirst()) 
        { 
            contactName = pCur 
                    .getString(pCur 
                            .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); 
            pCur.close(); 
        } 
        return contactName; 
    } 
/**
* 通過電話號碼獲取姓名
*/

 public String getContactNameFromPhoneNum(Context context, String phoneNum)
 {
  String contactName = "";
  ContentResolver cr = context.getContentResolver();
  Cursor pCur = cr.query(
    ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
    ContactsContract.CommonDataKinds.Phone.NUMBER + " = ?",
    new String[]
    { phoneNum }, null);
  if (pCur.moveToFirst())
  {
   contactName = pCur
     .getString(pCur
       .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
   pCur.close();
  }
  return contactName;
 }
Android系統源碼數據庫(mmssms.db)中幾個表之前的關系.

首先明瞭未接信息的數據庫的位置在系統

/data/data/com.android.providers.telephony/databases/mmssms.db 包下。

希望大傢能夠結合源碼中的

1.       Telephony.java (主要講這些表裡有哪些字段)

2.       MmsSmsProvider.java (ContentProvider被重寫)

3.       MmsProvider.java (ContentProvider被重寫)

4.       SmsProvider.java (ContentProvider被重寫)

5.       Conversation.java  描述 mmssms數據庫的Threads表

 

當我們查詢mmssms.db數據庫時,這其中涉及到以下幾張表:

1.       threads表

2.       存放短信的表(sms表)

3.       存放彩信的表(pdu表,part表)

4.       存放phone number的表( Canonical_address表)

threads表字段說明:

_id: 用於區分不同的電話號碼,系統會為不同的電話號碼分配不同的_id.

date: 收到信息的時間(如果收到來自同一個phone number多條信息,並且有對於一條信息未讀,那麼date表示收到的最後一條信息時的時間)

message_count: 收到的信息的數目(sms+mms)

snippet: 如果來自某個phone number,僅僅有一條信息,那麼會是如下情況

      如果是未接短信,代表未接短信的內容

      如果是未接彩信,代表未接彩信的subject.

      如果來自某個phone number,僅僅有多條信息,那麼則是如下情況

      如果是最後一條是未接短信,代表最後一條未接短信的內容

      如果是最後一條是未接彩信,代表最後一條未接彩信的subject.

      然而這個字段存儲的僅僅是一條短信內容或者彩信subject的部分內容,其餘內容用省略號表示。

read: 0. 代表未讀。 1.代表 已讀

has_attchment: 代表來自該phone number的信息是否包含有附件。

依據上面的表結構,也許會有人問,phone number 呢?有這樣的疑問是非常正常的,別著急,學過數據庫的人都知道,表結構之間並不是孤立的,而是相互關聯的。

phone number 會在另外幾張表中出現。

 

 

Sms表

查詢該表時的uri :   URI_SMS_INBOX = Uri.parse("content://sms/inbox")

_id
thread_id
address
date
read
subject
body
locked

Sms表字段說明

_id: 區分不同的短信。

threads_id: (外鍵)引用threads表的_id.

date: 該條短信接收的時間

read: 0表未讀,1表已讀

body: 表示具體的短信內容,(註意,雖然在thread表的snippet字段已經存儲瞭一部分body,但是那裡的並不全,僅僅是一部分body)

locked: 該字段我也不是很清楚,用到的不多,不過如果我標識某條信息為locked時,當我再刪除這條信息時,系統會提示我“是否刪除locked信息”。

很明顯以上:_id為4.或5的短信,來自同一個phone number,也就是說他們的thread_id是相同的.

 

Pdu表:

URI_MMS_INBOX = Uri.parse("content://mms/inbox");

_id
Thread_id
date
Msg_box
read
M_id
sub
Ct_l
m_type 

 

Pdu表字段說明:

_id: 區分不同的彩信

thread_id : 外鍵 (引用thread表的_id)

msg_box: 區分彩信的收件箱,發件箱,草稿箱等.

         很明顯1.代表收件箱

read:是否已讀,0 未讀,1.已讀

sub: 彩信的subject

ct_l: 如果彩信太大,或者由於網絡原因,也又是由於手機設備原因,dowload失敗,彩信看不瞭,這個字段就會有彩信的網址(我曾經見到過一次,http://格式的,就是一個網址)

 

摘自 奔跑的蝸牛

發佈留言