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 开发电话应用的朋友提供帮助,谢谢大家对本站的支持!