前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >android来电归属地提醒

android来电归属地提醒

作者头像
xiangzhihong
发布于 2018-01-29 06:34:21
发布于 2018-01-29 06:34:21
1.4K0
举报
文章被收录于专栏:向治洪向治洪

现在市面上常用的一些拨号软件的一个功能,来电归属地。拨号的时候,会在拨号界面出现一个号码归属地的小框框。效果如下:而且这个小窗体还可以自定义风格,并且可以自由移动。这里大概讲下实现的过程。

这个小框框其实就是一个自定义的吐司Toast。吐司是一个特殊的窗体,显示在所有窗体的最上方。归属地查询,其实就是自定义一个吐司,然后注册一个服务,后台监听响铃状态,响铃的时候显示吐司,就达到了归属地的效果。我们知道,吐司默认的界面是黑色的小框体,那么怎么样才能做成这种自定义的透明的加图标的吐司呢?

让我们先来查看一下吐司的源代码。

Toast的里面的最重要的一个方法就是MakeText方法。它的源码如下:

代码语言:js
AI代码解释
复制
public static Toast makeText(Context context, CharSequence text, int duration) {  
        Toast result = new Toast(context);  
 
        LayoutInflater inflate = (LayoutInflater)  
                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
        View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);  
        TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);  
        tv.setText(text);  
 
        result.mNextView = v;  
        result.mDuration = duration;  
 
 return result;  
    }  

可以看到吐司的界面view是由布局文件transient_notification inflate来的,也就是说吐司的界面就是在transient_notification中定义的。

下面就去看transient_notification的源码。

代码语言:js
AI代码解释
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" 
    android:background="?android:attr/toastFrameBackground">  
 
    <TextView  
        android:id="@android:id/message" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_weight="1" 
        android:layout_gravity="center_horizontal" 
        android:textAppearance="@style/TextAppearance.Small" 
        android:textColor="@color/bright_foreground_dark" 
        android:shadowColor="#BB000000" 
        android:shadowRadius="2.75" 
        />  
 
</LinearLayout>  

可以看到吐司的一些参数,比如背景图,字体颜色,宽高等。更改这里面的一些参数就可以更改吐司的样式。自定义一些我们比较喜欢的样式。

吐司是怎么显示到屏幕上面的呢?源码里面还有这么一段代码。

代码语言:js
AI代码解释
复制
mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);  
final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());  
                mParams.gravity = gravity;  
 if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {  
                    mParams.horizontalWeight = 1.0f;  
                }  
 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {  
                    mParams.verticalWeight = 1.0f;  
                }  
                mParams.x = mX;  
                mParams.y = mY;  
                mParams.verticalMargin = mVerticalMargin;  
                mParams.horizontalMargin = mHorizontalMargin;  
 
 
mWM.addView(mView, mParams);  
代码语言:js
AI代码解释
复制
<p><span style="font-size: 18px;">这一段代码就是实现将吐司显示在屏幕上面的。其中的mWM就是窗体管理器,两个参数分别是要显示的view对象和view对象显示在窗体上面需要的一些参数。</span></p><p>  
</p><p></p><p></p><p><span style="font-size: 18px;">下面我们就仿照源码来具体实现一下自定义的来电归属地小窗体的功能。</span></p><p><span style="font-size: 18px;">先自定义窗体的布局文件</span></p>  
代码语言:js
AI代码解释
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layout_gravity="center_vertical" 
    android:orientation="horizontal" 
    android:background="@drawable/call_locate_white" 
    >  
 
    <ImageView  
        android:layout_width="wrap_content" 
        android:layout_height="50dip" 
        android:src="@drawable/toast" />  
 
    <TextView  
        android:id="@+id/tv_toast_address" 
        android:layout_width="wrap_content" 
        android:layout_height="50dip" 
        android:text="toast" 
        android:textColor="#ffffff" 
        android:gravity="center_vertical" 
        android:textSize="25sp" />  
 
</LinearLayout>  

然后用布局文件生产view对象

代码语言:js
AI代码解释
复制
view = View.inflate(this, R.layout.activity_toast_address, null);  

定义一个窗体管理器

代码语言:js
AI代码解释
复制
wm = (WindowManager) getSystemService(WINDOW_SERVICE);  

根据上面的吐司源码的介绍要将一个view对象添加到窗体,要使用addView方法

代码语言:js
AI代码解释
复制
TextView tv_toast_address = (TextView) view.findViewById(R.id.tv_toast_address);  
tv_toast_address.setText(text);//Text为传入的归属地地址 
wm.addView(view, params);//将自定义吐司添加到窗体上 

view已经有了,params也可以参考源码里面的params,并且可以自己进行一些修改。

代码语言:js
AI代码解释
复制
params = new WindowManager.LayoutParams();//new一个params对象 
params.gravity = Gravity.LEFT + Gravity.TOP;  
params.height = WindowManager.LayoutParams.WRAP_CONTENT; // 
params.width = WindowManager.LayoutParams.WRAP_CONTENT;  
params.format = PixelFormat.TRANSLUCENT;  
params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;  
params.setTitle("Toast");  
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;  

按照上面的步骤,定义好一个归属地窗体了,但是这个窗体在调用removeView方法前,会一直显示在屏幕上。如何让窗体只在来去电的时候显示呢?

将上面的代码写在服务中,开机启动服务就可以了。但是,这个窗体现在会一直显示在所有界面上面,因为吐司是一个特殊的窗体,会显示在所有窗体的上面。

下面根据来去电两种情况分别进行处理。

来电时:

代码语言:js
AI代码解释
复制
// 监听响铃事件 有响铃就吐司 
tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);  
listener = new MyPhonestateListener();  
// 监听电话呼叫状态变化 
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE)  
private class MyPhonestateListener extends PhoneStateListener {  
 
 @Override 
 public void onCallStateChanged(int state, String incomingNumber) {  
 super.onCallStateChanged(state, incomingNumber);  
 switch (state) {  
 // 挂断手机时 
 case TelephonyManager.CALL_STATE_IDLE:  
 if (view != null) { // 移除添加的小窗体 
                    wm.removeView(view);  
                    view = null;  
                }  
 break;  
 // 手机响铃时 
 case TelephonyManager.CALL_STATE_RINGING:  
                String location = AddressDBDao.getAddress(incomingNumber);  
 // Toast.makeText(PhoneAddressService.this, location, 
 // 1).show(); 
                showMyToast(location);  
 break;  
            }  
 
        }  
    }  

这样就可以在来电响铃的时候显示归属地窗体了。在挂断手机的时候,将归属地窗体移除。

去电,也就是拨号时,系统会发出一个广播,接收这个广播,并在onReceive方法中对归属地小窗体的显示进行控制就可以了

在service服务类中创建一个内部类的广播接收者  当接收到拨号广播时就显示归属地小窗体

代码语言:js
AI代码解释
复制
// 定义一个广播接收者 
 class InnerReceiver extends BroadcastReceiver {  
 @Override 
 public void onReceive(Context context, Intent intent) {  
            String number = getResultData();  
            String location = AddressDBDao.getAddress(number);  
 // Toast.makeText(context, location, 1).show(); 
            showMyToast(location);  
        }  
    }  

然后在onCreate方法中对广播接收者进行注册。

代码语言:js
AI代码解释
复制
// 用代码注册一个广播接收者 
    receiver = new InnerReceiver();  
    IntentFilter filter = new IntentFilter("android.intent.action.NEW_OUTGOING_CALL");  
    registerReceiver(receiver, filter);  

根据上面的步骤,就完成了来去电显示归属地小窗体的功能了。

但是目前,这个小窗体还不能移动,只能在上面params中定义好的位置,要使窗体能够移动,还要对窗体的view进行处理。

窗体移动的原理其实就是手指在屏幕上移动的时候分别记录手指在x轴,y轴移动的距离,同时将归属地窗体也移动相应的距离,然后更新窗体的实时位置,并初始化手机的位置。最后还要对窗体离边框的距离进行处理。否则,归属地窗体会移出x轴,不符合实际情况。对窗体的坐标进行一些逻辑判断,最后代码如下:

代码语言:js
AI代码解释
复制
// 为自定义窗体设置一个触摸监听器 
        view.setOnTouchListener(new OnTouchListener() {  
 
 private int startX = 0;  
 private int startY = 0;  
 
 @Override 
 public boolean onTouch(View v, MotionEvent event) {  
 
 switch (event.getAction()) {  
 case MotionEvent.ACTION_DOWN:// 手指触摸到屏幕时执行的方法 
                    startX = (int) event.getRawX();  
                    startY = (int) event.getRawY();  
 break;  
 case MotionEvent.ACTION_MOVE:// 手指在屏幕上移动时执行的方法 
 // 计算手指在屏幕上移动的位移 
 int newX = (int) event.getRawX();  
 int newY = (int) event.getRawY();  
 int dx = newX - startX;  
 int dy = newY - startY;  
 // 将框体也移动相应的位置即可 
 if(params.x<0){  
                        params.x = 0;  
                    }  
 if(params.y<0){  
                        params.y = 0;  
                    }  
 if(params.x > (wm.getDefaultDisplay().getWidth()-params.width)){  
                        params.x = wm.getDefaultDisplay().getWidth()-params.width;  
                    }  
 if(params.y >(wm.getDefaultDisplay().getWidth()-params.width)){  
                        params.y = wm.getDefaultDisplay().getWidth()-params.width;  
                    }  
                    params.x += dx;  
                    params.y += dy;  
                    wm.updateViewLayout(view, params);//更新窗体位置 
 // 初始化手指的位置 
                    startX = (int) event.getRawX();  
                    startY = (int) event.getRawY();  
 break;  
 case MotionEvent.ACTION_UP:// 手指离开屏幕时执行的方法 
 break;  
 default:  
 break;  
                }  
 
 return false;  
            }  
        });  

当然还可以设置一个变量值,根据不同的值为窗体设置不同的背景,这就是换肤功能。这里就不具体说明了。

最后,服务结束的时候,还要取消注册监听器和广播接收者。

代码语言:js
AI代码解释
复制
public void onDestroy() {  
 super.onDestroy();  
        tm.listen(listener, PhoneStateListener.LISTEN_NONE);  
        listener = null;  
        unregisterReceiver(receiver);  
        receiver = null;  
    }  

到这里,一个可移动的来去电归属地小窗体的功能就实现了。

效果图:

代码语言:js
AI代码解释
复制
<pre code_snippet_id="147480" snippet_file_name="blog_20140108_4_4003010"></pre>  
<pre></pre>   
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2014-04-03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
MySQL之——源码编译MySQL8.x+升级gcc+升级cmake(亲测完整版)
最近,在CentOS 6.8服务器上编译安装MySQL 8.0.18的源码,百度了许久,发现网上的安装方式没一个可用的。基本都是基于CentOS 7.x来安装MySQL8.0,并且安装过程中会出现各种问题,按照他们的文章进行安装根本解决不了问题。更重要的一点就是,很多文章的内容一模一样!!我就纳闷了,那些发表文章的人,自己真的安装并且验证过吗?还是只是一味的抄袭呢?!
冰河
2020/10/29
2.3K0
MySQL之——源码编译MySQL8.x+升级gcc+升级cmake(亲测完整版)
CentOS 7.2编译安装MariaDB-10.0.xx
------------------------------------------分割线------------------------------------------
星哥玩云
2022/08/13
5080
[MySQL] MySQL的自己主动化安装部署
有过MySQL运维的人应该都清楚,线上的MySQL一般都採用源代码编译,由于这样才干够依据企业的各自须要选择要编译的功能,尽管MySQL的源代码编译挺简单的,可是试想一下,假设你有几百台server同一时候要安装MySQL,难道你还一台台去手动编译、编写配置文件吗?这显然太低效了,本文讨论MySQL的自己主动化安装部署。
全栈程序员站长
2022/07/12
5190
MySQL入门01-MySQL源码安装
也可以官网 https://cmake.org/ 下载源码编译。 我这里选择了官网下载最新版本cmake-3.5.2.tar.gz。
Alfred Zhao
2022/05/06
7260
mysql 8本地源码安装注意事项
yum -y install wget cmake gcc gcc-c++ ncurses ncurses-devel libaio-devel openssl openssl-devel
算法之名
2019/08/20
7160
CentOS 7.6 下MySQL 8.0.16编译安装
yum -y install ntpdate gcc gcc-c++ ncurses ncurses-devel cmake readline-devel zlib.x86_64 zlib-devel.x86_64 bison libcurl-* net-tool* tree nmap sysstat lrzsz dos2unix telnet.x86_64 nethogs iftop iotop unzip ftp.x86_
星哥玩云
2022/08/18
8430
基于Centos6.5源码编译安装mysql-5.7.17
基于Centos6.5源码编译安装mysql-5.7.17过程详解 由于工作需要,需要在centos6.5服务器上安装mysql5.7,如下是详细安装过程。
冬天里的懒猫
2020/08/04
8620
CentOS 7上编译安装MySQL 5.5
MySQL服务是一个真正的多线程、多用户的SQL数据库服务,凭借其高性能、高可靠和易于使用的特性,成为服务器领域中最受欢迎的开源数据库系统。为了确保MySQL数据库功能的完整性。可定制性,将采用源代码编译的方式安装MySQL数据库系统。
星哥玩云
2022/08/17
7660
在Linux下源码编译安装GreatSQL/MySQL
本次介绍如何利用Docker来将GreatSQL源码编译成二进制文件,以及制作二进制包、RPM包等。
老叶茶馆
2021/08/26
2.5K0
CentOS系统编译安装MariaDB数据库实现多实例
上一篇实现了yum安装多实例 现在开始用编译安装实现多实例 编译安装多实例 第一步:创建账户 [root@centos7 ~]#useradd -r -s /sbin/nologin mysql [root@centos7 ~]#id mysql uid=988(mysql) gid=983(mysql) groups=983(mysql) [root@centos7 ~]#getent passwd mysql mysql:x:988:983::/home/my
咻一咻
2020/05/29
6040
MYSQL5.6&5.7编译安装
此文只是帮助刚开始接触MYSQL的同学安装。可能会因为操作系统环境不一样,缺一些包,根据报错修复即可。装好后可以打包成RPM包,方便后续安装。 CMake编译工具 下载地址:https://cmake.org/download/ [root@shell ~]# wget -c https://cmake.org/files/v3.9/cmake-3.9.1.tar.gz [root@shell ~]# tar -zxf cmake-3.2.1.tar.gz && cd cmake-3.9.1 [root@s
MySQL轻松学
2018/03/09
1.1K0
CentOS Linux 7.5 编译安装 MySQL 8.0.12 及修改密码问题
#cat /etc/RedHat-release CentOS Linux release 7.5.1804 (Core)
星哥玩云
2022/08/17
5790
【MySQL数据库疑难杂症】常用的两种升级方法
动态修改innodb_fast_shutdown=0,以执行full purge(当innodb_fast_shutdown=0时,MySQL在执行关闭mysqld进程时,会对不再需要的undo log page进行清理,该清理动作非人为触发)和插入缓冲合并等操作,以干净的方式关闭MySQL。
samRsa
2025/02/11
2000
【MySQL数据库疑难杂症】常用的两种升级方法
linux环境编译安装Mysql8.0
本文以BClinux for euler 21.10(redhat/centos可以参考)为例。在本地内网(Linux主机无法连接互联网,能连接公网最好,不能也没关系)编译安装。
炒香菇的书呆子
2024/07/23
8190
MYSQL8+CENTOS7.6 主从+keepalived搭建总结
yum -y install ncurses-devel openssl openssl-devel bison
PHP开发工程师
2021/05/24
8020
编译安装mysql 5.6.40
环境说明 系统版本 CentOS 7.2 x86_64 软件版本 mysql-5.6.40 编译步骤如下: [root@db01 ~]# mkdir -p /service/tools [root@db01 ~]# mkdir /application [root@db01 ~]# yum install ncurses-devel libaio-devel cmake gcc gcc-c++ glibc openssl-devel bison-devel -y [root@db01 ~]# us
仙人技术
2020/04/29
1.1K0
部署MySQL 5.7
注:在安装MySQL前需要卸载掉当前已有的mariadb,然后需要安装gcc环境 1、安装cmake
小手冰凉
2020/04/12
8220
Linux 中 Discuz 部署
冷影玺
2023/10/11
5260
Linux 中 Discuz 部署
CentOS下源码编译安装LNMP(附源码包)
LNMP指的是一个基于CentOS/Debian编写的Nginx、PHP、MySQL、phpMyAdmin、eAccelerator一键安装包。可以在VPS、独立主机上轻松的安装LNMP生产环境。LNMP代表的就是:Linux系统下Nginx+MySQL+PHP这种网站服务器架构。Linux是一类Unix计算机操作系统的统称,是目前最流行的免费操作系统。代表版本有:debian、centos、Ubuntu、Fedora、gentoo等;Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器;Mysql是一个小型关系型数据库管理系统;PHP是一种在服务器端执行的嵌入HTML文档的脚本语言。这四种软件均为免费开源软件,组合到一起,成为一个免费、高效、扩展性强的网站服务系统。
星哥玩云
2022/07/14
1.7K0
CentOS下源码编译安装LNMP(附源码包)
Centos 7安装mysql-5.7.22
wget https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
py3study
2018/08/03
1K0
相关推荐
MySQL之——源码编译MySQL8.x+升级gcc+升级cmake(亲测完整版)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档