转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47089209

有了前面几篇博文作为基础(《Android之——AIDL小结》、《Android之——AIDL深入》、《Android之——自动挂断电话的实现》),我将在这片博文中向大家介绍如何实现手机黑名单的功能。用过Android手机的用户都知道,如果不想接听一些人的电话或者接收一些人的短信,可以将这些人的手机号码放入手机黑名单中,此时,将不会接收到这些人打进来的电话和发送进来的短信。那这些功能具体是如何实现的呢?就让我们一起来实现这些功能吧。

一、原理

以一个数据库表来管理手机黑名单,对这张数据表的管理就是在管理手机黑名单,可以向这张数据表中的数据进行增、删、改、查操作,从而实现对手机黑名单的管理,当数据表中存在的某一个号码,向本机拨打电话或者发送短信的时候,我们可以拦截到相应的电话或者短信,自动挂断电话或者不再提示本机相关显示信息即可,同时,我们将手机是否开启了黑名单功能保存在SharedPreferences中。

原理讲完了,是不是很简单呢?下面,我们就一起来动手实现一个手机黑名单的功能吧。

二、实践

1、数据库设计

实现手机黑名单的功能,这里我们的数据库表很简单,只有两个字段,一个是数据表的id,一个是手机号码字段,凡是这张表中有的数据,都是被拉入手机黑名单的号码。

数据库设计如图所示:

2、数据库实现

  • 新建数据库的相关类BlackNumberDBHelper

这个类继承自SQLiteOpenHelper,内部以一个单例模式来获取SQLiteOpenHelper对象,同时在这个类中定义了数据库的名称和创建存储数据的数据表。

具体实现如下:

package cn.lyz.mobilesafe.db;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.database.sqlite.SQLiteOpenHelper;/** * 手机黑名单数据库相关 * @author liuyazhuang * */public class BlackNumberDBHelper extends SQLiteOpenHelper {private static SQLiteOpenHelper mInstance;private final static String name = "blacknumber.db";public static SQLiteOpenHelper getInstance(Context context){if(mInstance == null){mInstance = new BlackNumberDBHelper(context, name, null, 1);}return mInstance;}private BlackNumberDBHelper(Context context, String name,CursorFactory factory, int version) {super(context, name, factory, version);// TODO Auto-generated constructor stub}@Overridepublic void onCreate(SQLiteDatabase db) {// TODO Auto-generated method stub        db.execSQL("create table blacknumber(_id integer primary key autoincrement,number text)");}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// TODO Auto-generated method stub}}

  • 新建数据库的操作类

这个类中主要是封装了对数据库的增、删、改、查操作,我们可以直接调用这个类中的方法来实现对数据库的增、删、改、查操作,从而实现对手机黑名单的操作。

具体实现如下:

package cn.lyz.mobilesafe.dao;import java.util.ArrayList;import java.util.List;import cn.lyz.mobilesafe.db.BlackNumberDBHelper;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;/** * 数据库的操作类 * 封装了对数据表的增删改查操作 * @author liuyazhuang * */public class BlackNumberDao {private SQLiteOpenHelper mOpenHelper;public BlackNumberDao(Context context) {// TODO Auto-generated constructor stubmOpenHelper = BlackNumberDBHelper.getInstance(context);}//添加黑名单public void add(String number){SQLiteDatabase db = mOpenHelper.getWritableDatabase();if(db.isOpen()){ContentValues values = new ContentValues();values.put("number", number);db.insert("blacknumber", "_id", values);db.close();}}//判断号码是否是黑名单public boolean isBlackNumber(String number){boolean isExist = false;SQLiteDatabase db = mOpenHelper.getReadableDatabase();if(db.isOpen()){Cursor c = db.query("blacknumber", null, " number = ? ", new String[]{number}, null, null, null);if(c.moveToFirst()){isExist = true;}c.close();db.close();}return isExist;}//根据号码查询idpublic int queryId(String number){int _id = 0;SQLiteDatabase db = mOpenHelper.getReadableDatabase();if(db.isOpen()){Cursor c = db.query("blacknumber", new String[]{"_id"}, " number = ? ", new String[]{number}, null, null, null);if(c.moveToFirst()){_id = c.getInt(0);}c.close();db.close();}return _id;}//删除黑名单public void delete(String number){SQLiteDatabase db = mOpenHelper.getWritableDatabase();if(db.isOpen()){db.delete("blacknumber", " number = ? ", new String[]{number});db.close();}}//更新黑名单public void update(int id,String number){SQLiteDatabase db = mOpenHelper.getWritableDatabase();if(db.isOpen()){ContentValues values = new ContentValues();values.put("number", number);db.update("blacknumber", values, " _id = ? ", new String[]{id+""});db.close();}}//得到所有的黑名单public List findAll(){List blacknumbers = new ArrayList();SQLiteDatabase db = mOpenHelper.getReadableDatabase();if(db.isOpen()){Cursor c = db.query("blacknumber", new String[]{"number"}, null, null, null, null, null);while(c.moveToNext()){String number = c.getString(0);blacknumbers.add(number);}c.close();db.close();}return blacknumbers;}}

3、短信接收者SmsRecevier

新建短信接收者SmsRecevier继承BroadcastReceiver,这个类用来接收外界发送来的短信,在这个类中,首先拦截到发送短信的号码,到黑名单数据库中查询是否存在这个号码,如果存在,则说明当前发送短信的号码为黑名单中的号码,我们就把这个短信拦截掉,否则不做任何操作。

具体实现代码如下:

package cn.lyz.mobilesafe.receiver;import android.app.admin.DevicePolicyManager;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.media.MediaPlayer;import android.telephony.SmsManager;import android.telephony.SmsMessage;import android.util.Log;import cn.lyz.mobilesafe.R;import cn.lyz.mobilesafe.dao.BlackNumberDao;import cn.lyz.mobilesafe.engine.GPSInfoService;/** * 短信接收者 * @author liuyazhuang * */public class SmsRecevier extends BroadcastReceiver {private SharedPreferences sp;private DevicePolicyManager devicePolicyManager;private BlackNumberDao blackNumberDao;@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubLog.i("i", "已经拦截到了短信");sp = context.getSharedPreferences("config", Context.MODE_PRIVATE);blackNumberDao = new BlackNumberDao(context);//判断保护是否开启boolean isprotected = sp.getBoolean("isprotected", false);if(isprotected){devicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);Object[] pdus = (Object[]) intent.getExtras().get("pdus");for(Object pdu:pdus){String address = smsMessage.getDisplayOriginatingAddress();//判断是不是黑名单的一个短信boolean isBlackNumber = blackNumberDao.isBlackNumber(address);if(isBlackNumber){abortBroadcast();}}}}}

4、黑名单电话服务BlackNumberService

新建黑名单电话服务类BlackNumberService继承自Service,这是一个服务类,它会一直在Android后台运行,监听来电是否为黑名单中的号码。首先,这个类中的方法会先从SharedPreferences中获取是否开启了黑名单的信息,如果开启了黑名单,则再从数据库中查询相关电话号码是否为黑名单中的号码,如果是,则自动挂断电话(有关自动挂断电话的功能请详见《Android之——自动挂断电话的实现》一文)。

具体代码实现如下:

package cn.lyz.mobilesafe.service;import java.lang.reflect.Method;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.Service;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.database.ContentObserver;import android.net.Uri;import android.os.Handler;import android.os.IBinder;import android.provider.CallLog.Calls;import android.telephony.PhoneStateListener;import android.telephony.TelephonyManager;import cn.lyz.mobilesafe.activity.BlackNumberListActivity;import cn.lyz.mobilesafe.dao.BlackNumberDao;import com.android.internal.telephony.ITelephony;/** * 黑名单电话服务 * @author liuyazhuang * */public class BlackNumberService extends Service {private TelephonyManager tm;private MyPhoneStateListener listener;private BlackNumberDao blackNumberDao;private SharedPreferences sp;private NotificationManager nm;@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);sp = getSharedPreferences("config", Context.MODE_PRIVATE);listener = new MyPhoneStateListener();tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);blackNumberDao = new BlackNumberDao(this);nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);}private final class MyPhoneStateListener extends PhoneStateListener{private long startTime = 0;@Overridepublic void onCallStateChanged(int state, String incomingNumber) {// TODO Auto-generated method stubsuper.onCallStateChanged(state, incomingNumber);switch (state) {case TelephonyManager.CALL_STATE_RINGING://判断来电黑名单是否开启boolean isblackstart = sp.getBoolean("isblacknumber", false); if(isblackstart){boolean isBlackNumber = blackNumberDao.isBlackNumber(incomingNumber);if(isBlackNumber){endCall(incomingNumber);return;}}startTime = System.currentTimeMillis();break;case TelephonyManager.CALL_STATE_OFFHOOK:break;case TelephonyManager.CALL_STATE_IDLE:long endTime = System.currentTimeMillis();//来电一声响if(endTime - startTime < 3000){//发送通知Notification notification = new Notification(android.R.drawable.stat_notify_missed_call, "拦截到来电一声响", System.currentTimeMillis());Intent intent = new Intent(getApplicationContext(),BlackNumberListActivity.class);intent.putExtra("number", incomingNumber);PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 100, intent, 0);notification.setLatestEventInfo(getApplicationContext(), "来电一声响", "拦截到来电一声响", contentIntent);notification.flags = Notification.FLAG_AUTO_CANCEL;nm.notify(100, notification);}break;default:break;}}}//挂断电话private void endCall(String incomingNumber){try {Class<?> clazz = Class.forName("android.os.ServiceManager");Method method = clazz.getMethod("getService", String.class);IBinder ibinder = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);ITelephony iTelephony = ITelephony.Stub.asInterface(ibinder);iTelephony.endCall();//删除通话记录 通话记录的保存是一个异步的操作,需要使用ContentObserver技术来实现Uri uri = Calls.CONTENT_URI;getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler(),incomingNumber));} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}private final class MyContentObserver extends ContentObserver{private String incomingNumber;public MyContentObserver(Handler handler, String incomingNumber) {super(handler);// TODO Auto-generated constructor stubthis.incomingNumber = incomingNumber;}@Overridepublic void onChange(boolean selfChange) {// TODO Auto-generated method stubsuper.onChange(selfChange);Uri uri = Calls.CONTENT_URI;String where = Calls.NUMBER + " = ?";String[] selectionArgs = new String[]{incomingNumber};getContentResolver().delete(uri, where, selectionArgs);//解除监听getContentResolver().unregisterContentObserver(this);}}@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();//取消状态监听tm.listen(listener, PhoneStateListener.LISTEN_NONE);}}

5、页面布局

具体实现如下:

<?xml version="1.0" encoding="utf-8"?>                                                        

6、菜单布局

具体实现如下:

<?xml version="1.0" encoding="utf-8"?>                

7、手机黑名单的入口类BlackNumberListActivity

这个类是应用程序的入口类,是用户直接可以看到的界面,在这个类中,我们首先找到页面上的各个控件,设置相关的事件状态,我们通过在这个类中设置上下文菜单来实现对黑名单的修改与删除操作,通过长按黑名单列表来实现修改与删除黑名单中相应号码的操作。

具体实现如下:

package cn.lyz.mobilesafe.activity;import java.util.List;import android.app.Activity;import android.app.AlertDialog;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.util.Log;import android.view.ContextMenu;import android.view.ContextMenu.ContextMenuInfo;import android.view.LayoutInflater;import android.view.MenuItem;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.AdapterView.AdapterContextMenuInfo;import android.widget.Button;import android.widget.EditText;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;import cn.lyz.mobilesafe.R;import cn.lyz.mobilesafe.adapter.BlackNumberAdapter;import cn.lyz.mobilesafe.dao.BlackNumberDao;/** * 手机黑名单的实现 * @author liuyazhuang * */public class BlackNumberListActivity extends Activity implements OnClickListener{private static final int MENU_UPDATE_ID = 0;private static final int MENU_DELETE_ID = 1;private TextView tv_add_blacknumber;private ListView lv_blacknumber;private TextView empty;private View view;private LayoutInflater mInflater;private EditText et_number_blacknumber_dialog;private Button bt_ok_blacknumber_dialog;private Button bt_cancel_blacknumber_dialog;private BlackNumberDao blackNumberDao;private AlertDialog dialog;private BlackNumberAdapter mAdapter;private int flag = 0;private final static int ADD = 1;private final static int UPDATE = 2;private String blacknumber;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);Log.i("i", "  on create ");blacknumber = getIntent().getStringExtra("number");setContentView(R.layout.blacknumber_list);tv_add_blacknumber = (TextView) findViewById(R.id.tv_add_blacknumber);lv_blacknumber = (ListView) findViewById(R.id.lv_blacknumber);empty = (TextView) findViewById(R.id.empty);mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);view = mInflater.inflate(R.layout.add_blacknumber_dialog, null);et_number_blacknumber_dialog = (EditText) view.findViewById(R.id.et_number_blacknumber_dialog);bt_ok_blacknumber_dialog = (Button) view.findViewById(R.id.bt_ok_blacknumber_dialog);bt_cancel_blacknumber_dialog = (Button) view.findViewById(R.id.bt_cancel_blacknumber_dialog);bt_ok_blacknumber_dialog.setOnClickListener(this);bt_cancel_blacknumber_dialog.setOnClickListener(this);//当listview没有数据的显示内容lv_blacknumber.setEmptyView(empty);blackNumberDao = new BlackNumberDao(this);List blacknumbers = blackNumberDao.findAll();mAdapter = new BlackNumberAdapter(this, blacknumbers);lv_blacknumber.setAdapter(mAdapter);tv_add_blacknumber.setOnClickListener(this);//给一个控件注册上下文菜单registerForContextMenu(lv_blacknumber);if(blacknumber != null){boolean isBlackNumber = blackNumberDao.isBlackNumber(blacknumber);if(!isBlackNumber){ViewGroup parent = (ViewGroup) view.getParent();if(parent != null){parent.removeAllViews();}et_number_blacknumber_dialog.setText(blacknumber);AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("添加黑名单");builder.setView(view);dialog = builder.create();dialog.show();flag = ADD;}}}@Overrideprotected void onNewIntent(Intent intent) {// TODO Auto-generated method stubsuper.onNewIntent(intent);Log.i("i", "  on new  intent");blacknumber = intent.getStringExtra("number");if(blacknumber != null){boolean isBlackNumber = blackNumberDao.isBlackNumber(blacknumber);if(!isBlackNumber){ViewGroup parent = (ViewGroup) view.getParent();if(parent != null){parent.removeAllViews();}et_number_blacknumber_dialog.setText(blacknumber);AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("添加黑名单");builder.setView(view);dialog = builder.create();dialog.show();flag = ADD;}}}@Overridepublic void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {// TODO Auto-generated method stubsuper.onCreateContextMenu(menu, v, menuInfo);menu.add(0, MENU_UPDATE_ID, 0, "更新黑名单号码");menu.add(0, MENU_DELETE_ID, 0, "删除黑名单号码");}@Overridepublic boolean onContextItemSelected(MenuItem item) {// TODO Auto-generated method stubAdapterContextMenuInfo acmi = (AdapterContextMenuInfo) item.getMenuInfo();int position = acmi.position;blacknumber = (String) mAdapter.getItem(position);int id = item.getItemId();switch (id) {case MENU_UPDATE_ID:ViewGroup parent = (ViewGroup) view.getParent();if(parent != null){parent.removeAllViews();}et_number_blacknumber_dialog.setText(blacknumber);AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("更新黑名单");builder.setView(view);dialog = builder.create();dialog.show();flag = UPDATE;break;case MENU_DELETE_ID:blackNumberDao.delete(blacknumber);mAdapter.setBlacknumbers(blackNumberDao.findAll());mAdapter.notifyDataSetChanged();break;default:break;}return super.onContextItemSelected(item);}//按钮点击事件public void onClick(View v) {// TODO Auto-generated method stubint id = v.getId();switch (id) {case R.id.tv_add_blacknumber:ViewGroup parent = (ViewGroup) view.getParent();if(parent != null){parent.removeAllViews();}AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("添加黑名单");builder.setView(view);dialog = builder.create();dialog.show();flag = ADD;break;case R.id.bt_ok_blacknumber_dialog:String number = et_number_blacknumber_dialog.getText().toString();if("".equals(number)){Toast.makeText(this, "黑名单号码不能为空", 1).show();}else{boolean isBlackNumber = blackNumberDao.isBlackNumber(number);if(isBlackNumber){Toast.makeText(this, "号码已经存在于黑名单中", 1).show();}else{if(flag == ADD){blackNumberDao.add(number);Toast.makeText(this, "黑名单号码添加成功", 1).show();}else{int _id = blackNumberDao.queryId(blacknumber);blackNumberDao.update(_id, number);Toast.makeText(this, "黑名单号码修改成功", 1).show();}dialog.dismiss();List blacknumbers = blackNumberDao.findAll();mAdapter.setBlacknumbers(blacknumbers);mAdapter.notifyDataSetChanged();//让listview自动刷新}}break;case R.id.bt_cancel_blacknumber_dialog:dialog.dismiss();break;default:break;}}}

8、注册权限

最后,别忘了在AndroidManifest.xml中注册相关权限

具体要注册的权限如下:

三、运行效果

1、来电相关

程序运行图

Android之——手机黑名单的实现_第1张图片

添加黑名单

Android之——手机黑名单的实现_第2张图片

黑名单添加成功

Android之——手机黑名单的实现_第3张图片

长按更新或删除黑名单

Android之——手机黑名单的实现_第4张图片

更新黑名单号码

Android之——手机黑名单的实现_第5张图片

更新黑名单号码

Android之——手机黑名单的实现_第6张图片

修改成功

Android之——手机黑名单的实现_第7张图片

以不是黑名单的号码向手机打电话

Android之——手机黑名单的实现_第8张图片

正常显示来电

Android之——手机黑名单的实现_第9张图片

以黑名单号码给手机来电

Android之——手机黑名单的实现_第10张图片

不显示来电

Android之——手机黑名单的实现_第11张图片

2、短信相关

正常号码向手机发短信

Android之——手机黑名单的实现_第12张图片

正常提示短信信息

Android之——手机黑名单的实现_第13张图片

以黑名单中的号码向手机发短信

Android之——手机黑名单的实现_第14张图片

不提示短信信息

Android之——手机黑名单的实现_第15张图片

至此,手机黑名单功能完成。

四、温馨提示

本实例中,为了方面,我把一些文字直接写在了布局文件中和相关的类中,大家在真实的项目中要把这些文字写在string.xml文件中,在外部引用这些资源,切记,这是作为一个Android程序员最基本的开发常识和规范,我在这里只是为了方便直接写在了类和布局文件中。

更多相关文章

  1. Android手机游戏开发入门教程
  2. 谷歌正式发布Android 2.2手机操作平台
  3. 浅析Android手机卫士接收短信指令执行相应操作
  4. 有关Android手机软件详细分析
  5. Android下实现手机验证码
  6. Android获得手机信息
  7. android设定手机的显示模式,横竖屏,是否全屏

随机推荐

  1. 自定义android Dialog
  2. Android 屏幕真实分辨率获取
  3. Android 对程序异常崩溃的捕捉
  4. 【Android】定位与解决anr错误记录
  5. Android:验证EditText输入框输入的手机号
  6. android activity之间传递bean类型数据
  7. Android APP开发集成工具
  8. Android View之组合控件实例(二)
  9. 蓝牙原理Android代码实现
  10. NDK is missing a "platforms" directory