系统通话界面 自定义来电显示

上一篇文章写了使用WindowManager实现从自己的app界面拨打电话调用系统通话展示自定义布局。这一篇文章主要介绍一下使用BroadcastReceiver、Service配合WindowManager实现当有电话打进来时,搜索该号码是否是自己app内的用户(好友),显示特定的信息。

既然使用了BroadcastReceiver和Service,首先先介绍一下BroadcastReceiver和Service吧。

1.BroadcastReceiver

BroadcastReceiver顾名思义就是广播接收器,广播分为广播接收者和发送者,属于Android四大组件之一,用于监听 / 接收 应用 App 发出的广播消息,并 做出响应。
BroadcastReceiver的注册分为两种:静态注册和动态注册。
(一)静态注册:在清单文件中通过标签声明,同时声明要接收的action。
当此 App首次启动时,系统会自动实例化该BroadcastReceiver类,并注册到系统中,至此它的声明周期就和该app没什么关系了,android不能自动销毁广播接收器,也就是说当应用程序关闭后,还是会接收广播。
例如:

 <receiver android:name=".PhoneReceive">
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE"/>
                <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
                <action android:name="com.ckw.CUSTOM_PHONE"/>
            </intent-filter>
        </receiver>

(二)动态注册:在代码中调用Context.registerReceiver()方法注册,这里不再多说。动态注册的广播接收器的声明周期和宿主的声明周期一致,当宿主被destroy了,它也就被销毁了。

2.Service

Service也是Android的四大组件之一,可以使用Service在后台执行耗时操作,例如下载。
Service的启动方式也分为两种
(一)startService:
其他组件通过调用startService方法,启动service。service会一直运行在后台,即使启动它的组件已经被销毁了。
例如:

Intent ringingIntent = new Intent(mContext,PhoneService.class); 
ringingIntent.putExtra("phoneState",TelephonyManager.CALL_STATE_RINGING);
mContext.startService(ringingIntent);

这种方式需要在清单文件中注册服务:

<service android:name=".PhoneService"/>

(二)bindService:
其他组件调用bindService()方法绑定一个Service。多个组件可与一个service绑定,service不再与任何组件绑定时,该service会被destroy。
这种方式的service可以通过与Activity绑定,来实现与Activity的通信,这里不再多说。

3.功能实现:
这里用到了静态注册的BroadcastReceiver和startService方式创建的Service。
来电界面显示的具体流程如图:
这里写图片描述

来电之后,通过App内部的广播通过PhoneStateListener接收系统广播的Action,
接着开启Service,之后将App内需要展示的信息(通过本地读取或者网络请求拿到),
将这些信息传给Service。让Service创建WindowManager来绘制自定义的界面,并将信息显示到来电界面。

下面直接贴上代码吧:
(一):Service

public class PhoneService extends Service{
    /**
     * 用于在线程中创建或移除悬浮窗。
     */
    private Handler handler = new Handler();

    /**
     * 定时器,定时进行检测当前应该创建还是移除悬浮窗。
     */
    private Timer timer;
    private int mPhoneState;//0 挂断 1 来电 2 通话中 3 主动拨号

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mPhoneState = intent.getIntExtra("phoneState",0);
        String userName = "";
        String userDep = "";
        if(mPhoneState == 3 || mPhoneState == 1){//拨打电话 这里后面还需要加个 1的类型
            userName = intent.getStringExtra("userName");
            userDep = intent.getStringExtra("userDep");
        }
        // 开启定时器,每隔0.5秒刷新一次
        if (timer == null) {
            timer = new Timer();
            timer.scheduleAtFixedRate(new RefreshTask(userName,userDep), 0, 500);
        }
        return super.onStartCommand(intent, flags, startId);
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        // Service被终止的同时也停止定时器继续运行
        timer.cancel();
        timer = null;
    }

    class RefreshTask extends TimerTask {
        private String userName;
        private String userDep;
        public RefreshTask(String userName,String userDep) {
            this.userName = userName;
            this.userDep = userDep;
        }

        @Override
        public void run() {
            if(!isHome() && !PhoneWindowManager.isWindowShowing()){
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        PhoneWindowManager.createBigWindow(getApplicationContext(),userName,userDep);
                    }
                });
            }
            // 当前界面是桌面,且有悬浮窗显示,则移除悬浮窗。
            if (isHome() || mPhoneState == 0) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        PhoneWindowManager.removeBigWindow(getApplicationContext());
                        Intent intent = new Intent(getApplicationContext(), PhoneService.class);
                        getApplicationContext().stopService(intent);
                    }
                });
            }

        }

    }


    /**
     * 判断当前界面是否是桌面
     */
    private boolean isHome() {
        ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
        return getHomes().contains(rti.get(0).topActivity.getPackageName());
    }

    /**
     * 获得属于桌面的应用的应用包名称
     *
     * @return 返回包含所有包名的字符串列表
     */
    private List<String> getHomes() {
        List<String> names = new ArrayList<String>();
        PackageManager packageManager = this.getPackageManager();
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
                PackageManager.MATCH_DEFAULT_ONLY);
        for (ResolveInfo ri : resolveInfo) {
            names.add(ri.activityInfo.packageName);
        }
        return names;
    }


}

(二)BroadcastReceiver:

public class PhoneReceive extends BroadcastReceiver implements PhoneInfoContract.View{

    private Context mContext;

    @Inject
    PersonalAffairsApi personalAffairsApi;

    @Inject
    HttpManager httpManager;

    @Override
    public void onReceive(Context context, Intent intent) {
        mContext = context;

        if (intent.getAction().equals("com.ckw.CUSTOM_PHONE")) {//从自己的程序里发出的,拨打电话
            String userName = intent.getStringExtra("userName");
            String userDep = intent.getStringExtra("userDep");
            Intent phoneIntent = new Intent(context, PhoneService.class);
            phoneIntent.putExtra("userName", userName);
            phoneIntent.putExtra("userDep", userDep);
            phoneIntent.putExtra("phoneState", 3);
            context.startService(phoneIntent);
        }
        //如果是去电
        else if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
            //主动拨打电话的话,会经过这里,但是我们用上面的代码,因为需要传自己的数据过来
        } else {
            //设置一个监听器
            TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
            tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
        }
    }


    PhoneStateListener listener = new PhoneStateListener(){
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            //注意,方法必须写在super方法后面,否则incomingNumber无法获取到值。
            super.onCallStateChanged(state, incomingNumber);
            switch(state){
                case TelephonyManager.CALL_STATE_IDLE:
                    Intent phoneIntent = new Intent(mContext,PhoneService.class);
                    phoneIntent.putExtra("phoneState",TelephonyManager.CALL_STATE_IDLE);
                    mContext.startService(phoneIntent);
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK://应该是打电话的状态,通话中
                    break;
                case TelephonyManager.CALL_STATE_RINGING://响铃,比如来电
                    String userId = DbHelper.getUserId(mContext);
                    PhoneInfoPresenter phoneInfoPresenter = new PhoneInfoPresenter(PhoneReceive.this,mContext);
                    phoneInfoPresenter.getPhoneInfo(incomingNumber,userId);
                    break;
            }
        }
    };


    @Override
    public void showPhoneInfoResult(PhoneInfo info) {
        //在这里开启service
        Intent ringingIntent = new Intent(mContext,PhoneService.class);
                    ringingIntent.putExtra("userName",info.getXm());
                    ringingIntent.putExtra("userDep",info.getDepname());
        ringingIntent.putExtra("phoneState",TelephonyManager.CALL_STATE_RINGING);
        mContext.startService(ringingIntent);

    }

    @Override
    public boolean isActive() {
        return true;
    }

    @Override
    public void showError(String msg) {
        Log.d("----", "showError: "+msg);
    }

    @Override
    public void setPresenter(PhoneInfoPresenter presenter) {

    }



    @Override
    public void showProgressDialog(String msg) {

    }

    @Override
    public void hideProgressDialog() {

    }
}

(三)自定义的WindowManager:

public class PhoneWindowManager {

    /**
     * 显示的view
     */
    private static FloatWindowView mFloatWindowView;


    /**
     * 悬浮窗View的参数
     */
    private static WindowManager.LayoutParams bigWindowParams;

    /**
     * 用于控制在屏幕上添加或移除悬浮窗
     */
    private static WindowManager mWindowManager;

    /**
     * 用于获取手机可用内存
     */
    private static ActivityManager mActivityManager;



    /**
     * 创建一个悬浮窗。位置为屏幕正中间。
     *
     * @param context
     *            必须为应用程序的Context.
     */
    public static void createBigWindow(Context context,String userName,String userDep) {
        WindowManager windowManager = getWindowManager(context);
        if (mFloatWindowView == null) {
            mFloatWindowView = new FloatWindowView(context,userName,userDep);
            if (bigWindowParams == null) {
                bigWindowParams = new WindowManager.LayoutParams();
                bigWindowParams.x = 0;
                bigWindowParams.y = 0;
                bigWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                bigWindowParams.type = WindowManager.LayoutParams.TYPE_PHONE;
                bigWindowParams.format = PixelFormat.RGBA_8888;
                bigWindowParams.gravity = Gravity.CENTER;
                bigWindowParams.height = FloatWindowView.viewHeight;
                bigWindowParams.width = FloatWindowView.viewWidth;
            }
            windowManager.addView(mFloatWindowView, bigWindowParams);
        }
    }

    /**
     * 将悬浮窗从屏幕上移除。
     *
     * @param context
     *            必须为应用程序的Context.
     */
    public static void removeBigWindow(Context context) {
        if (mFloatWindowView != null) {
            WindowManager windowManager = getWindowManager(context);
            windowManager.removeView(mFloatWindowView);
            mFloatWindowView = null;
        }
    }


    /**
     * 是否有悬浮窗显示在屏幕上。
     *
     * @return 有悬浮窗显示在桌面上返回true,没有的话返回false。
     */
    public static boolean isWindowShowing() {
        return mFloatWindowView != null;
    }

    /**
     * 如果WindowManager还未创建,则创建一个新的WindowManager返回。否则返回当前已创建的WindowManager。
     *
     * @param context
     *            必须为应用程序的Context.
     * @return WindowManager的实例,用于控制在屏幕上添加或移除悬浮窗。
     */
    private static WindowManager getWindowManager(Context context) {
        if (mWindowManager == null) {
            mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        }
        return mWindowManager;
    }

    /**
     * 如果ActivityManager还未创建,则创建一个新的ActivityManager返回。否则返回当前已创建的ActivityManager。
     *
     * @param context
     *            可传入应用程序上下文。
     * @return ActivityManager的实例,用于获取手机可用内存。
     */
    private static ActivityManager getActivityManager(Context context) {
        if (mActivityManager == null) {
            mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        }
        return mActivityManager;
    }

    /**
     * 获取当前可用内存,返回数据以字节为单位。
     *
     * @param context
     *            可传入应用程序上下文。
     * @return 当前可用内存。
     */
    private static long getAvailableMemory(Context context) {
        ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
        getActivityManager(context).getMemoryInfo(mi);
        return mi.availMem;
    }
}

(四)自定义的显示布局:
根据自己的需求来,这里就不贴了。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
电话录音管理软件功能介绍: 1、当客户来电时,电脑上能快速弹出客户的详细信息,如姓名,电话,地址,证件号码及以往的业务记录等,即:来电弹屏功能(也有叫来电弹屏软件) 2、显示号码所在地、区号、手机卡类型信息。自动区分手机、固定电话等。 3、客户相关信息调取显示功能。软件支持相关信息显示内容的个性化配置,您可以在相关信息里调取客户的消费记录、采购历史、个人偏好、来访记录等等。4、客户信息即时添加。如果来电号码是陌生号码,操作人员可以在接电话的同时询问并添加客户信息。 5、客户来电内容备忘信息管理。来电内容可以即时备忘,随时查看及编辑、删除等。 6、客户资料管理功能。您可以利用数据管理器很方便地对客户资料进行修改和删除等操作。 7、数据查找功能支持“等于”、“小于”、“大于”、“模糊”等方式,可以快速查找数据。 8、今天所有的来电进行汇总。在今日来电栏,可以看到今天几点几分有什么电话打进来,点击号码,即会显示出该客户的详细信息。 9、系统挂起功能。操作员离开的时候,可以使用系统挂起功能。除非操作员本人输入密码,否则任何人都无法查看和操作软件,保证系统数据的安全性。 10、系统数据的导入导出功能。您可以使用此功能将外部数据导入到系统数据库;或者将系统数据导出到Excel文件中,进行数据备份和携带。 11、软件拨号器功能。您可以使用软件进行拨号、挂机操作,方便快捷。 12、权限管理。软件可以对操作人员权限进行精确化控制,最大程度保证软件、数据的安全稳定。   IT0电话录音管理系统 v1.0更新内容: 增加了按阴历日期进行生日提醒的功能  ·         增加了通过记事本查看客户备注信息的功能,点击通讯录编辑界面或者弹屏界面中的记事本图标,将自动打开包含备注信息的记事本文件,方便了备注信息的阅读浏览 网络版增加了业务记录字段查看权限功能,可以设置业务记录的字段信息对那些客户端可见     增加了自定义通讯录列表记录颜色的功能,用户可以根据自己的喜好重新设定列表记录的颜色       网络版服务器端增加了查询即时消息的功能    增加了通话记录的图形统计功能1:统计每条线路“今天,本周,本月”的话务量 增加了通话记录的图形统计功能2:统计每条线路“自定义时间范围内”的话务量 增加了通话记录的图形统计功能3:以月为单位,统计某一条线路在自定义时间范围内的话务量      呼叫中心系统新增功能:去电通话结束后,对分机坐席进行话务考评(非常满意请按2,满意请按1,不满意请按0。。。)。
IVR语音导航系统(以下简称本系统)是一款功能强大、易于使用的电话管理系统软件,主要包括以下几大功能模块。  IVR语音导航/语音流程设置:分时段设置所需的语音导航流程,可设定任意层次,支持“转接人工”、“返回上级菜单”、“留言录音”等功能,设定好流程并导入相应音频文件后即生效。  来电黑名单拒接:可设置黑名单列表,或从通话记录中选取号码通过右键菜单添加入黑名单。当处于黑名单中的号码呼入时,系统自动拒接,并可以选择向对方播放“已停机”或“号码是空号”的提示语音。  来电/去电弹屏:来电或者去电时,电脑自动弹出对方号码所对应的联系人名片以及与该联系人的交往记录,使得您在通话前就全面了解了联系人的信息,使通话交流更加有的放矢、顺畅自如。  通话录音:可以自动对来电和去电的通话进行录音(摘机通话自动开始,挂机自动结束)。可以通过内嵌到IVR语音导航系统中的微软媒体播放器收听录音文件。  挂机/无应答短信:当来电结束、去电结束,以及来电无应答时,系统自动发送预设的短信内容,给予客户提示和说明,增强客户友好体验。  通话录音管理:按照今天、昨天、最近一周、最近一月等时间段选项或者来电、去电、未接等通话类型选项分类显示通话记录和录音记录,每一条通话记录都可以编辑相应的通话摘要,更加方便您对通话记录的管理。  客户通讯录管理:您可以把您经常联系的客户资料添加到IVR语音导航系统中,也可以导入存放在Excel表格中的联系人。存储在IVR语音导航系统中的客户资料,管理起来更加方便,分类浏览更加清晰,快速查找定位快捷方便。  通话录音记录查询:根据通话时间、通话类型、通话号码、联系人姓名等属性进行灵活的通话录音记录查询,查询结果可以导出至Excel文件。  短信收发:网络接口直接接入到网络运营商的平台,需要注册帐号并充值,然后在本系统系统设置界面设置好注册帐号和密码即可,该接口可以发送即时短信和定时短信。短信猫接口需要用户购买短信猫设备,将手机卡(只支持GSM手机卡)插入到短信猫,即可收发短信。可以在联系人的编辑界面,通讯录,通话记录,来电弹屏等界面点击号码发送短信,操作方便快捷。  业务记录字段自定义:为使客户资料和业务记录的字段信息与您的实际业务描述相一致,您可以自定义设置客户资料字段名称和业务记录字段名称。
云来电客户电话管理系统(以下简称本系统)是一款功能强大、易于使用的来电管理系统软件,主要包括以下几大功能模块。  来电/去电弹屏:来电或者去电时,电脑自动弹出对方号码所对应的联系人名片以及与该联系人的交往记录,使得您在通话前就全面了解了联系人的信息,使通话交流更加有的放矢、顺畅自如。  通话录音:可以自动对来电和去电的通话进行录音(摘机通话自动开始,挂机自动结束)。可以通过内嵌到客户电话管理系统中的微软媒体播放器收听录音文件。  挂机/无应答短信:当来电结束、去电结束,以及来电无应答时,系统自动发送预设的短信内容,给予客户提示和说明,增强客户友好体验。  通话录音管理:按照今天、昨天、最近一周、最近一月等时间段选项或者来电、去电、未接等通话类型选项分类显示通话记录和录音记录,每一条通话记录都可以编辑相应的通话摘要,更加方便您对通话记录的管理。  客户通讯录管理:您可以把您经常联系的客户资料添加到客户电话管理系统中,也可以导入存放在Excel表格中的联系人。存储在客户电话管理系统中的客户资料,管理起来更加方便,分类浏览更加清晰,快速查找定位快捷方便。  通话录音记录查询:根据通话时间、通话类型、通话号码、联系人姓名等属性进行灵活的通话录音记录查询,查询结果可以导出至Excel文件。  短信收发:网络接口直接接入到网络运营商的平台,需要注册帐号并充值,然后在本系统系统设置界面设置好注册帐号和密码即可,该接口可以发送即时短信和定时短信。短信猫接口需要用户购买短信猫设备,将手机卡(只支持GSM手机卡)插入到短信猫,即可收发短信。可以在联系人的编辑界面,通讯录,通话记录,来电弹屏等界面点击号码发送短信,操作方便快捷。  业务记录字段自定义:为使客户资料和业务记录的字段信息与您的实际业务描述相一致,您可以自定义设置客户资料字段名称和业务记录字段名称。
功能 1. 查询来电号码并显示悬浮窗,显示位置和其他号码信息。 2. 主界面显示最近来电列表(不会导入已有的系统通讯录)。 3. 在主界面可以查询任意电话号码信息。 4. 自定义设置卡片及悬浮窗的颜色。 5. 自定义悬浮窗, 如文字大小、透明度、位置。可以自定义显示与隐藏,如忽略已存在的联系人、去电时显示、接听后隐藏。 6. 离线查询。优先从本地的离线归属地及历史记录中查询数据并显示,没有查询到标记数据且有网络(有 WIFI 或手机未掉网)时会联网查询。 隐藏功能 (点击七次版本后出现) 1. 自定义数据源。可以自定义百度、聚合数据(360)的 API 密钥,可以自定义 API (用于适配客户信息系统)。可以设置忽略号码段来忽略查询,可以强制使用本地离线数据。 插件功能(安装插件后出现) 1. 自动挂断。可以自动挂断匹配的标记关键字(诈骗、广告等)、归属地、起始号码(400*)。归属地可逆向匹配,如 "!西安 !咸阳" 将挂断所有除 "西安" "咸阳" 的来电。起始号码关键字添加完整号码并以空格分隔可以实现 "黑名单" 的功能。 2. 添加号码信息到系统通话记录。会添加诈骗、骚扰、广告、响一声、自动挂断等信息到系统通话记录。 说明 1. “来电信息” 的不断改进和完善离不开社区的反馈,非常感谢所有在 Play 市场、V站、酷市场留言及发送邮件反馈的朋友。 2. 应用开源免费无广告,请放心使用。APK 文件通过 Travis CI 自动生成并上传,用户可在每个 GitHub 版本发行 中找到编译日志来校验文件 sha1 及 md5。 3. 请避免限制主应用及插件请求的权限。如出现来电时不显示悬浮窗,请先检查权限设置、权限管理类型应用的设置。如果安装了插件,请确保插件和主应用没有进入管理类软件的黑名单或优化项目。 4. 如果对此开源应用有任何不满、问题或建议,请在 GitHub 提交问题单或发送问题到作者邮件。非常欢迎大家反馈,来和作者一起完善这个应用。 5. 如果您觉得这个应用做的不错,欢迎在 GitHub star、在 Play 市场 及 酷市场 五星好评,欢迎您将此应用通过推特、微博、朋友圈等社交网络推广给更多的人。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值