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

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

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

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

[java] view plaincopyprint?
  1. public static Toast makeText(Context context, CharSequence text, int duration) {
  2. Toast result = new Toast(context);
  3. LayoutInflater inflate = (LayoutInflater)
  4. context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  5. View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
  6. TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
  7. tv.setText(text);
  8. result.mNextView = v;
  9. result.mDuration = duration;
  10. return result;
  11. }

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

下面就去看transient_notification的源码。

[java] view plaincopyprint?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="match_parent"
  4. android:orientation="vertical"
  5. android:background="?android:attr/toastFrameBackground">
  6. <TextView
  7. android:id="@android:id/message"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_weight="1"
  11. android:layout_gravity="center_horizontal"
  12. android:textAppearance="@style/TextAppearance.Small"
  13. android:textColor="@color/bright_foreground_dark"
  14. android:shadowColor="#BB000000"
  15. android:shadowRadius="2.75"
  16. />
  17. </LinearLayout>

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

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

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

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

[java] view plaincopyprint?
  1. view = View.inflate(this, R.layout.activity_toast_address, null);

定义一个窗体管理器

[java] view plaincopyprint?
  1. wm = (WindowManager) getSystemService(WINDOW_SERVICE);

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

[java] view plaincopyprint?
  1. TextView tv_toast_address = (TextView) view.findViewById(R.id.tv_toast_address);
  2. tv_toast_address.setText(text);//Text为传入的归属地地址
  3. wm.addView(view, params);//将自定义吐司添加到窗体上

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

[java] view plaincopyprint?
  1. params = new WindowManager.LayoutParams();//new一个params对象
  2. params.gravity = Gravity.LEFT + Gravity.TOP;
  3. params.height = WindowManager.LayoutParams.WRAP_CONTENT; //
  4. params.width = WindowManager.LayoutParams.WRAP_CONTENT;
  5. params.format = PixelFormat.TRANSLUCENT;
  6. params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
  7. params.setTitle("Toast");
  8. params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

按照上面的步骤,定义好一个归属地窗体了,但是这个窗体在调用removeView方法前,会一直显示在屏幕上。如何让窗体只在来去电的时候显示呢?
将上面的代码写在服务中,开机启动服务就可以了。但是,这个窗体现在会一直显示在所有界面上面,因为吐司是一个特殊的窗体,会显示在所有窗体的上面。
下面根据来去电两种情况分别进行处理。

来电时:

[java] view plaincopyprint?
  1. // 监听响铃事件 有响铃就吐司
  2. tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
  3. listener = new MyPhonestateListener();
  4. // 监听电话呼叫状态变化
  5. tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE)
  6. private class MyPhonestateListener extends PhoneStateListener {
  7. @Override
  8. public void onCallStateChanged(int state, String incomingNumber) {
  9. super.onCallStateChanged(state, incomingNumber);
  10. switch (state) {
  11. // 挂断手机时
  12. case TelephonyManager.CALL_STATE_IDLE:
  13. if (view != null) { // 移除添加的小窗体
  14. wm.removeView(view);
  15. view = null;
  16. }
  17. break;
  18. // 手机响铃时
  19. case TelephonyManager.CALL_STATE_RINGING:
  20. String location = AddressDBDao.getAddress(incomingNumber);
  21. // Toast.makeText(PhoneAddressService.this, location,
  22. // 1).show();
  23. showMyToast(location);
  24. break;
  25. }
  26. }
  27. }

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

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

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

[java] view plaincopyprint?
  1. // 定义一个广播接收者
  2. class InnerReceiver extends BroadcastReceiver {
  3. @Override
  4. public void onReceive(Context context, Intent intent) {
  5. String number = getResultData();
  6. String location = AddressDBDao.getAddress(number);
  7. // Toast.makeText(context, location, 1).show();
  8. showMyToast(location);
  9. }
  10. }

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

[java] view plaincopyprint?
  1. // 用代码注册一个广播接收者
  2. receiver = new InnerReceiver();
  3. IntentFilter filter = new IntentFilter("android.intent.action.NEW_OUTGOING_CALL");
  4. registerReceiver(receiver, filter);

根据上面的步骤,就完成了来去电显示归属地小窗体的功能了。
但是目前,这个小窗体还不能移动,只能在上面params中定义好的位置,要使窗体能够移动,还要对窗体的view进行处理。
窗体移动的原理其实就是手指在屏幕上移动的时候分别记录手指在x轴,y轴移动的距离,同时将归属地窗体也移动相应的距离,然后更新窗体的实时位置,并初始化手机的位置。最后还要对窗体离边框的距离进行处理。否则,归属地窗体会移出x轴,不符合实际情况。对窗体的坐标进行一些逻辑判断,最后代码如下:

[java] view plaincopyprint?
  1. // 为自定义窗体设置一个触摸监听器
  2. view.setOnTouchListener(new OnTouchListener() {
  3. private int startX = 0;
  4. private int startY = 0;
  5. @Override
  6. public boolean onTouch(View v, MotionEvent event) {
  7. switch (event.getAction()) {
  8. case MotionEvent.ACTION_DOWN:// 手指触摸到屏幕时执行的方法
  9. startX = (int) event.getRawX();
  10. startY = (int) event.getRawY();
  11. break;
  12. case MotionEvent.ACTION_MOVE:// 手指在屏幕上移动时执行的方法
  13. // 计算手指在屏幕上移动的位移
  14. int newX = (int) event.getRawX();
  15. int newY = (int) event.getRawY();
  16. int dx = newX - startX;
  17. int dy = newY - startY;
  18. // 将框体也移动相应的位置即可
  19. if(params.x<0){
  20. params.x = 0;
  21. }
  22. if(params.y<0){
  23. params.y = 0;
  24. }
  25. if(params.x > (wm.getDefaultDisplay().getWidth()-params.width)){
  26. params.x = wm.getDefaultDisplay().getWidth()-params.width;
  27. }
  28. if(params.y >(wm.getDefaultDisplay().getWidth()-params.width)){
  29. params.y = wm.getDefaultDisplay().getWidth()-params.width;
  30. }
  31. params.x += dx;
  32. params.y += dy;
  33. wm.updateViewLayout(view, params);//更新窗体位置
  34. // 初始化手指的位置
  35. startX = (int) event.getRawX();
  36. startY = (int) event.getRawY();
  37. break;
  38. case MotionEvent.ACTION_UP:// 手指离开屏幕时执行的方法
  39. break;
  40. default:
  41. break;
  42. }
  43. return false;
  44. }
  45. });

当然还可以设置一个变量值,根据不同的值为窗体设置不同的背景,这就是换肤功能。这里就不具体说明了。
最后,服务结束的时候,还要取消注册监听器和广播接收者。

[java] view plaincopyprint?
  1. public void onDestroy() {
  2. super.onDestroy();
  3. tm.listen(listener, PhoneStateListener.LISTEN_NONE);
  4. listener = null;
  5. unregisterReceiver(receiver);
  6. receiver = null;
  7. }

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

效果图:

                   

[java] view plaincopyprint?
  1. <pre code_snippet_id="147480" snippet_file_name="blog_20140108_4_4003010"></pre>
  2. <pre></pre>

android来电归属地提醒相关推荐

  1. Android 来电归属地显示功能demo

    2019独角兽企业重金招聘Python工程师标准>>> 需求:打进电话,用Toast显示来电归属地(注:说明系统的拨号不能改) 第一步:创建后台监听来电服务AddressServic ...

  2. android 来电号码归属地,[Android] 来电归属地查询的实现思路

    想要监听来电首先需要要manifest中申明"android.permission.READ_PHONE_STATE"权限 Xml代码  还需要注册来电监听,目前我的处理方式是接收 ...

  3. sony lt26i android 5.1rom,索尼 LT26 Xperia L 5.1.1 ROM刷机包 扁平化 来电归属 农历 新相机 稳定流畅...

    ROM 介绍 ROM信息 ROM名称:Xperia L ROM版本:5.1.1 机型:lt26i(xperia s),ii不知道行不行没条件测试 注意事项 1.请更新最新版的recovery刷机以免卡 ...

  4. iOS 8 Beta 2加入来电归属地功能

    [IT168 资讯]距离推出iOS 8开发者版仅两周,苹果公司现在正式向广大开发者发布了iOS 8系统的第二个测试版beta 2,编译版本号为12A4297e.除了修复了beta版本此前出现的一些BU ...

  5. 21、高级工具--来电归属地提示框的位置设置

    创建设置提示框位置的activity:DragViewActivity以及布局文件. 代码: package com.example.mobilesafe;import android.app.Act ...

  6. Android来电铃声默认设置的实现方法与如何设置语音来电的默认铃声

    Android来电铃声默认设置的实现方法与如何设置语音来电的默认铃声 一.Android来电铃声默认设置的实现方法 Andoird默认来电铃声的设置方法为修改build/target/product/ ...

  7. android来电电话获取,Android获取来电号码代码

    对于Android平台的整个来电软件制作十分简单,Android平台在各方面都比较智能,加上一个BOOT_COMPLETED获取,保证开机自动运行,一个来电通就很容易的制作完成了. Android来电 ...

  8. 来电归属地java_来电归属地数据查询Java实现

    项目需要实现来电归属地查询,所以就找到了下面这个文章 原理主要在(一)和(二)中,作者的数据压缩思路很给力,将6M的原始文本数据压缩到400kb左右,原作者已经将分析讲的很清楚了,这里提炼一下要点,并 ...

  9. android 自动挂断,android 来电自动接听和自动挂断(2.3以上)

    转自http://stephen830.iteye.com/blog/1181786java android 来电自动接听和自动挂断android 注意:android2.3版本不支持下面的自动接听方 ...

最新文章

  1. 日事清【员工绩效】功能活动上线!
  2. 在两个页面间翻转设置Animation动作的一些总结
  3. 从程序员到项目经理,没有捷径可走
  4. 217.存在重复元素
  5. 【拓扑排序】排队-C++
  6. LiteIDE调试工具delve
  7. Python封装的获取文件目录的函数
  8. 拉格朗日插值的优缺点_对拉格朗日插值法与牛顿插值法的学习和比较
  9. 什么是连接池?为什么需要连接池呢?连接池的组成原理又是什么呢?
  10. 吉林大学前卫南区计算机宿舍,睡过双一流学生宿舍后,把宿舍照片分享给你们,看看你们想去的学校宿舍长啥样!...
  11. 计算机应用基础——计算机硬件(三)
  12. 磁盘占用率100%——哪些程序可以禁用(详细版)【还讲到独立显卡、集成显卡、双显卡、固态硬盘卡机卡死卡顿解决】
  13. g mysql windows_Windows平台配置5.7版本+MySQL数据库服务
  14. 科学计算机怎么解一元一次方程,解一元一次方程“八不要”
  15. 学什么副业前景好?学一个什么副业比较好?自学副业有哪些?
  16. GoogleHacking
  17. 勘误发布:《数字滤波器的MATLAB与FPGA实现——Xilinx/VHDL版》P320
  18. 2021年三季度中国食品加工行业A股上市企业营收排行榜:双汇发展再度蝉联榜单TOP1,4家企业新上榜(附热榜TOP19详单)
  19. CVPR2021:百篇AR/VR关联性研究成果汇总
  20. 51单片机 LED点亮、闪烁以及流水灯实现

热门文章

  1. 新版二级域名分发平台源码+带教程/界面很可爱
  2. 某畅销理财书读书笔记
  3. CentOS6.8搭建Sentry环境
  4. 植物大战僵尸游戏内存地址
  5. Vue3 +ts 打包后访问是空白页面
  6. 万能实体类(pageDate)
  7. 服务器系统部署方案,服务器 部署方案
  8. 如何用AE导出程序员可以复用的Json代码
  9. 计算机组成原理第一章知识点总结
  10. Vue简明实用教程(13)——Vue的生命周期