所要实现的功能如下图
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 context 12 * @param serviceName 13 * @return 14 */ 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 @Override 13 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 = address 32 .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 }
结束