android 黑名单中电话拦截

时间:2022-06-13 22:42:23

今天讲一下最近项目中刚做的黑名单拦截,其中可以拦截短信和电话

先讲一下拦截电话的操作

首先要注册一个监听电话广播的广播接收器。

在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