以前剛開始接觸android時對諸如簡訊攔截之類的功能高度興趣,網上很多文章都介紹了使用廣播接收android.provider.Telephony.SMS_RECEIVED的動作,從而接收到SMS資訊,不過當時也不知道怎麼樣把這個廣播刪掉,從而實現一個類似簡訊黑名單的功能。後來在網上看到可以使用abortBroadcast來屏蔽廣播,我測試了一下,可行。
先上源碼:
AndroidManifest.xml的代碼:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.study.sms"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<receiver android:name=".smsReceiver">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.RECEIVE_SMS">
</uses-permission>
</manifest>
smsReceiver的代碼:
package com.study.sms;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
public class smsReceiver extends BroadcastReceiver {
public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (SMS_RECEIVED_ACTION.equals(action)){
Bundle bundle = intent.getExtras();
if (bundle != null){
Object[] pdus = (Object[])bundle.get("pdus");
for (Object pdu : pdus){
SmsMessage message = SmsMessage.createFromPdu((byte[]) pdu);
String sender = message.getOriginatingAddress();
if ("5556".equals(sender)){
//屏蔽手機號為5556的簡訊,這裡還可以時行一些處理,如把這個資訊發送到第三人的手機等等。
abortBroadcast();
}
System.out.println(message.getOriginatingAddress()+", "+message.getMessageBody()+", "+message.getIndexOnIcc());
}
}
}
}
}
測試的:
使用5556給5554傳送簡訊,5554無法收到。同時再起一個5558的avd給5554傳送簡訊,一切正常。
之所以這個程式能實現屏蔽系統簡訊的功能,是因為廣播有兩種不同的類型:普通廣播(normal broadcasts)和有序廣播(ordered broadcasts)。普通廣播是完全非同步,可以被所有的接收者接收到,並且接收者無法終止廣播的傳播。然而有序廣播是按照接收者聲明的優先順序別,被接收者依次接收到。優先順序別聲明在 intent-filter 元素的 android:priority 屬性中,數越大優先順序別越高,取值範圍:-1000到1000,優先順序別也可以調用IntentFilter對象的setPriority()進行設定。有序廣播的接收者可以終止廣播Intent的傳播,廣播Intent的傳播一旦終止,後面的接收者就無法接收到廣播。上面的執行個體就是將smsReceiver的優先順序設為1000。
其次我們需要實現onReceive方法,根據上面的代碼,我們可以從bundle中拿到簡訊內容並還原成SmsMessage,這樣我們可以根據特定條件來判斷哪些是需要我們攔截並且不要讓使用者知道的,哪些是我們可以允許存取的。需要我們攔截的簡訊,我們可以在收到後直接abortBroadcast()(上面的代碼中是判斷當簡訊內容包含hahaha的時候直接攔截),這樣系統收件匣將無法接收到該條簡訊,繼而也就不會有notification去通知使用者。
至此,應用編寫好之後,簡訊攔截功能就完成了,當然基於此還可以做一些其他功能,這方面就看需求了。注意,優先順序相同,則根據包名依次傳遞廣播。
想刪除收件匣中已存在的簡訊,請參考Android源碼SmsProvider類,可以在你的應用中使用ContentProvider機制進行操作。
Context.sendBroadcast()
發送的是普通廣播,所有訂閱者都有機會獲得並進行處理。
Context.sendOrderedBroadcast()
發送的是有序廣播,系統會根據接收者聲明的優先順序別按順序逐個執行接收者。
我查看了一下系統發送android.provider.Telephony.SMS_RECEIVED廣播的源碼SMSDispatcher.java(frameworks/base/telephony/java/com/android/internal/telephony),證實其發送的是有序廣播。
protected void dispatchPdus(byte[][] pdus) {
Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
intent.putExtra("pdus", pdus);
dispatch(intent, "android.permission.RECEIVE_SMS");
}
public void dispatch(Intent intent, String permission) {
// Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
// receivers time to take their own wake locks.
mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
mContext.sendOrderedBroadcast(intent, permission, mResultReceiver,
this, Activity.RESULT_OK, null, null);
}
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/prince58/archive/2011/03/10/6237792.aspx