今天讲一下最近项目中刚做的黑名单拦截,其中可以拦截短信和电话
先讲一下拦截电话的操作
首先要注册一个监听电话广播的广播接收器。
在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