今天講一下最近項目中剛做的黑名單攔截,其中可以攔截短信和電話
先講一下攔截電話的操作
首先要註冊一個監聽電話廣播的廣播接收器。
在Manifest文件中
<receiver android:name=".Receiver.InterceptSmsReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="2147483647"> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>同時還要添加讀取電話記錄,寫入電話記錄,以及監聽電話的權限
<uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.WRITE_CALL_LOG" /> <uses-permission android:name="android.permission.READ_CALL_LOG" />
現在來說一下攔截電話的邏輯
使用廣播接收器監聽電話廣播,如果發現來電號碼存在於黑名單中,那麼就endCall(),這時要注意通話記錄中是都存在需要攔截的號碼的電話記錄,如果存在的話,要通過ContentResolver將其刪除掉。
public class InterceptCallReceiver extends BroadcastReceiver { private static final String TAG = "interceptcall"; public InterceptCallReceiver() { } @Override public void onReceive(Context context, Intent intent) { SharedPreferences mSp = context.getSharedPreferences("config", Context.MODE_PRIVATE); boolean BlackNumStatus = mSp.getBoolean("BlackNumStatus", true); if (!BlackNumStatus) { return; } BlackNumberDBOperation operation = new BlackNumberDBOperation(context); if (!intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) { String mIncomingNumber = ""; /**來電**/ TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); switch (telephonyManager.getCallState()) { case TelephonyManager.CALL_STATE_RINGING: mIncomingNumber = intent.getStringExtra("incoming_number"); int blackContactMode = operation.getBlackContactMode(mIncomingNumber); /**這裏的Opration是一個實體類的操作類,用戶與查詢黑名單是都存在,並返回攔截模式**/ if (blackContactMode == 1 || blackContactMode == 3) { /** * 觀察呼叫記錄(其他的應用程序,像是手機通訊錄程序)的變化 * 如果生成了呼叫記錄,就把呼叫記錄刪除掉 */ Uri uri = Uri.parse("content://call_log/calls"); context.getContentResolver().registerContentObserver(uri, true, new CallLogObserver(new Handler(), mIncomingNumber, context)); endCall(context); } break; } } } private class CallLogObserver extends ContentObserver { /** * Creates a content observer. * * @param handler The handler to run {@link #onChange} on, or null if none. */ private String incomingNumber; private Context context; public CallLogObserver(Handler handler, String incomingNumber, Context context) { super(handler); this.incomingNumber = incomingNumber; this.context = context; } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); Log.d(TAG, "呼叫數據庫的內容變化了"); context.getContentResolver().unregisterContentObserver(this); deleteCallLog(incomingNumber, context); } } /** * 清除呼叫記錄 * @param incomingNumber * @param context */ public void deleteCallLog(String incomingNumber, Context context) { ContentResolver resolver = context.getContentResolver(); Uri uri = Uri.parse("content://call_log/calls"); Cursor cursor = resolver .query(uri, new String[]{"_id"}, "number=?", new String[]{incomingNumber}, "_id desc limit 1"); if (cursor.moveToNext()) { String id = cursor.getString(0); resolver.delete(uri, "_id", new String[]{id}); } } /** * 掛斷電話需要複製兩個AIDL(利用反射) */ public void endCall(Context context){ try { Class clazz=context.getClassLoader().loadClass("android.os.Service Manager"); Method method=clazz.getDeclaredMethod("getService",String.class); IBinder iBinder = (IBinder) method.invoke(null,Context.TELEPHONY_SERVICE); ITelephony itelephony = ITelephony.Stub.asInterface(iBinder); itelephony.endCall(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
最後,需要講的是程序掛斷電話,需要通過反射得到ITelephony接口。
需要將android源碼中的兩個AIDL複製到程序目錄中。
一個是ITelephony.aidl,需要建立一個與其包名一致的包com.android.internal.telephony(在src下建立的是com/android/internal/telephony),然後將其複製到包下
還有一個則是與ITelephony關聯的AIDL文件,NeighboringCellInfo.aidl,它所在的包是android.telephony,如上方法創建
兩個AIDL文件的下載路徑:http://pan.baidu.com/s/1pLrh9VX
密碼:y4fw