android来电归属地提醒

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

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

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

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

[java] view plaincopyprint?

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

可以看到吐司的界面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.   
  7.     <TextView  
  8.         android:id="@android:id/message"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content"  
  11.         android:layout_weight="1"  
  12.         android:layout_gravity="center_horizontal"  
  13.         android:textAppearance="@style/TextAppearance.Small"  
  14.         android:textColor="@color/bright_foreground_dark"  
  15.         android:shadowColor="#BB000000"  
  16.         android:shadowRadius="2.75"  
  17.         />  
  18.   
  19. </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.   
  15.   
  16. 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.   
  9.     <ImageView  
  10.         android:layout_width="wrap_content"  
  11.         android:layout_height="50dip"  
  12.         android:src="@drawable/toast" />  
  13.   
  14.     <TextView  
  15.         android:id="@+id/tv_toast_address"  
  16.         android:layout_width="wrap_content"  
  17.         android:layout_height="50dip"  
  18.         android:text="toast"  
  19.         android:textColor="#ffffff"  
  20.         android:gravity="center_vertical"  
  21.         android:textSize="25sp" />  
  22.   
  23. </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.   
  8.         @Override  
  9.         public void onCallStateChanged(int state, String incomingNumber) {  
  10.             super.onCallStateChanged(state, incomingNumber);  
  11.             switch (state) {  
  12.             // 挂断手机时  
  13.             case TelephonyManager.CALL_STATE_IDLE:  
  14.                 if (view != null) { // 移除添加的小窗体  
  15.                     wm.removeView(view);  
  16.                     view = null;  
  17.                 }  
  18.                 break;  
  19.             // 手机响铃时  
  20.             case TelephonyManager.CALL_STATE_RINGING:  
  21.                 String location = AddressDBDao.getAddress(incomingNumber);  
  22.                 // Toast.makeText(PhoneAddressService.this, location,  
  23.                 // 1).show();  
  24.                 showMyToast(location);  
  25.                 break;  
  26.             }  
  27.   
  28.         }  
  29.     }  

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

去电,也就是拨号时,系统会发出一个广播,接收这个广播,并在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.   
  4.             private int startX = 0;  
  5.             private int startY = 0;  
  6.   
  7.             @Override  
  8.             public boolean onTouch(View v, MotionEvent event) {  
  9.   
  10.                 switch (event.getAction()) {  
  11.                 case MotionEvent.ACTION_DOWN:// 手指触摸到屏幕时执行的方法  
  12.                     startX = (int) event.getRawX();  
  13.                     startY = (int) event.getRawY();  
  14.                     break;  
  15.                 case MotionEvent.ACTION_MOVE:// 手指在屏幕上移动时执行的方法  
  16.                     // 计算手指在屏幕上移动的位移  
  17.                     int newX = (int) event.getRawX();  
  18.                     int newY = (int) event.getRawY();  
  19.                     int dx = newX - startX;  
  20.                     int dy = newY - startY;  
  21.                     // 将框体也移动相应的位置即可  
  22.                     if(params.x<0){  
  23.                         params.x = 0;  
  24.                     }  
  25.                     if(params.y<0){  
  26.                         params.y = 0;  
  27.                     }  
  28.                     if(params.x > (wm.getDefaultDisplay().getWidth()-params.width)){  
  29.                         params.x = wm.getDefaultDisplay().getWidth()-params.width;  
  30.                     }  
  31.                     if(params.y >(wm.getDefaultDisplay().getWidth()-params.width)){  
  32.                         params.y = wm.getDefaultDisplay().getWidth()-params.width;  
  33.                     }  
  34.                     params.x += dx;  
  35.                     params.y += dy;  
  36.                     wm.updateViewLayout(view, params);//更新窗体位置  
  37.                     // 初始化手指的位置  
  38.                     startX = (int) event.getRawX();  
  39.                     startY = (int) event.getRawY();  
  40.                     break;  
  41.                 case MotionEvent.ACTION_UP:// 手指离开屏幕时执行的方法  
  42.                     break;  
  43.                 default:  
  44.                     break;  
  45.                 }  
  46.   
  47.                 return false;  
  48.             }  
  49.         });  

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

[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> 
时间: 2024-09-12 19:53:26

android来电归属地提醒的相关文章

android 手机号码归属地问题

问题描述 android 手机号码归属地问题 想一次性查询通讯录中的号码归属地,一种方法是使用webservice,但是使用webservice免费用户每天只能使用一百次,可是一般通讯录中的号码何止一百.另一种方法是将所有的号码段信息存储在数据库中,然后通过查询匹配,这样做又太麻烦.请问有没有其他更好的方法. 解决方案 你可以看看这个http://download.csdn.net/download/sunboy_2050/4179519 他的实现方法应该是用数据库的,但是源码和数据库都提供了.

android 广播-Android来电来信以及挂断接通的广播事件

问题描述 Android来电来信以及挂断接通的广播事件 鄙人想开发一个来电来信闪光的软件.网上这两个广播事件讲的不清不楚的.请大神告诉我,还有相应的权限 解决方案 Android中电话通信的简单流程 使用代码拨打电话 1>创建隐式意图 Intent intent=new Intent(); intent.setAction(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:13555555555")); 2>启动Activ

求android中一个定时提醒功能的实现思路!

问题描述 求android中一个定时提醒功能的实现思路! 比如在一个记事本中,我写了一项任务,想加一个定时提醒功能,类似闹钟一样,但又和闹钟不一样,闹钟只能定今天的时间,我想定任意一天的任意时刻的一个提醒功能,跪求实现思路!!! 解决方案 http://blog.csdn.net/wanglang3081/article/details/7456684 解决方案二: 这一个service在后台运行,实时检查时间 解决方案三: Timer定时机制. 解决方案四: 如果要实现任意天任意时刻,那就必须

android 来电系统广播

问题描述 android 来电系统广播 android来电的系统广播是什么,还是说只有电话状态改变的广播 解决方案 http://blog.csdn.net/zhuifeng11/article/details/7579346 这篇博客文章里有你要的答案,你可以点击上面的链接进去看看: 如果回答对您有帮助,请采纳 解决方案二: 就相当于你收到短音时,有的软件,像360助手可以提前得到短音一样,都是通过广播发送给你的 解决方案三: Android的广播机制http://blog.csdn.net/

android 本地定时提醒-android 本地定时通知提醒

问题描述 android 本地定时通知提醒 如果做到像ios那种定时通知提醒.因为服务器只给两个时间,所以不需要推送什么的进行提醒.本来使用android里面的闹钟进行定时提醒的,但是手机关机重启之后闹钟就会失效.在android里面有没有什么方法能够实现本地定时提醒的功能啊,求大神告知,谢谢了~~ 解决方案 android 在后台定时提醒---------------------- 解决方案二: 如果只是关机重启之后会失效 你可以考虑做一个开机自启的功能.

三星E7如何设置来电归属地?E7000来电归属地开启方法

1.这个功能在手机中的[电话]中了,我们点击桌面上的电话图标打开进入了.   2.进入之后我们再点击右上角的三点...[菜单]之后然后找到[设定]进入.   3.在打开设定功能中我们再点击[通话]打开进入,细节如下所示.   4.进入设定成功之后我们再找到[来电归属地]. 5.将[启动号码定位器]打钩即可.     以上操作完成后,当有来电时,就会显示此来电的归属地了.     好了到这里这个手机就有来电归属地功能了,大家去接听电话试一下吧.

三星Galaxy S5如何设置来电归属地?S5来电归属地设置方法

1.亲手截图看看下在风们点击[应用程序].        2.然后我们在下图找到一个电放标识的图标,也就是下面有文字的[手机]点击进入.        3.然后我们在手机最下方按下[菜单]硬键,然后在弹出层中点击[通话设定].         4.现在我们进入到通话设定之后会看到如下图所示的[来电归属地]选项,我们点击它进入.        5.现在在来电归属地中我们会看到有一个[启动号码定位器]默认状态是未启动的,现在我们把它选中.        好了按上面方法设置之后你再的一个电话试一下是不

三星GALAXY S5 4G手机没有来电归属地功能怎么设置

没有来电归属地这样来电我们不知道是哪里打过来了,这个功能其实也没关系但有强迫症的朋友可能就会觉得要显示了,那么要如何开启来电归属地功能呢,具体的我们一起来看看吧. 1.在待机页面下,点击[应用程序].      2.点击[设定].     3.向上滑动屏幕,点击[通话].     4.点击[来电归属地].     5.将[启动号码定位器]选中了,这样的话就可以了,其实是非常的简单的呀,各位看看吧.      完成以上操作后,再来电就会显示来电的归属地了.     好了这里有一个细节不知道各位注意

详解Android中Notification通知提醒_Android

在消息通知时,我们经常用到两个组件Toast和Notification.特别是重要的和需要长时间显示的信息,用Notification就最 合适不过了.当有消息通知时,状态栏会显示通知的图标和文字,通过下拉状态栏,就可以看到通知信息了,Android这一创新性的UI组件赢得了用户的一 致好评,就连苹果也开始模仿了.今天我们就结合实例,探讨一下Notification具体的使用方法.  首先说明一下我们需要实现的功能是:在程序启动时,发出一个通知,这个通知在软件运行过程中一直存在,相当于qq的托盘