Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android之——手機黑名單的實現

Android之——手機黑名單的實現

編輯:關於Android編程

 

有了前面幾篇博文作為基礎(《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
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		// TODO Auto-generated method stub
        db.execSQL(create table blacknumber(_id integer primary key autoincrement,number text));
	}

	@Override
	public 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 stub
		mOpenHelper = 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;
	}
	
	//根據號碼查詢id
	public 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;
	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub

		Log.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;
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.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;
		@Override
		public void onCallStateChanged(int state, String incomingNumber) {
			// TODO Auto-generated method stub
			super.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 block
			e.printStackTrace();
		}
	}
	
	private final class MyContentObserver extends ContentObserver{

		private String incomingNumber;
		public MyContentObserver(Handler handler, String incomingNumber) {
			super(handler);
			// TODO Auto-generated constructor stub
			this.incomingNumber = incomingNumber;
		}
		
		@Override
		public void onChange(boolean selfChange) {
			// TODO Auto-generated method stub
			super.onChange(selfChange);
			Uri uri = Calls.CONTENT_URI;
			String where = Calls.NUMBER +  = ?;
			String[] selectionArgs = new String[]{incomingNumber};
			getContentResolver().delete(uri, where, selectionArgs);
			
			//解除監聽
			getContentResolver().unregisterContentObserver(this);
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

	
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		//取消狀態監聽
		tm.listen(listener, PhoneStateListener.LISTEN_NONE);
	}
}

 

5、頁面布局

具體實現如下:

 




    

    

    

        

        
    

    

        

        
    

 

6、菜單布局

具體實現如下:

 




    

    

 

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;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.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;
			}
		}

	}
	
	@Override
	protected void onNewIntent(Intent intent) {
		// TODO Auto-generated method stub
		super.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;
			}
		}

	}
	
	@Override
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenuInfo menuInfo) {
		// TODO Auto-generated method stub
		super.onCreateContextMenu(menu, v, menuInfo);
		
		menu.add(0, MENU_UPDATE_ID, 0, 更新黑名單號碼);
		menu.add(0, MENU_DELETE_ID, 0, 刪除黑名單號碼);
	}
	
	@Override
	public boolean onContextItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
		AdapterContextMenuInfo 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 stub
		int 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、來電相關

程序運行圖

height=343

添加黑名單

height=354

黑名單添加成功

height=341

長按更新或刪除黑名單

height=341

更新黑名單號碼

height=361

更新黑名單號碼

height=368

修改成功

height=353

以不是黑名單的號碼向手機打電話

height=239

正常顯示來電

height=353

以黑名單號碼給手機來電

height=313

不顯示來電

height=398

2、短信相關

正常號碼向手機發短信

height=230

正常提示短信信息

height=383

以黑名單中的號碼向手機發短信

height=280

不提示短信信息

height=385

至此,手機黑名單功能完成。

四、溫馨提示

本實例中,為了方面,我把一些文字直接寫在了布局文件中和相關的類中,大家在真實的項目中要把這些文字寫在string.xml文件中,在外部引用這些資源,切記,這是作為一個Android程序員最基本的開發常識和規范,我在這裡只是為了方便直接寫在了類和布局文件中。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved