Android 代码实现来电拦截

为了更好地理解这个Demo,我先向大家介绍一下需求与功能。

需求:

每天都会有很多无聊的电话,比如推销商品等,占用我们大量时间不说,有时候还会打乱我们的思路,扰乱我们的正常生活。所以实现一个对某些号码(比如陌生号码,指定号码/黑名单等)进行拦截以避免受到骚扰,是很有现实用途的。

为了避免程序过分复杂,造成不易学习的麻烦我在这里只实现“如果来电号码没在联系人中,则进行挂断,并存入xml文件(SharedPreferences)中,并在首页显示”,以期达到抛砖引玉的效果。

 

其实在android在1.1版本后就已经把Phone类的相关API给隐藏起来了,想要用代码实现挂断电话的功能,就必须通过AIDL才行,然后利用反射来使用其方法。

第一步:在程序中新建一个包,包名必须为:com.android.internal.telephony,因为要使用aidl。

第二步:在这个包里面新建一个名为ITelephony.aidl的文件,然后在文件里面写入代码:

 

[java] view plaincopy
 
  1. package com.android.internal.telephony;  
  2.     interface ITelephony{  
  3.         boolean endCall();  
  4.         void answerRingingCall();  
  5.     }  

 

 

然后是要监听电话状态,当来电时,检测来电号码是否符合拦截标准(这个拦截标准是我们自己定的,你可以拦截指定号码如实现一个黑名单的功能,我们在这里拦截所有不在联系人里的号码,并把此号码存入文件,以方便在首页显示),代码如下:

 

[java] view plaincopy
 
  1. import java.lang.reflect.Method;  
  2. import java.util.ArrayList;  
  3.   
  4. import com.android.internal.telephony.ITelephony;  
  5.   
  6. import android.app.Service;  
  7. import android.content.BroadcastReceiver;  
  8. import android.content.ContentResolver;  
  9. import android.content.Context;  
  10. import android.content.Intent;  
  11. import android.content.SharedPreferences;  
  12. import android.content.SharedPreferences.Editor;  
  13. import android.database.Cursor;  
  14. import android.provider.ContactsContract;  
  15. import android.telephony.TelephonyManager;  
  16. import android.util.Log;  
  17.   
  18. public class PhoneStatReceiver extends BroadcastReceiver{  
  19.   
  20.     String TAG = "tag";  
  21.     TelephonyManager telMgr;  
  22.     @Override  
  23.     public void onReceive(Context context, Intent intent) {  
  24.         telMgr = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);  
  25.         switch (telMgr.getCallState()) {  
  26.             case TelephonyManager.CALL_STATE_RINGING:  
  27.                 String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);   
  28.                 Log.v(TAG,"number:"+number);  
  29.                 if (!getPhoneNum(context).contains(number)) {  
  30.                     SharedPreferences phonenumSP = context.getSharedPreferences("in_phone_num", Context.MODE_PRIVATE);  
  31.                     Editor editor = phonenumSP.edit();  
  32.                     editor.putString(number,number);  
  33.                     editor.commit();  
  34.                     endCall();  
  35.                 }  
  36.                 break;  
  37.             case TelephonyManager.CALL_STATE_OFFHOOK:                                 
  38.                 break;  
  39.             case TelephonyManager.CALL_STATE_IDLE:                                 
  40.                 break;  
  41.         }  
  42.           
  43.     }  
  44.     /** 
  45.      * 挂断电话 
  46.      */  
  47.     private void endCall()  
  48.     {  
  49.         Class<TelephonyManager> c = TelephonyManager.class;           
  50.         try  
  51.         {  
  52.             Method getITelephonyMethod = c.getDeclaredMethod("getITelephony", (Class[]) null);  
  53.             getITelephonyMethod.setAccessible(true);  
  54.             ITelephony iTelephony = null;  
  55.             Log.e(TAG, "End call.");  
  56.             iTelephony = (ITelephony) getITelephonyMethod.invoke(telMgr, (Object[]) null);  
  57.             iTelephony.endCall();  
  58.         }  
  59.         catch (Exception e)  
  60.         {  
  61.             Log.e(TAG, "Fail to answer ring call.", e);  
  62.         }          
  63.     }  
  64.     private ArrayList<String>  getPhoneNum(Context context) {  
  65.         ArrayList<String> numList = new ArrayList<String>();  
  66.         //得到ContentResolver对象     
  67.         ContentResolver cr = context.getContentResolver();       
  68.         //取得电话本中开始一项的光标     
  69.         Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, nullnullnullnull);     
  70.         while (cursor.moveToNext())     
  71.         {                 
  72.             // 取得联系人ID     
  73.             String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));     
  74.             Cursor phone = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,  
  75.                     ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, nullnull);     
  76.             // 取得电话号码(可能存在多个号码)     
  77.             while (phone.moveToNext())     
  78.             {     
  79.                 String strPhoneNumber = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));     
  80.                 numList.add(strPhoneNumber);    
  81.                 Log.v("tag","strPhoneNumber:"+strPhoneNumber);  
  82.             }     
  83.               
  84.             phone.close();     
  85.         }     
  86.         cursor.close();  
  87.         return numList;  
  88.     }  
  89. }  

这里我们要注意以下几点:

 

1.PhoneStatReceiver一定要在清单文件(AndroidManifest.xml)中注册。

2.一定要添加权限

AndroidManifest文件如下:

 

[html] view plaincopy
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.xxxx.xxxx"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk android:minSdkVersion="8" />  
  8.     <!-- 挂断手机的权限 -->  
  9.     <uses-permission android:name="android.permission.CALL_PHONE"/>  
  10.     <!-- 读取手机状态的权限 -->  
  11.     <uses-permission android:name="android.permission.READ_PHONE_STATE" />  
  12.     <!-- 读content的权限 -->  
  13.     <uses-permission android:name="android.permission.READ_CONTACTS" />  
  14.     <application  
  15.         android:icon="@drawable/ic_launcher"  
  16.         android:label="@string/app_name" >  
  17.         <activity  
  18.             android:name=".MainActivity"  
  19.             android:label="@string/app_name" >  
  20.             <intent-filter>  
  21.                 <action android:name="android.intent.action.MAIN" />  
  22.   
  23.                 <category android:name="android.intent.category.LAUNCHER" />  
  24.             </intent-filter>  
  25.         </activity>  
  26.         <!-- 注册监听手机状态 -->  
  27.         <receiver android:name=".PhoneStatReceiver">  
  28.             <intent-filter android:priority="1000" >  
  29.                 <action android:name="android.intent.action.PHONE_STATE" />  
  30.             </intent-filter>  
  31.         </receiver>  
  32.           
  33.     </application>  
  34.   
  35. </manifest>  

其实最到这里,整个拦截功能就已经实现了,但是呢,我们的首页也不能让它光秃秃的显示个Hello World!吧。所以,在MainActivity中,再给大家加点料,就是在listView中显示所有已经被拦截的电话号码,代码如下:

 

 

[java] view plaincopy
 
  1. import java.util.Map;  
  2. import android.app.ListActivity;  
  3. import android.content.Context;  
  4. import android.content.SharedPreferences;  
  5. import android.os.Bundle;  
  6. import android.util.Log;  
  7. import android.widget.ArrayAdapter;  
  8.   
  9. public class MainActivity extends ListActivity {  
  10.     @Override  
  11.     public void onCreate(Bundle savedInstanceState) {  
  12.         super.onCreate(savedInstanceState);  
  13.           
  14.         SharedPreferences phonenumSP = getSharedPreferences("in_phone_num", Context.MODE_PRIVATE);  
  15.         Map map = phonenumSP.getAll();  
  16.         Object[] array = map.keySet().toArray();  
  17.         Log.v("tag",map.toString()+map.size());  
  18.         ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1,array);  
  19.           
  20.         setListAdapter(adapter);  
  21.     }  
  22. }  

 

好了,整个项目就完成了,我们可以拦截骚扰电话了,这只是一个小例子,你可以添加一些控制功能以更加人性化,比如开启和关闭拦截,可选的拦截时间段,给ListView添加点击事件使用户可以把拦截到的电话添加到通讯录等功能。

不过,这里只是完成了对来电的拦截功能,未对外拨电话进行拦截,下篇博客再写吧!

 

参考:http://blog.163.com/wu_zefeng/blog/static/1826291752011312114420975/

    http://www.cotrun.net/blog/1572.html

posted @ 2014-04-03 23:36  V青山绿水  阅读(5579)  评论(2编辑  收藏  举报