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