[mobilesafe] 04_黑名单电话拦截

Android 4.0

黑名单电话拦截

一、黑名单电话拦截步骤: CallSmsSafeService  
1、注册一个电话状态的服务 TelephonyManager
2、当有电话打进来的时候,判断是否在黑名单中
3、在设置中心看是否设置了开启黑名单拦截功能
4、如果开启了,且在黑名单中,那么立刻挂断该电话
挂断电话监听服务:CallSmsSafeService.java
package cn.zengfansheng.mobilesafe.service;
import java.lang.reflect.Method;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import cn.zengfansheng.mobilesafe.db.dao.BlackNumberDao;
import com.android.internal.telephony.ITelephony;
/**
 * 3、黑名单电话短信监听服务
 * @author hacket
 */
public class CallSmsSafeService extends Service {
    private TelephonyManager tm;// 电话管理者
    private PhoneStateListener listener;// 电话状态监听器
    private BlackNumberDao blackNumberDao;// 黑名单dao
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    // 1、服务开启时
    @Override
    public void onCreate() {
        super.onCreate();
        blackNumberDao = new BlackNumberDao(getApplicationContext());
        // 初始化电话管理者
        tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        listener = new MyPhoneStateListener();
        tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
    }
    // 2、服务停止时
    @Override
    public void onDestroy() {
        super.onDestroy();
        tm.listen(listener, PhoneStateListener.LISTEN_NONE);
        listener = null;
    }
    
    private class MyPhoneStateListener extends PhoneStateListener {
        private static final String TAG = "MyPhoneStateListener";
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);
            switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:// 电话响铃的时候,查找数据库来电号码是否在黑名单数据库中
                String blacknumberMode = blackNumberDao.getBlackNumberMode(incomingNumber);
                // 检查当前的号码是否需要拦截,如果需要,挂断电话
                if (!TextUtils.isEmpty(blacknumberMode)) {
                    if ("1".equals(blacknumberMode) || "3".equals(blacknumberMode)) {// 拦截模式为"1",即电话拦截;或者"3",全部拦截
                        Log.i(TAG"拦截黑名单:" + incomingNumber);
                        endCall();// 挂断电话
                        return;
                    }
                }
                break;
            }
        }
        /**
         * 3、挂断电话
         */
        private void endCall() {
            // IBinder b = ServiceManager.getService(LOCATION_SERVICE);
            //利用反射来找到,因为系统给隐藏了
            try {
                Class<?> clazz = getClassLoader().loadClass("android.os.ServiceManager");
                Method method = clazz.getDeclaredMethod("getService", String.class);
                IBinder b = (IBinder) method.invoke(nullTELEPHONY_SERVICE);
                // IBinder 转成接口类型
                ITelephony asInterface = ITelephony.Stub.asInterface(b);
                asInterface.endCall();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
挂断电话核心代码:
/**
 * 3、挂断电话
 */
private void endCall() {
    // IBinder b = ServiceManager.getService(LOCATION_SERVICE);
    //利用反射来找到,因为系统给隐藏了
    try {
        Class<?> clazz = getClassLoader().loadClass("android.os.ServiceManager");
        Method method = clazz.getDeclaredMethod("getService", String.class);
        IBinder b = (IBinder) method.invoke(nullTELEPHONY_SERVICE);
        // IBinder 转成接口类型
        ITelephony asInterface = ITelephony.Stub.asInterface(b);
        asInterface.endCall();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Android平台源码和系统源码区别
Android API16平台源码:
\sdk\sources\android-16\android\
Android所有源码:上面的源码只是Android所有源码中的一小部分
\aosp_jb422\frameworks\base\core\java\android\
如何查看一些抽象类的实现(系统源码):比如Context,PackageManager
public abstract class PackageManager{}
public abstract class Context{} 
问题:可以看到这些都是一些抽象类,没有具体的实现
解决:在syso处断点,然后通过断点调试的方式,找到默认实现类
public void click(View view){
    PackageManager pm = getPackageManager();
    Context context = getApplicationContext();
    System.out.println("------");
}  
可以看出Context默认的实现类为ContextImpl
PageageManager的默认实现类为IPackageManager
TelephonyManager中的endCall()在后面的版本给屏蔽掉了
所以需要利用反射给找到
1、查看系统源码 IBinder b = ServiceManager.getService(LOCATION_SERVICE);  
2、利用反射
Class<?> clazz = getClassLoader().loadClass("android.os.ServiceManager");
Method method = clazz.getDeclaredMethod("getService", String.class);
IBinder b = (IBinder) method.invoke(nullTELEPHONY_SERVICE);  
3、IBinder转成接口类型,aidl
a)搜ITelephony.aidl
\frameworks\base\telephony\java\com\android\internal\telephony\ITelephony.aidl
b)找到ITelephony.aidl的包名
com.android.internal.telephony;
{@hide}表示隐藏的
c)然后在工程中创建相同的包名,将该ITelephony.aidl给拷贝进去
d)这两个地方报错,说明缺少这个两个文件,继续找

\frameworks\base\telephony\java\android\telephony\NeighboringCellInfo.aidl
\frameworks\base\telephony\java\android\telephony\CellInfo.aidl
e)然后创建包名,将aidl文件复制进来
问题1:权限
<uses-permission android:name="android.permission.CALL_PHONE" />  
问题2:通话记录还有通话记录电话拨号的记录