首页 > 代码库 > 仿手机卫士打电话弹出归属地
仿手机卫士打电话弹出归属地
所要实现的功能如下图
no tu no bb
实现此功能需要解决一下问题
1,来电号码所在地址怎么解决?
答:从数据库里面获取,数据库从哪来?从百度,google。soga!
2,怎么知道什么时候来电or去电?
答:监听系统广播
3,怎么知道来电or去电人的姓名和号码归属地
答:通过内容提供者来获取!
4,弹出的窗口怎么来做?
答:用popupwindow ? 否 我们经常在service 或者 BroadcastReceiver里面弹出Toast,
我们这里就用Toast做,通过WindowManager来实现
我们先来实现第1个问题加载数据库
先从网上下个数据库contactAddress.db,把此文件放在assets文件夹中,我们要想使用该数据库就要把contactAddress.db放在files文件中
下面是实现代码
1 /** 2 * 加载数据库 3 */ 4 private void loadDb() { 5 try { 6 File file = new File(getFilesDir(), "contactAddress.db"); 7 // 判断contactAddress.db是否存在,不存在复制数据库到app 8 if (file.exists() && file.length() > 0) { 9 return;10 } else {11 // 找到assets,打开contactAddress.db,得到输入流12 InputStream is = getAssets().open("contactAddress.db");13 FileOutputStream fos = new FileOutputStream(file);14 byte []buffer = new byte[1024];15 int length = 0;16 while((length = is.read(buffer)) != -1){17 fos.write(buffer, 0, length);18 }19 fos.flush();20 is.close();21 fos.close();22 }23 } catch (IOException e) {24 e.printStackTrace();25 }26 }
第1个问题以解决,下面我们来实现第2个问题:怎么知道什么时候来电or去电?
这个问题我们换个方法来实现我们用service来实现,通常情况下都是用BroadcastReceiver来实现,这个地方有个问题BroadcastReceiver生命周期限制,有可能会因为通话时间过长
导致BroadcastReceiver生命周期结束,这样弹出的窗口就不显示了。
我们想要开启service时,我们要考虑一个问题,如果这个service已开启,我们就不用再次开启,那么,问题来了怎么检测服务是否开启!
直接上代码:
1 /** 2 * service 工具类 3 * @author Administrator 4 * 5 */ 6 public class ServiceUtil { 7 8 /** 9 * 根据service名称查看是否死掉10 * service名称 = 需要加上包名+service类名称11 * @param context12 * @param serviceName13 * @return14 */15 public static boolean isRun(Context context,String serviceName){16 ActivityManager activityManager = (ActivityManager) context.getSystemService(Activity.ACTIVITY_SERVICE);17 List<RunningServiceInfo> list = activityManager.getRunningServices(200);18 for(RunningServiceInfo info : list){19 if(info.service.getClassName().equals(serviceName)){20 return true;21 }22 }23 return false; 24 }25 26 }
下面我们来看看这个service怎么来写
新建一个PhoneService,在onCreate()方法里面先实现来电监听
1 mTeleManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); 2 myListener = new MyPhoneStateListener(); 3 mTeleManager.listen(myListener, PhoneStateListener.LISTEN_CALL_STATE); 4 5 /** 6 * 电话进来,监听 7 * @author Administrator 8 * 9 */10 class MyPhoneStateListener extends PhoneStateListener{11 12 @Override13 public void onCallStateChanged(int state, String incomingNumber) {14 super.onCallStateChanged(state, incomingNumber);15 switch (state) {16 case TelephonyManager.CALL_STATE_RINGING://电话铃声响起17 //to do21 break;22 23 case TelephonyManager.CALL_STATE_IDLE: //电话空闲了24 //to do27 break;28 }29 }30 31 }
这样来电监听就可以实现了,下面实现去电监听
1 /** 2 * 打电话广播接收者 3 */ 4 class OutCallReceiver extends BroadcastReceiver{ 5 6 @Override 7 public void onReceive(Context context, Intent intent) { 8 //获取拨打出去的电话 9 String phone = getResultData();
//to do
14 }
15 16 }
我们需要在PhoneService 的onCreate动态注册一下
1 //注册广播2 receiver = new OutCallReceiver();3 IntentFilter filter = new IntentFilter();4 filter.addAction("android.intent.action.NEW_OUTGOING_CALL");5 registerReceiver(receiver, filter );
ok 电话去电和来电的监听已解决.
下面来看第3个问题: 怎么知道来电or去电人的姓名和号码归属地
通过问题2可以获取到来电or去电的电话号码 解决姓名和归属地也就是分分钟钟的事了
我们先看如何获取姓名,这里我写了一个工具类方法:
1 public static String getContactName(Context context,String phone) { 2 String name = "陌生人"; 3 // 内容解析器 4 ContentResolver resolver = context.getContentResolver(); 5 // 获取手机联系人 6 String[] PHONES_PROJECTION = new String[] { Phone.DISPLAY_NAME,Phone.NUMBER}; 7 Cursor phoneCursor = resolver.query(Phone.CONTENT_URI, 8 PHONES_PROJECTION, Phone.NUMBER+" =? ", new String[]{phone}, null); 9 if (phoneCursor != null && phoneCursor.getCount() > 0) {10 while (phoneCursor.moveToNext()) {11 name = phoneCursor.getString(0); 12 }13 }14 phoneCursor.close();15 return name;16 }
搜噶!调用这个方法就可以获取到姓名了!
来看一下获取归属地我们的数据库要登场了,封装一下吧!
1 public static String getAddress(String phone) { 2 String dbAddress = "data/data/com.example.demo/files/contactAddress.db"; 3 String address = phone; 4 SQLiteDatabase database = SQLiteDatabase.openDatabase(dbAddress, null, 5 SQLiteDatabase.OPEN_READONLY); 6 // 判断是否为手机号 7 if (phone.matches("^1[34568]\\d{9}$")) { 8 String sql = "select d2.location from data1 as d1 left join data2 as d2 on d1.outkey = d2.id where d1.id = ?"; 9 Cursor cursor = database.rawQuery(sql,10 new String[] { (String) phone.subSequence(0, 7) });11 if (cursor != null && cursor.getCount() > 0) {12 while (cursor.moveToNext()) {13 address = cursor.getString(0);14 }15 }16 } else {17 switch (phone.length()) {18 case 3:19 address = "求救电话";20 break;21 default:22 // 固话23 if (phone.length() > 0 && phone.startsWith("0")) {24 String sql = "select location from data2 where area = ? or area = ?";25 Cursor cursor = database.rawQuery(sql,26 new String[] { (String) phone.subSequence(1, 3),27 (String) phone.subSequence(1, 4) });28 if (cursor != null && cursor.getCount() > 0) {29 while (cursor.moveToNext()) {30 address = cursor.getString(0);31 address = address32 .substring(0, address.length() - 2);33 }34 }35 }36 break;37 }38 }39 return address;40 41 }
这样我们就可以获取到归属地和姓名了
我们监听的时候调用这两个方法就可以了 在 //to do 下面调用就可以了
我们来解决第4个问题:弹出的窗口怎么来?
我们需要在PhoneService 的onCreate 实例化一个WindowManager
1 mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
窗口管理类 有两个方法addView()和 removeView(),如果来电话或者去电我们调用一下 addview 就可以弹出一个窗口了 挂断时调用removeView()。
下面我们调用addview显示弹出窗口,so 封装一个方法
1 /** 2 * 弹出来电号码地址 3 */ 4 public void showWindow(String address){ 5 view = View.inflate(PhoneService.this, R.layout.address_show, null); 6 TextView tv_address = (TextView) view.findViewById(R.id.tv_address); 7 tv_address.setText(address); 8 9 params = new WindowManager.LayoutParams();10 params.height = WindowManager.LayoutParams.WRAP_CONTENT;11 params.width = WindowManager.LayoutParams.WRAP_CONTENT;12 params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 13 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;14 params.format = PixelFormat.TRANSLUCENT;15 params.type = WindowManager.LayoutParams.TYPE_TOAST;16 17 params.gravity = Gravity.CENTER_VERTICAL|Gravity.CENTER_HORIZONTAL;18 mWindowManager.addView(view, params );19 }
好了,这样就可以打电话时弹出电话归属地了!!!!!尼玛,等等!腾讯的手机管家弹出的归属地还可以移动,我的也必须动起,
给view 添加一个触摸事件就ok了
1 view.setOnTouchListener(new OnTouchListener() { 2 int startX ,startY; 3 @Override 4 public boolean onTouch(View v, MotionEvent event) { 5 switch (event.getAction()) { 6 case MotionEvent.ACTION_DOWN: 7 startX = (int) event.getRawX(); 8 startY = (int) event.getRawY(); 9 break;10 case MotionEvent.ACTION_MOVE:11 int newX = (int) event.getRawX();12 int newY= (int) event.getRawY();13 int dx = newX - startX;14 int dy = newY - startY;15 params.x += dx;16 params.y += dy;17 mWindowManager.updateViewLayout(view, params);18 // 重新初始化手指的开始结束位置。19 startX = (int) event.getRawX();20 startY = (int) event.getRawY();21 break;22 case MotionEvent.ACTION_UP:23 break;24 }25 return false;26 }27 });
这个触摸事件用 GestureDetector 更容易实现。
当service 死掉后 我们把该回收的要回收一下!扫扫地
1 @Override 2 public void onDestroy() { 3 // TODO Auto-generated method stub 4 super.onDestroy(); 5 mTeleManager.listen(myListener,PhoneStateListener.LISTEN_NONE); 6 myListener = null; 7 8 unregisterReceiver(receiver); 9 receiver = null;10 }
主要的代码就这么多
最后我们给客户要看到的界面是什么样的!让用户可操作是否开启归属地显示!直接给用户一个Button 自己玩吧
我们看一下activity 怎么写的
1 isRunPhoneService = ServiceUtil.isRun(this, "com.example.demo.PhoneService");2 mButton = (Button) findViewById(R.id.button);3 4 if(isRunPhoneService){5 mButton.setText("service 服务已开启");6 }else{7 mButton.setText("service 服务已关闭");8 }
button的点击事件
1 /** 2 * 点击开启服务,如果服务已开启,就不用开启 3 * 4 * @param view 5 */ 6 public void click(View view) { 7 isRunPhoneService = !isRunPhoneService; 8 Intent service = new Intent(MainActivity.this, PhoneService.class); 9 if(isRunPhoneService){10 mButton.setText("service 服务已开启");11 startService(service );12 }else{13 mButton.setText("service 服务已关闭");14 stopService(service);15 }16 }
结束
仿手机卫士打电话弹出归属地