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