加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

仿360手机卫士之查询号码归属地

发布时间:2020-12-12 19:22:13 所属栏目:百科 来源:网络整理
导读:360手机卫士里基本的功能–查询来电归属地 技术要点大概如下 - 对最新号码归属地数据的压缩与解压 - sqlite3数据库的基本操作 - 监听手机来电 - 自定义Toast 准备操作 最新号码归属地数据库,这里有一份但不是最新的https://pan.baidu.com/s/1bpKSghT,这是

360手机卫士里基本的功能–查询来电归属地

技术要点大概如下
- 对最新号码归属地数据的压缩与解压
- sqlite3数据库的基本操作
- 监听手机来电
- 自定义Toast


准备操作
最新号码归属地数据库,这里有一份但不是最新的https://pan.baidu.com/s/1bpKSghT,这是压缩过的2兆多,解压后40多兆,本来更大,这里将一个表拆成多表,减少数据冗余,其实里面的表还可以拆分,更大程度的减少数据冗余,只是查询上会造成单表查询变成多表查询,不过这种拆分应该是值得的。

1.解压
前面准备的数据库其实已经压缩过了,是用下面的工具类ZipUtil实现的,用360压缩也是ok的,亲测一样。压缩过的(链接中下载到的)放到assets目录下,启动应用程序的时候解压缩,或者用到的时候再解压,暂称为懒解压。工具类ZipUtil如下:

/** * 压缩 * @param filePath * @param savePath * @throws Exception */
    public static void compress(String filePath,String savePath) throws Exception{
        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(  
                savePath));
        BufferedOutputStream bos = new BufferedOutputStream(out);
        File file = new File(filePath);

        zip(out,file,file.getName(),bos);

        if(bos != null){
            bos.close();
        }
        if(out != null){
            out.close();
        }
    }

    private static int k = 0;
    private static void zip(ZipOutputStream out,File f,String base,BufferedOutputStream bo) throws Exception { // 方法重载 
        if (f.isDirectory()) {  
            File[] fl = f.listFiles();  
            if (fl.length == 0) {  
                out.putNextEntry(new ZipEntry(base + "/")); // 创建zip压缩进入点base 
                System.out.println(base + "/");  
            }  
            for (int i = 0; i < fl.length; i++) {  
                zip(out,fl[i],base + "/" + fl[i].getName(),bo); // 递归遍历子文件夹 
            }  
            System.out.println("第" + k + "次递归");  
            k++;  
        } else {  
            out.putNextEntry(new ZipEntry(base)); // 创建zip压缩进入点base 
            System.out.println(base);  
            FileInputStream in = new FileInputStream(f);  
            BufferedInputStream bi = new BufferedInputStream(in);  
            int b;  
            while ((b = bi.read()) != -1) {  
                bo.write(b); // 将字节流写入当前zip目录 
            }  
            bi.close();  
            in.close(); // 输入流关闭 
        }  
    }
    /** * 解压缩 * @param filePath 源文件路径 * @param rootPath 要解压到哪个文件夹下 * @throws Exception */
    public static void uncompress(String filePath,String rootPath) throws Exception{
        ZipInputStream zis=new ZipInputStream(new FileInputStream(  
                filePath));//输入源zip路径 
        BufferedInputStream bis=new BufferedInputStream(zis);  
        File fOut=null;  
        ZipEntry entry;
        while((entry = zis.getNextEntry())!=null){
            if(entry.isDirectory()){
                continue;
            }
            fOut=new File(rootPath,entry.getName());  
            if(!fOut.exists()){  
                (new File(fOut.getParent())).mkdirs();  
            }  
            FileOutputStream out=new FileOutputStream(fOut);  
            BufferedOutputStream Bout=new BufferedOutputStream(out);  
            int b;  
            while((b=bis.read())!=-1){  
                Bout.write(b);  
            }
            Bout.flush();
            Bout.close();  
            out.close();  
        }
        bis.close();  
        zis.close();
    }

ok,解压完成,40多兆的东西进了手机,流汗!

2.监听来电,自定义toast
用后台开启服务的方式监听手机来电

public class MonitorPhoneService extends Service {

    private static final String TAG = "MonitorPhoneService";

    private WindowManager windowManager;
    private TelephonyManager manager;
    private MyListener listener;
    private View view;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        listener = new MyListener();
        manager.listen(listener,PhoneStateListener.LISTEN_CALL_STATE);
    }

    private class MyListener extends PhoneStateListener {
        @Override
        public void onCallStateChanged(int state,String incomingNumber) {
            super.onCallStateChanged(state,incomingNumber);
            switch (state) {
                case TelephonyManager.CALL_STATE_IDLE:  //处于静止状态,没有呼叫
                    if (view != null) { //这里及时移除view(自定义toast)
                        windowManager.removeView(view);
                        view = null;
                    }
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK:  //接通状态
                    if (view != null) { //同上
                        windowManager.removeView(view);
                        view = null;
                    }
                    break;
                case TelephonyManager.CALL_STATE_RINGING:  //铃响状态
                    showAddress(incomingNumber);
                    break;
            }
        }
    }

    //显示归属地,自定义Toast
    private void showAddress(String incomingNumber) {
        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.format = PixelFormat.TRANSLUCENT;
        params.type = WindowManager.LayoutParams.TYPE_TOAST;
        params.setTitle("Toast");
        params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
        view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.toast_query_address,null);
        TextView tv = (TextView) view.findViewById(R.id.tv_toast_query_address);
        //这里操作数据库查询号码归属地
        tv.setText(new QueryAddressEngine(getApplicationContext()).queryAddress(incomingNumber));
        tv.setTextSize(20);
        windowManager.addView(view,params);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        manager.listen(listener,PhoneStateListener.LISTEN_NONE);
        listener = null;
    }
}

只需启动服务监听就行了,还要添加权限

<uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />

3.查询号码归属地
这里只用对数据库进行查-DQL

public class QueryAddressEngine {

    private Context mContext;

    public QueryAddressEngine(Context mContext) {
        this.mContext = mContext;
    }

    public String queryAddress(String number) {
        //匹配手机号可以写成工具类
        String pattern = "^1[3458]d{9}$";
        String result = number;
        int type = -1;
        String city = "";
        String province = "";
        if(number.matches(pattern)){ //手机号码
            SQLiteDatabase database = DbDao.getDatabase(mContext);
            if(database.isOpen()){
                Cursor cursor = database.rawQuery(
                        "select province,city,type from phone where mobilepre = ? limit 1",new String[]{number.substring(0,7)});
                if(cursor.moveToNext()){
                    city = cursor.getString(cursor.getColumnIndex("city"));
                    type = cursor.getInt(cursor.getColumnIndex("type"));
                    province = cursor.getString(cursor.getColumnIndex("province"));
                }
                result = province + " " + city + " " + getOperatorByType(type);
                cursor.close();
                database.close();
            }
        } else {  //固定电话
            int len = number.length();
            SQLiteDatabase db;
            switch (len){
                case 4: //模拟器
                    result = "模拟器";
                    break;
                case 7: //本地号码
                case 8: //本地号码
                    result = "本地号码";
                    break;
                case 10: //3位区号 + 7位号码
                    db = DbDao.getDatabase(mContext);
                    if(db.isOpen()){
                        Cursor cursor = db.rawQuery(
                                "select province,type from phone where areacode = ? limit 1",3)});
                        if(cursor.moveToNext()){
                            city = cursor.getString(cursor.getColumnIndex("city"));
                            type = cursor.getInt(cursor.getColumnIndex("type"));
                            province = cursor.getString(cursor.getColumnIndex("province"));
                        }
                        result = province + " " + city + " " + getOperatorByType(type);
                        cursor.close();
                        db.close();
                    }
                    break;
                case 11:  //3位区号 + 8位号码 4位区号 + 7位号码
                    SQLiteDatabase db2 = DbDao.getDatabase(mContext);
                    if(db2.isOpen()){
                        Cursor cursor = db2.rawQuery(
                                "select province,3)});
                        if(cursor.moveToNext()){
                            city = cursor.getString(cursor.getColumnIndex("city"));
                            type = cursor.getInt(cursor.getColumnIndex("type"));
                            province = cursor.getString(cursor.getColumnIndex("province"));
                        } else {
                            Cursor cursor2 = db2.rawQuery(
                                    "select province,4)});
                            if(cursor.moveToNext()){
                                city = cursor.getString(cursor.getColumnIndex("city"));
                                type = cursor.getInt(cursor.getColumnIndex("type"));
                                province = cursor.getString(cursor.getColumnIndex("province"));
                            }
                            cursor2.close();
                        }
                        result = province + " " + city + " " + getOperatorByType(type);
                        cursor.close();
                        db2.close();
                    }
                    break;
                case 12: //4位区号 +8位号码
                    db = DbDao.getDatabase(mContext);
                    if (db.isOpen()) {
                        Cursor cursor = db.rawQuery(
                                "select province,new String[] { number.substring(0,4) });
                        if(cursor.moveToNext()){
                            city = cursor.getString(cursor.getColumnIndex("city"));
                            type = cursor.getInt(cursor.getColumnIndex("type"));
                            province = cursor.getString(cursor.getColumnIndex("province"));
                        }
                        result = province + " " + city + " " + getOperatorByType(type);
                        cursor.close();
                        db.close();

                    }

                    break;
            }
        }
        return result;
    }

    public String getOperatorByType(int type){
        String operator = "未知";
        switch (type){
            case 1:
                operator = "移动";
                break;
            case 2:
                operator = "联通";
                break;
            case 3:
                operator = "电信";
                break;
            case 4:
                operator = "虚拟运营商";
                break;
        }
        return operator;
    }
}

public class DbDao {

    public static SQLiteDatabase getDatabase(Context mContext){
        return new DbHelper(mContext).getWritableDatabase();
    }
}

public class DbHelper extends SQLiteOpenHelper {

    public DbHelper(Context context){
        this(context,Db.NAME,null,Db.VERSION);
    }

    public DbHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version) {
        super(context,name,factory,version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion) {

    }
}

好了,写完收工领盒饭

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读