android项目 之 来电管家(5) ----- 添加监听服务

上面四节,已经实现了界面设计,黑名单(白名单的添加与删除与黑名单同理,不再赘述),启用监听开关,定时拦截开关,及拦截模式选择等功能,下面就要实现来电管家最核心的功能,也就是拦截功能。

  主要思路

1.  制定拦截模式,这里主要有两个,一个是黑名单模式,也就是只拦截在黑名单中的号码;另一个就是白名单模式,拦截除了白名单以外的号码。

2.  根据用户自定义设置信息,制定正则表达式,判断拦截的标准。

3.  使用对应的类实现挂断电话的功能。

监听模块主要是利用service实现功能,为了实现电话挂断功能,这里需要调用远程的AIDL Service,大多数书上都介绍要将Android源代码中如下两个文件复制到项目的相应位置:

com.android.internal.telephony包下的ITelephony.aidl

android.telephony包下的NeighboringCellinfo.aidl

但是下载源码需要翻墙,有点麻烦,其实做这些的目的就是为了在根目录下自动生成ITelephony.java源文件,因此没有源码也可以,具体做法如下:

1)在项目的src目录下,新建package:com.android.internal.telephony

2)   在刚新建的package下,新建一个名为ITelephony.aidl的文件。

3)   将以下代码拷到刚新建的文件中。

  package com.android.internal.telephony;
        interface ITelephony{
            boolean endCall();
            void answerRingingCall();
        }  

这样,ADT会在根目录下自动生成ITelephony.java源文件了。

service的整个代码如下,里面也有解释:

ListenService.java

package com.example.callmanager;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.media.AudioManager;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.Toast;

import com.android.internal.telephony.ITelephony;

public class ListenService extends Service {
	TelephonyManager tManager;
	private SQLiteDatabase db;
	private SharedPreferences spf;
	private CustomPhoneCallListener callListener;

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();

	    System.out.println("create");
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		tManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);

	    callListener = new CustomPhoneCallListener();
		spf = this.getSharedPreferences("setting", Activity.MODE_PRIVATE);
		tManager.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);
		System.out.println("start");
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		callListener = null;
		tManager = null;
		System.out.println("destory");
		stopSelf();
	}

	@Override
	public boolean onUnbind(Intent intent) {
		// TODO Auto-generated method stub
		return super.onUnbind(intent);

	}

	//创建或打开数据库
    public void create_db(){
    	//创建或打开数据库
    	db = SQLiteDatabase.openOrCreateDatabase(ListenService.this.getFilesDir().toString()+"/list.db3", null);

    	if(db == null){
    		Toast.makeText(ListenService.this,"数据库创建不成功",Toast.LENGTH_LONG).show();
    	}
    	else{

    		/*//创建另一个表,用于存放来电信息
    		db.execSQL("create table if not exists callInfo(_id integer primary key autoincrement," +
    				"name varchar(50)," +
    				"number varchar(15),"+
    				"callTimes varchar(20));");*/

    	}
    }

   //插入
    public void insert_callInfo(String name,String number,String time){
    	Cursor cursor = db.rawQuery("select * from callInfo where callTimes = '"+time+"';",null);
    	if(cursor.getCount() == 0){
    		db.execSQL("insert into callInfo(name,number,callTimes) values('"+ name+ "','" + number +"','" + time + "');");
    	}
    	cursor.close();

    }

	 public class CustomPhoneCallListener extends PhoneStateListener{
	    	@Override
	    	public void onCallStateChanged(int state, String incomingNumber) {
	    		super.onCallStateChanged(state, incomingNumber);

	    			if(spf.getBoolean("isStartListen", false)){
		    			//判断该电话是否在黑名单中
	    				create_db();
	    				boolean callEnd_flag = false;
	    				String incomingName = null;
	    				SimpleDateFormat   formatter   =   new   SimpleDateFormat   ("MM-dd HH:mm");
				        Date   curDate   =   new   Date(System.currentTimeMillis());//获取当前时间
				        String   strTime   =   formatter.format(curDate);
	    				//如果启用白名单模式
	    				if(spf.getBoolean("isWhiteList",false)){
	    					System.out.println("whiteList");
	    					callEnd_flag = !isInWhiteList(incomingNumber);

	    					//根据号码找到联系人姓名
	    					incomingName = getContactsNameByNumber(incomingNumber);

	    				}
	    				//如果是黑名单模式
	    				else{
	    					incomingName = isInBalckList(incomingNumber);
	    					if(incomingName == null)
	    						callEnd_flag = false;
	    					else
	    						callEnd_flag = true;
	    				}

	    				//如果启用时间段,则判断当前拨打电话时间是否在设定时间段中
	    				if(spf.getBoolean("isTime", false)){
	    					System.out.println("inTime");
	    					callEnd_flag = callEnd_flag && isInterceptTime(strTime);
	    				}

		    			switch(state){
		    			case TelephonyManager.CALL_STATE_IDLE:
		    				break;
		    			case TelephonyManager.CALL_STATE_OFFHOOK :
		    				break;
		    			//当电话呼入时
		    			case TelephonyManager.CALL_STATE_RINGING :
		    				toggleRingerMute(getApplicationContext());

		    				if(callEnd_flag){

		    					try {
									Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
									//获取远程telephony_service的IBindler对象的代理
									IBinder binder = (IBinder)method.invoke(null, new Object[]{TELEPHONY_SERVICE});
									//将IBinder对象的代理转换为ITelephony对象
									ITelephony telephony = ITelephony.Stub.asInterface(binder);
									//挂断电话
									telephony.endCall();
		    					} catch (NoSuchMethodException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (ClassNotFoundException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (IllegalAccessException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (IllegalArgumentException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (InvocationTargetException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (RemoteException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}

		    					//将该号码插入来电信息数据库中
		    					//获得当前的时间
		    					if(incomingName == null){
		    						incomingName = "陌生号码";
		    					}
		    			        insert_callInfo(incomingName, incomingNumber, strTime);

		    				}
		    				System.out.println("bindListen");

		    				break;
		    			}
		    		}

	    		db.close();
	    	}
	    }
          //通过电话号码查找联系人的姓名,如果查找到,则返回联系人的姓名,否则,返回null
	 public String getContactsNameByNumber(String number){
		 Cursor c = getContentResolver().query(Uri.withAppendedPath(
	             PhoneLookup.CONTENT_FILTER_URI, number), new String[] {
	             PhoneLookup._ID,
	             PhoneLookup.NUMBER,
	             PhoneLookup.DISPLAY_NAME,
	             PhoneLookup.TYPE, PhoneLookup.LABEL }, null, null,   null );

		 if(c.getCount() == 0){
			 return null;
		 }
		 else {
	         c.moveToFirst();
	         return c.getString(2); //获取姓名

	     }

	 }

	 private static int previousMuteMode = -1;

	 /**
	  * 来电静音
	  *
	  * @param context
	  */
	 private void toggleRingerMute(Context context)
	 {
	     AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
	     if (previousMuteMode == -1)
	     {
	         previousMuteMode = am.getRingerMode();
	         am.setRingerMode(0);
	     }
	     am.setRingerMode(previousMuteMode);
	     previousMuteMode = -1;
	 }

	 //判断当前拨打时间 是否在拦截时间段里
	 public boolean isInterceptTime(String time){
		 //如果启用时间段
		 if(spf.getBoolean("isTime", false)){
			 String startTime = spf.getString("startTime", "");
			 String endTime = spf.getString("endTime", "");
			//比较当前时间是否在拦截时间段内
			if(time.compareTo(startTime) >= 0 && time.compareTo(endTime) <= 0){
				 return true;
		    }
		 }
		 return false;
	 }

	 //判断给定号码是否在白名单中
	 public boolean isInWhiteList(String phone){
		 Cursor cursor = db.rawQuery("select * from whiteList where number='"+phone+"';", null);
		 cursor.moveToFirst();
		 //如果该号码在白名单中,则返回true
		 if(cursor.getCount() > 0){
			 cursor.close();
			 return true;
		 }
		 return false;
	 }

	//判断给定号码是否在黑名单中
	public String isInBalckList(String phone){
	    	Cursor cursor = db.rawQuery("select * from blackList where number='"+phone+"';", null);
	    	String name = null;
	    	cursor.moveToFirst();
	    	if(cursor.getCount()>0)
	    		name = cursor.getString(cursor.getColumnIndex("name"));
	    	cursor.close();
	    	return name;
	}

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

}

代码很长,但核心的就是CustomPhoneCallListener这一部分,里面的主要思路就是通过读取用户的设置信息,判断是否拦截。

这里同时也实现了,将拦截信息写入数据库,所以也就有了上述代码中的数据库的相关代码了。

最后,重要的一点,就是,和Activity一样,service同样也需要进行注册,在AndroidManifest.xml里添加:

 		<service android:name="com.example.callmanager.ListenService"
   				android:enabled="true" >
   			<intent-filter>
       				<action android:name="com.example.callmanager.ListenService" />
   			 </intent-filter>
		</service> 

当然,因为要监听来电状态,少不了读取通话记录和读取电话状态的权限,在AndroidManifest.xml里添加:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>

这样,在该需要启用该监听服务时,就可以通过Intent来启动该服务,当启用该服务后,即使退出了Activity,也可以实现监听,因为service依然在后台运行,这就是service最基本的功能。

时间: 2024-10-16 03:19:19

android项目 之 来电管家(5) ----- 添加监听服务的相关文章

android项目 之 来电管家(8) ----- 添加开机自启动监听服务

现在大多数的应用都会开机自启动,来电管家更是如此,添加了开机自启动监听服务后,开机后即使你没有打开来电管家应用程序,一样可以拦截来电信息. 开机自启动Activity或Service的方法: 主要步骤: 1.  要有开机要启动的service或activity(这里开机要启动的当然就是ListenService了) 2. 编写一个BroadcastReceiver用以捕获ACTION_BOOT_COMPLETED这条广播,并在捕获之后启动我们要启动的Activity或service. BootC

android项目 之 来电管家(7) ----- 加载用户设置并启监听用服务

因为我们用的是SharedPreferences来存储用户设置信息,那么在初次进入来电管家时,会有一些默认的设置,后续根据用户的设置,更新设置信息文件的内容. 打开应用程序,首先启动的是ActivityGroupDemo,并默认显示黑名单界面,这时,需要在ActivityGroupDemo.java中添加代码,判断用户是否是第一次进入该应用,如果是第一次,则写入默认的设置信息. 这里判断用户是否为第一次进入该应用程序,采用的思路为: 1)因为SharedPreferences会在应用程序目录下的

android项目 之 来电管家(1) ----- 界面设计

因为需要,最近几天忙着写来电管家这个小软件,现在已经基本写的差不多了,基本的功能也都已实现,就剩下后续的完善了,而之前的记事本项目最近几天没写,但是肯定还是会完成的. 来电管家的基本功能,这里主要做的是拦截. 1.    添加黑白名单 2.    选择拦截模式 3.    启用拦截时间段 4.    拦截开关 主要功能,就是通过用户选择开启拦截,并选择拦截模式,这时就会启动后台监听服务,监听来电,判断是否挂断,并且,用户可以自由选择拦截时间段,也就是在该时间段内才启用监听服务. 先来看界面:  

android项目 之 来电管家(4) ----- 添加拦截时间段

在大多数的骚扰拦截类的软件中都会有定时拦截这个实用的的功能,其实,也不难实现. 看图: 在未选中启用时间段时,下面的两个开始时间和结束时间呈灰色状态,并且单击无响应,启用时间段后,下面则变成了可以单击的状态,通过单击可以弹出选择日期与时间的对话框,用于选择开始时间和结束时间. 主要思路: 1.  启用时间段,将下面的控件变成可获得焦点状态 2.  添加单击事件,弹出日期时间选择对话框 3.  选择时间,并显示在相应的位置 4.  通过SharedPrefresence将相关设置保存,以便下次启动

android项目 之 来电管家(2) ----- ListView+CheckBox的使用

上一节,已经完成了来电管家的界面设计,那么下面就要实现具体的功能了,如何将添加的黑白名单显示呢?这里用到了ListView,那么,如果需要删除黑白名单呢,是一个个长按弹出菜单删除,还是将所的黑白名单清空呢,这都不符合用户的需求,往往,都是删除多个,这就有个问题了,如何在ListView中删除指定的多个item呢??可能大家想到了,要用到CheckBox. 先看图: 可以看出,当处于删除模式时,底部按钮也变成了删除与返回,中间也显示了当前共选择了多少项,而且在ListView的每一个Item右边也

android项目 之 来电管家(3) ----- 添加与删除黑名单

现在就实现具体的功能-----添加黑名单 先看图: 从图中也可以看出整个逻辑,就是: 1.  点击底部的添加按钮 2.  转到联系人选择界面选择联系人(这里调用的是系统的联系人界面,每次只能选择一个联系人,当然了,要实现每次选择多个联系人也可以,可以自定义选择联系人界面) 3. 返回选择的联系人并插入到数据库中. 4. 遍历数据库中的黑名单表,将所有的黑名单显示在ListView中 5. 删除联系人 6. 刷新黑名单显示列表 主要代码(BlackListActivity.java): priva

Android 给按钮添加监听事件

在安卓开发中,如果要给一个按钮添加监听事件的话,有以下三种实现方式 1.方式一 public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获取button按钮 Butt

安卓按钮添加监听的三种方法

在安卓开发中,对按钮添加监听,是每一个app都需要用到的.通常我们会用三种办法来对按钮进行监听.下面我们哎说说着三种.我个人是比较喜欢匿名内部类的方法的. 第一种,匿名内部类 匿名内部类一般通过以下代码完成,顾名思义,通过传入匿名内部类来实现监听并写出对应的事件处理 btButton.setOnClickListener(new OnClickListener() { @SuppressLint("ShowToast") @Override public void onClick(Vi

Android USB大容量存储时SD卡状态监听(转)

对SD卡状态监听,到现在为止我知道的有两种方式: 1.注册StorageEventListener来监听sd卡状态 StorageEventListener中有onStorageStateChanged()方法,当sd卡状态改变时,此方法会调用,对各状态的判断一般会用到Environment类,此类中包含的有关sd卡状态的常量有: MEDIA_BAD_REMOVAL:表明SDCard 被卸载前己被移除 MEDIA_CHECKING:表明对象正在磁盘检查 MEDIA_MOUNTED:表明sd对象是