Android项目:手机安全卫士(10)—— 电话号码归属地显示

来源:互联网 发布:js满足条件自动跳转 编辑:程序博客网 时间:2024/05/21 00:55
 

Android项目:手机安全卫士(10)—— 电话号码归属地显示

1 概述

前一篇文章已经提供了电话号码的归属地查询功能,现在要做的,就是在打电话和来电显示的时候,显示一个电话归属地提示框,就像这样:


感觉很简单是不是,No,这个还费了一点功夫,首先是监听来电、去电,同时这个提示框是可以拖动的,而且这个提示框可以自定义风格,可以设置它的颜色,是否显示等,所以,并不简单。

关于项目相关文章,请访问:

  • Android 项目:手机安全卫士(5)—— 自定义弹窗
  • Android 项目:手机安全卫士(6)—— 手机防盗设置向导
  • Android 项目:手机安全卫士(6)—— 手机防盗设置向导(二)
  • Android 项目:手机安全卫士(7)—— 手机防盗功能
  • Android 项目:手机安全卫士(8)—— 管理员权限
  • Android 项目:手机安全卫士(9)—— 手机号码归属地查询

项目源码地址(实时更新):https://github.com/xwdoor/MobileSafe

2 监听来电

首先创建一个服务:AddressService,然后在里面监听来电,代码如下:

//获取电话管理器    mTM = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);    mPhoneListener = new PhoneListener(getApplicationContext());    mTM.listen(mPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);//监听来电
首先获得电话管理器,然后通过调用它的 listen() 方法开始监听,第一个参数是我们的回调方法,第二个参数是我们要监听的事件。PhoneListener 是需要自己实现的一个类,因为我们需要重写其中的 onCallStateChanged() 方法,具体代码如下:

/**     * 电话状态监听     *     * Created by XWdoor on 2016/3/11 011 13:50.     * 博客:http://blog.csdn.net/xwdoor     */    public class PhoneListener extends PhoneStateListener {        private Context mContext;        private View mView;        private WindowManager mWM;        public PhoneListener(Context context) {            mContext = context;        }        // 电话状态发生变化        @Override        public void onCallStateChanged(int state, String incomingNumber) {            super.onCallStateChanged(state, incomingNumber);            switch (state){                case TelephonyManager.CALL_STATE_RINGING://电话铃响                    String address = AddressQuery.getAddress(mContext, incomingNumber);                    showAddressBox(address);                    break;                case TelephonyManager.CALL_STATE_OFFHOOK://电话摘机                    break;                case TelephonyManager.CALL_STATE_IDLE://电话空闲                    closeAddressBox();                    break;            }        }        /**         * 显示电话归属地提示框         *         * @param address         */        public void showAddressBox(String address){            Log.i(BaseActivity.TAG_LOG,"电话归属地-->"+address);        }        /**         * 关闭电话归属地提示框         */        public void closeAddressBox(){        }    }

现在主要实现了代码逻辑,功能还没有做,先不用管它,可以打印一条日志。这样我们就可以监听来电了,并且在 showAddressBox() 方法中弹出提示框。

3 监听去电(打电话)

监听打电话与监听来电略有不同,需要监听广播。创建一个广播 CallReceiver,并传入 PhoneListener 对象,因为我们要用到归属地提示框的显示与关闭,代码如下:

/**     * 打电话监听:去电监听     *     * Created by XWdoor on 2016/3/11 011 13:44.     * 博客:http://blog.csdn.net/xwdoor     */    public class CallReceiver extends BroadcastReceiver {        private final PhoneListener mPhoneListener;        public CallReceiver(PhoneListener phoneListener) {            this.mPhoneListener = phoneListener;        }        @Override        public void onReceive(Context context, Intent intent) {            String number = getResultData();//获取电话号码            String address = AddressQuery.getAddress(context, number);            //ToastUtils.showToast(context, "去电地址-->" + address + ",去电号码-->" + number);            mPhoneListener.showAddressBox(address);        }    }

当然,去电监听是需要权限的:<uses-permission Android:name="android.permission.PROCESS_OUTGOING_CALLS" /> 
创建完广播后,因为是否显示归属地提示框是可以进行设置的,所以该广播不能在清单文件中进行注册,那样就不能停止了,我们需要在代码中进行注册,我选择在服务 AddressService 中进行注册,代码如下:

 //监听去电    mCallReceiver = new CallReceiver(mPhoneListener);    IntentFilter filter = new IntentFilter();    filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);    registerReceiver(mCallReceiver,filter);
当然,在服务停止的时候,我们需要注销监听:

  @Override    public void onDestroy() {        super.onDestroy();        //取消监听来电        mTM.listen(mPhoneListener,PhoneStateListener.LISTEN_NONE);        //取消监听去电        unregisterReceiver(mCallReceiver);        mCallReceiver = null;    }

4 开启服务

在 activity_setting.xml 文件中增加一个 item,用于设置归属地服务是否开启:

 <net.xwdoor.mobilesafe.view.SettingItemView        android:id="@+id/siv_address"        android:layout_width="match_parent"        android:layout_height="wrap_content"        xwdoor:stitle="电话归属地显示设置"        xwdoor:desc_on="归属地显示已开启"        xwdoor:desc_off="归属地显示已关闭"/>
后台代码如下:

/**     * 初始化归属地设置     */    private void initAddress() {        final SettingItemView sivAddress = (SettingItemView) findViewById(R.id.siv_address);        // 根据服务是否运行来更新checkbox        boolean serviceRunning = ServiceStatusUtils.isServiceRunning(this,                "net.xwdoor.mobilesafe.service.AddressService");        sivAddress.setChecked(serviceRunning);        sivAddress.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                sivAddress.setChecked(!sivAddress.isChecked());                Intent service = new Intent(SettingActivity.this, AddressService.class);                if(sivAddress.isChecked()){                    startService(service);//开启电话归属地显示服务                }else {                    stopService(service);//关闭电话归属地服务                }            }        });    }
首先判断该服务是否已经运行,然后设置 item 的状态,判断服务是否运行的代码如下所示。然后设置 item 的点击事件,根据用户的选择来动态启动或关闭归属地显示服务。

/**     * 判断服务是否正在运行     * @param context     * @param serviceName     * @return     */    public static boolean isServiceRunning(Context context, String serviceName) {        //获取活动管理器        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);        //获取当前正在运行的服务,最多返回100条记录        List<ActivityManager.RunningServiceInfo> runningServices = am.getRunningServices(100);        for(ActivityManager.RunningServiceInfo service : runningServices){            // 获取服务名称,并判断            if(serviceName.equals(service.service.getClassName())){                return true;            }        }        return false;    }

5 显示归属地提示框

以上的工作就可以正常打印日志了,但是还没有具体的提示框出现,现在就来实现我们的提示框,实现原理参照系统的 Toast,因为只有它可以在另一个应用运行时进行显示,额,可以这么说,Toast 显示的时候,可以运行其他任何 app。首先创建一个布局文件,里面就只有一个 TextView,这里就不写了,相信写了那么多的 UI 布局,这个可以轻松搞定。

然后,我么就可以实现 PhoneListener 中的两个方法了:

/**     * 显示电话归属地提示框     * 需要权限:android.permission.SYSTEM_ALERT_WINDOW     *     * @param address     */    public void showAddressBox(String address){        Log.i(BaseActivity.TAG_LOG,"电话归属地-->"+address);        //窗口管理器, 系统最顶级的界面布局, 所有东西都展示在窗口上,activity,状态栏        mWM = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);        //初始化布局参数        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();        params.height = WindowManager.LayoutParams.WRAP_CONTENT;        params.width = WindowManager.LayoutParams.WRAP_CONTENT;        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE                // | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;        params.format = PixelFormat.TRANSLUCENT;        params.type = WindowManager.LayoutParams.TYPE_PHONE;// 提高类型级别,保证可以触摸移动        params.gravity = Gravity.CENTER;// 将重心设置在左上方位置,和屏幕坐标体系重合,方便修改窗口的位置        // 初始化布局        mView = View.inflate(mContext, R.layout.dialog_address_box, null);        TextView tvAddress = (TextView) mView.findViewById(R.id.tv_address);        tvAddress.setText(address);        // 给窗口添加布局        mWM.addView(mView, params);    }    /**     * 关闭电话归属地提示框     */    public void closeAddressBox(){        if (mWM != null && mView != null) {            mWM.removeView(mView);// 电话挂断后,移除窗口布局        }    }

别看这么复杂,其中初始化布局参数那一段代码都是从系统 Toast 的源码中复制过来的,所以,呵呵。有了以上的代码,运行效果就跟文章图片中展示的一样了。

6 总结

我觉得这篇文章也是属于干货,学到的知识点有:

  • 监听来电,获取来电号码,实现电话拦截
  • 监听去电,记录行为
  • WindowManager、ActivityManager、TelephonyManager 的使用

由于篇幅的限制,还有一部分功能没有实现,就是我们的归属地的自定义风格,可拖拽等效果,没办法,只能放到下篇了。

关于项目相关文章,请访问:

  • Android 项目:手机安全卫士(5)—— 自定义弹窗
  • Android 项目:手机安全卫士(6)—— 手机防盗设置向导
  • Android 项目:手机安全卫士(6)—— 手机防盗设置向导(二)
  • Android 项目:手机安全卫士(7)—— 手机防盗功能
  • Android 项目:手机安全卫士(8)—— 管理员权限
  • Android 项目:手机安全卫士(9)—— 手机号码归属地查询

项目源码地址(实时更新):https://github.com/xwdoor/MobileSafe


转发自:http://blog.csdn.net/xwdoor/article/details/50857147










阅读全文
0 0