欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 实现电话拦截及拦截提示音功能的开发

程序员文章站 2024-03-07 10:02:56
  本文所讲的内容是在android系统中如何写程序进行电话拦截,并发出拦截提示音提醒用户,可以说此功能还是比较实用的。    &...

  本文所讲的内容是在android系统中如何写程序进行电话拦截,并发出拦截提示音提醒用户,可以说此功能还是比较实用的。

       1、电话拦截

       这个功能大家可能都知道了,就是利用反射原理调用itelephony的隐藏方法来实现。

       2、拦截后提示忙音/空号/已关机/已停机

       这个功能其实是要用到mmi指令,具体如何设置呼叫转移的指定可以参考这里 http://baike.baidu.com/view/206402.html?fromtaglist。

       在本文中我们会用到“遇忙转移”的功能。中国移动的设置方式是 **67#电话号码#,取消方式为 ##67#。”无条件转移“用21代替67即可。这两个指令可以直接在手机的拨号界面输入并拨号测试。itelephony的endcall方法挂断电话后,会提示电话忙。如果事前设置好了忙时转移到一个空号/已关机/已停机的电话号码,就会提示您拨的电话号码是空号/已关机/已停机。

       其实大家可以下载 xxx卫士看下,它设置来电拒接模式后,都是会启动设置mmi指令的界面。然后再去“设置->通话设置->来电转接”,看看 “占线时转接” 设置好的电话号码,就可以知道空号/已关机/已停机对应的电话号码是什么了。

       1、修改一下blocked_number这个变量值,把它设置为你要测试拦截的电话号码。

       2、全部功能是在一个activity里实现的,所以大家要先运行这个activity,然后点击“设置呼叫转移”,设置好呼叫转移后,不要关闭这个activity,关了就拦截不了电话了。有心的朋友可以自己去写一个service在后台运行拦截功能。

       实现方式1:

       代码如下:

package net.toeach.android.callforwarding;   
  
import java.lang.reflect.method;   
  
import android.app.activity;   
import android.content.broadcastreceiver;   
import android.content.context;   
import android.content.intent;   
import android.content.intentfilter;   
import android.media.audiomanager;   
import android.net.uri;   
import android.os.bundle;   
import android.os.handler;   
import android.os.message;   
import android.os.remoteexception;   
import android.telephony.telephonymanager;   
import android.util.log;   
import android.view.view;   
import android.view.view.onclicklistener;   
  
import com.android.internal.telephony.itelephony;   
  
/**  
 * 演示如何设置呼叫转移,拦截电话(拦截后提示为空号)的例子  
 * @author tony from toeach.  
 * @email wan1976@21cn.com  
 */  
public class mainactivity extends activity {   
 private static final string tag = mainactivity.class.getsimplename();   
    
 private final static int op_register = 100;   
 private final static int op_cancel = 200;   
   
 private final static string blocked_number = "1892501xxxx";//要拦截的号码   
 //占线时转移,这里13800000000是空号,所以会提示所拨的号码为空号   
  private final string enable_service = "tel:**67*13800000000%23";   
  //占线时转移   
  private final string disable_service = "tel:%23%2367%23";   
  
 private incomingcallreceiver mreceiver;   
  private itelephony itelephony;   
  private audiomanager maudiomanager;   
   
  @override  
  public void oncreate(bundle savedinstancestate) {   
    super.oncreate(savedinstancestate);   
    setcontentview(r.layout.main);   
      
    findviewbyid(r.id.btnenable).setonclicklistener(new onclicklistener(){   
  public void onclick(view v) {   
     //设置呼叫转移   
     message message = mhandler.obtainmessage();   
  message.what = op_register;   
  mhandler.dispatchmessage(message);   
  }   
    });   
      
    findviewbyid(r.id.btndisable).setonclicklistener(new onclicklistener(){   
  public void onclick(view v) {   
  //取消呼叫转移   
       message message = mhandler.obtainmessage();   
    message.what = op_cancel;   
    mhandler.dispatchmessage(message);   
  }   
    });   
      
    mreceiver = new incomingcallreceiver();   
 intentfilter filter = new intentfilter("android.intent.action.phone_state");     
    registerreceiver(mreceiver, filter);// 注册broadcastreceiver   
      
    maudiomanager = (audiomanager) getsystemservice(context.audio_service);   
      
    //利用反射获取隐藏的endcall方法   
    telephonymanager telephonymgr = (telephonymanager) getsystemservice(context.telephony_service);   
 try {   
  method getitelephonymethod = telephonymanager.class.getdeclaredmethod("getitelephony", (class[]) null);   
  getitelephonymethod.setaccessible(true);   
  itelephony = (itelephony) getitelephonymethod.invoke(telephonymgr, (object[]) null);   
   } catch (exception e) {   
   e.printstacktrace();   
   }   
  }   
    
  private handler mhandler = new handler() {   
 public void handlemessage(message response) {   
   int what = response.what;   
   switch(what) {   
    case op_register:{   
    intent i = new intent(intent.action_call);   
       i.setdata(uri.parse(enable_service));   
       startactivity(i);   
    break;   
    }   
    case op_cancel:{   
    intent i = new intent(intent.action_call);   
       i.setdata(uri.parse(disable_service));   
       startactivity(i);   
    break;   
    }   
   }   
 }   
 };   
   
 private class incomingcallreceiver extends broadcastreceiver{   
 @override  
 public void onreceive(context context, intent intent) {   
  string state = intent.getstringextra(telephonymanager.extra_state);   
     log.i(tag, "state: "+ state);   
       
  string number = intent.getstringextra(telephonymanager.extra_incoming_number);   
     log.d(tag, "incomng number: " + number);   
       
     if(state.equalsignorecase(telephonymanager.extra_state_ringing)){//电话正在响铃        
     if(number.equals(blocked_number)){//拦截指定的电话号码   
      //先静音处理   
      maudiomanager.setringermode(audiomanager.ringer_mode_silent);   
      log.d(tag, "turn ringtone silent");   
        
      try {   
      //挂断电话   
   itelephony.endcall();   
   } catch (remoteexception e) {   
   e.printstacktrace();   
   }   
     
   //再恢复正常铃声   
         maudiomanager.setringermode(audiomanager.ringer_mode_normal);   
     }   
     }   
 }   
 }   
}  

         androidmanifest.xml 如下:

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android "  
   package="net.toeach.android.callforwarding"  
   android:versioncode="1"  
   android:versionname="1.0">  
  <application android:icon="@drawable/icon" android:label="@string/app_name">  
    <activity android:name=".mainactivity"  
         android:label="@string/app_name">  
      <intent-filter>  
        <action android:name="android.intent.action.main" />  
        <category android:name="android.intent.category.launcher" />  
      </intent-filter>  
    </activity>  
  
  </application>  
  <uses-sdk android:minsdkversion="8" />  
    
  <uses-permission android:name="android.permission.read_phone_state"/>  
  <uses-permission android:name="android.permission.call_phone"/>  
  
</manifest>   

        实现方式2:

       1、建立包android.refusecalling。

       refusecalling.java代码如下:

package android.refusecalling;   
  
import android.app.activity;   
import android.net.uri;   
import android.os.bundle;   
  
import java.lang.reflect.invocationtargetexception;   
import java.lang.reflect.method;   
  
import android.content.context;   
import android.content.intent;   
import android.os.remoteexception;   
import android.telephony.phonestatelistener;   
import android.telephony.telephonymanager;   
import android.util.log;   
import android.widget.textview;   
import com.android.internal.telephony.itelephony;   
  
public class refusecalling extends activity {   
  
  private static final string tag = "telephony";   
  private textview view = null;   
  private telephonymanager tmanager = null;   
  private itelephony itelephony = null;   
     
   //占线时转移,提示所拨的号码为空号   
  private final string enable_service = "tel:**67*13800000000%23";   
   //占线时转移,提示所拨的号码为关机   
  private final string enable_poweroff_service = "tel:**67*13810538911%23";   
  //占线时转移,提示所拨的号码为停机   
  private final string enable_stop_service = "tel:**21*13701110216%23";   
     
  //占线时转移   
  private final string disable_service = "tel:%23%2321%23";   
  
  @override  
  protected void oncreate(bundle savedinstancestate) {   
    super.oncreate(savedinstancestate);   
       
    //打开监听电话功能   
    telephonymanager mtelephonymgr = (telephonymanager) this  
        .getsystemservice(context.telephony_service);   
    mtelephonymgr.listen(new telelistener(),   
        phonestatelistener.listen_call_state);   
       
    //gui   
    view = new textview(this);   
    view.settext("listen the state of phone\n");   
    setcontentview(view);   
       
    tmanager = (telephonymanager)this.getsystemservice(context.telephony_service);   
    //初始化itelephony   
    class <telephonymanager> c = telephonymanager.class;   
    method getitelephonymethod = null;   
    try {   
    getitelephonymethod = c.getdeclaredmethod("getitelephony", (class[])null);   
    getitelephonymethod.setaccessible(true);   
    } catch (securityexception e) {   
    // todo auto-generated catch block   
    e.printstacktrace();   
    } catch (nosuchmethodexception e) {   
    // todo auto-generated catch block   
    e.printstacktrace();   
    }   
  
    try {   
    itelephony = (itelephony) getitelephonymethod.invoke(tmanager, (object[])null);   
    } catch (illegalargumentexception e) {   
    // todo auto-generated catch block   
    e.printstacktrace();   
    } catch (illegalaccessexception e) {   
    // todo auto-generated catch block   
    e.printstacktrace();   
    } catch (invocationtargetexception e) {   
    // todo auto-generated catch block   
    e.printstacktrace();   
    }   
       
    //启用空号提示   
    intent i = new intent(intent.action_call);   
    i.setdata(uri.parse(enable_stop_service));   
    startactivity(i);   
    log.v(tag, "启用空号提示");   
  }   
  
  class telelistener extends phonestatelistener {   
  
    @override  
    public void oncallstatechanged(int state, string incomingnumber) {   
      super.oncallstatechanged(state, incomingnumber);   
      switch (state) {   
      case telephonymanager.call_state_idle: {   
        log.e(tag, "call_state_idle");   
        view.append("call_state_idle " + "\n");   
        break;   
      }   
      case telephonymanager.call_state_offhook: {   
        log.e(tag, "call_state_offhook");   
        view.append("call_state_offhook" + "\n");   
        break;   
      }   
      case telephonymanager.call_state_ringing: {   
        log.e(tag, "call_state_ringing");   
        view.append("call_state_ringing" + "\n");   
        try {   
          itelephony.endcall();             
        } catch (remoteexception e1) {   
          // todo auto-generated catch block   
          e1.printstacktrace();   
        }           
        break;   
      }   
      default:   
        break;   
      }   
    }   
  }   
  protected void onstop() {   
    super.onstop();   
    }   
  protected void ondestroy() {   
    super.ondestroy();   
    finish();   
    intent i = new intent(intent.action_call);   
    i.setdata(uri.parse(disable_service));   
    startactivity(i);   
    }   
}  

       2、建立包android.telephony。

       neighboringcellinfo.aidl代码如下:

       package android.telephony;

       3、建立包 com.android.internal.telephony。

       itelephony.aidl代码如下:

/*  
 *  
 * licensed under the android license, version 2.0 (the "license");  
 * you may not use this file except in compliance with the license.  
 * you may obtain a copy of the license at  
 *  
 *   http://www.apache.org/licenses/license-2.0  
 *  
 * unless required by applicable law or agreed to in writing, software  
 * distributed under the license is distributed on an "as is" basis,  
 * without warranties or conditions of any kind, either express or implied.  
 * see the license for the specific language governing permissions and  
 * limitations under the license.  
 */  
  
package com.android.internal.telephony;   
  
import android.os.bundle;   
import java.util.list;   
import android.telephony.neighboringcellinfo;   
//import com.framespeed.neighboringcellinfo;   
  
/**  
 * interface used to interact with the phone. mostly this is used by the  
 * telephonymanager class. a few places are still using this directly.  
 * please clean them up if possible and use telephonymanager insteadl.  
 *  
 * {@hide}  
 */  
interface itelephony {   
  
  /**  
   * dial a number. this doesn't place the call. it displays  
   * the dialer screen.  
   * @param number the number to be dialed. if null, this  
   * would display the dialer screen with no number pre-filled.  
   */  
  void dial(string number);  
/**  
   * place a call to the specified number.  
   * @param number the number to be called.  
   */  
  void call(string number);   
  
  /**  
   * if there is currently a call in progress, show the call screen.  
   * the dtmf dialpad may or may not be visible initially, depending on  
   * whether it was up when the user last exited the incallscreen.  
   *  
   * @return true if the call screen was shown.  
   */  
  boolean showcallscreen();   
  
  /**  
   * variation of showcallscreen() that also specifies whether the  
   * dtmf dialpad should be initially visible when the incallscreen  
   * comes up.  
   *  
   * @param showdialpad if true, make the dialpad visible initially,  
   *          otherwise hide the dialpad initially.  
   * @return true if the call screen was shown.  
   *  
   * @see showcallscreen  
   */  
  boolean showcallscreenwithdialpad(boolean showdialpad);   
  
  /**  
   * end call if there is a call in progress, otherwise does nothing.  
   *  
   * @return whether it hung up  
   */  
  boolean endcall();   
  
  /**  
   * answer the currently-ringing call.  
   *  
   * if there's already a current active call, that call will be  
   * automatically put on hold. if both lines are currently in use, the  
   * current active call will be ended.  
   *  
   * todo: provide a flag to let the caller specify what policy to use  
   * if both lines are in use. (the current behavior is hardwired to  
   * "answer incoming, end ongoing", which is how the call button  
   * is specced to behave.)  
   *  
   * todo: this should be a oneway call (especially since it's called  
   * directly from the key queue thread).  
   */  
  void answerringingcall();   
  
  /**  
   * silence the ringer if an incoming call is currently ringing.  
   * (if vibrating, stop the vibrator also.)  
   *  
   * it's safe to call this if the ringer has already been silenced, or  
   * even if there's no incoming call. (if so, this method will do nothing.)  
   *  
   * todo: this should be a oneway call too (see above).  
   *    (actually *all* the methods here that return void can  
   *    probably be oneway.)  
   */  
  void silenceringer();   
  
  /**  
   * check if we are in either an active or holding call  
   * @return true if the phone state is offhook.  
   */  
  boolean isoffhook();   
  
  /**  
   * check if an incoming phone call is ringing or call waiting.  
   * @return true if the phone state is ringing.  
   */  
  boolean isringing();   
  
  /**  
   * check if the phone is idle.  
   * @return true if the phone state is idle.  
   */  
  boolean isidle();   
  
  /**  
   * check to see if the radio is on or not.  
   * @return returns true if the radio is on.  
   */  
  boolean isradioon();   
  
  /**  
   * check if the sim pin lock is enabled.  
   * @return true if the sim pin lock is enabled.  
   */  
  boolean issimpinenabled();   
  
  /**  
   * cancels the missed calls notification.  
   */  
  void cancelmissedcallsnotification();   
  
  /**  
   * supply a pin to unlock the sim. blocks until a result is determined.  
   * @param pin the pin to check.  
   * @return whether the operation was a success.  
   */  
  boolean supplypin(string pin);   
     
   /**  
   * [asd2-es1|connice|2011.04.14]  
   */  
  boolean supplypuk(string puk, string pin);   
  
  /**  
   * handles pin mmi commands (pin/pin2/puk/puk2), which are initiated  
   * without send (so <code>dial</code> is not appropriate).  
   *  
   * @param dialstring the mmi command to be executed.  
   * @return true if mmi command is executed.  
   */  
  boolean handlepinmmi(string dialstring);  
/**  
   * toggles the radio on or off.  
   */  
  void toggleradioonoff();   
  
  /**  
   * set the radio to on or off  
   */  
  boolean setradio(boolean turnon);   
  
  /**  
   * request to update location information in service state  
   */  
  void updateservicelocation();   
  
  /**  
   * enable location update notifications.  
   */  
  void enablelocationupdates();   
  
  /**  
   * disable location update notifications.  
   */  
  void disablelocationupdates();   
  
  /**  
   * enable a specific apn type.  
   */  
  int enableapntype(string type);   
  
  /**  
   * disable a specific apn type.  
   */  
  int disableapntype(string type);   
  
  /**  
   * allow mobile data connections.  
   */  
  boolean enabledataconnectivity();   
  
  /**  
   * disallow mobile data connections.  
   */  
  boolean disabledataconnectivity();   
  
  /**  
   * report whether data connectivity is possible.  
   */  
  boolean isdataconnectivitypossible();   
  
  bundle getcelllocation();   
  
  /**  
   * returns the neighboring cell information of the device.  
   */  
  list<neighboringcellinfo> getneighboringcellinfo();   
  
   int getcallstate();   
   int getdataactivity();   
   int getdatastate();   
  
  /**  
   * returns the current active phone type as integer.  
   * returns telephonymanager.phone_type_cdma if rilconstants.cdma_phone  
   * and telephonymanager.phone_type_gsm if rilconstants.gsm_phone  
   */  
  int getactivephonetype();   
  
  /**  
   * returns the cdma eri icon index to display  
   */  
  int getcdmaeriiconindex();   
  
  /**  
   * returns the cdma eri icon mode,  
   * 0 - on  
   * 1 - flashing  
   */  
  int getcdmaeriiconmode();   
  
  /**  
   * returns the cdma eri text,  
   */  
  string getcdmaeritext();   
  
  /**  
   * returns true if ota service provisioning needs to run.  
   * only relevant on some technologies, others will always  
   * return false.  
   */  
  boolean needsotaserviceprovisioning();   
  
  /**  
   * returns the unread count of voicemails  
   */  
  int getvoicemessagecount();   
  
  /**  
   * returns the network type  
   */  
  int getnetworktype();   
     
  /**  
   * return true if an icc card is present  
   */  
  boolean hasicccard();   
}   
  
parcelable neighboringcellinfo; 

  4、androidmanifest.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
   package="android.refusecalling"  
   android:versioncode="1"  
   android:versionname="1.0">  
   <uses-permission android:name="android.permission.read_phone_state" />    
   <uses-permission android:name="android.permission.call_phone" />    
   <uses-permission android:name="android.permission.modify_phone_state" />        
  
  <application android:icon="@drawable/icon" android:label="@string/app_name">  
    <activity android:name=".refusecalling"  
         android:label="@string/app_name">  
      <intent-filter>  
        <action android:name="android.intent.action.main" />  
        <category android:name="android.intent.category.launcher" />  
      </intent-filter>  
    </activity>  
  
  </application>  
</manifest>  

希望通过此文能对开发android 开发电话应用的朋友提供帮助,谢谢大家对本站的支持!