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:
代码如下:
packagenet.toeach.android.callforwarding; importjava.lang.reflect.Method; importandroid.app.Activity; importandroid.content.BroadcastReceiver; importandroid.content.Context; importandroid.content.Intent; importandroid.content.IntentFilter; importandroid.media.AudioManager; importandroid.net.Uri; importandroid.os.Bundle; importandroid.os.Handler; importandroid.os.Message; importandroid.os.RemoteException; importandroid.telephony.TelephonyManager; importandroid.util.Log; importandroid.view.View; importandroid.view.View.OnClickListener; importcom.android.internal.telephony.ITelephony; /** *演示如何设置呼叫转移,拦截电话(拦截后提示为空号)的例子 *@authorTonyfromToEach. *@emailwan1976@21cn.com */ publicclassMainActivityextendsActivity{ privatestaticfinalStringTAG=MainActivity.class.getSimpleName(); privatefinalstaticintOP_REGISTER=100; privatefinalstaticintOP_CANCEL=200; privatefinalstaticStringBLOCKED_NUMBER="1892501xxxx";//要拦截的号码 //占线时转移,这里13800000000是空号,所以会提示所拨的号码为空号 privatefinalStringENABLE_SERVICE="tel:**67*13800000000%23"; //占线时转移 privatefinalStringDISABLE_SERVICE="tel:%23%2367%23"; privateIncomingCallReceivermReceiver; privateITelephonyiTelephony; privateAudioManagermAudioManager; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.btnEnable).setOnClickListener(newOnClickListener(){ publicvoidonClick(Viewv){ //设置呼叫转移 Messagemessage=mHandler.obtainMessage(); message.what=OP_REGISTER; mHandler.dispatchMessage(message); } }); findViewById(R.id.btnDisable).setOnClickListener(newOnClickListener(){ publicvoidonClick(Viewv){ //取消呼叫转移 Messagemessage=mHandler.obtainMessage(); message.what=OP_CANCEL; mHandler.dispatchMessage(message); } }); mReceiver=newIncomingCallReceiver(); IntentFilterfilter=newIntentFilter("android.intent.action.PHONE_STATE"); registerReceiver(mReceiver,filter);//注册BroadcastReceiver mAudioManager=(AudioManager)getSystemService(Context.AUDIO_SERVICE); //利用反射获取隐藏的endcall方法 TelephonyManagertelephonyMgr=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); try{ MethodgetITelephonyMethod=TelephonyManager.class.getDeclaredMethod("getITelephony",(Class[])null); getITelephonyMethod.setAccessible(true); iTelephony=(ITelephony)getITelephonyMethod.invoke(telephonyMgr,(Object[])null); }catch(Exceptione){ e.printStackTrace(); } } privateHandlermHandler=newHandler(){ publicvoidhandleMessage(Messageresponse){ intwhat=response.what; switch(what){ caseOP_REGISTER:{ Intenti=newIntent(Intent.ACTION_CALL); i.setData(Uri.parse(ENABLE_SERVICE)); startActivity(i); break; } caseOP_CANCEL:{ Intenti=newIntent(Intent.ACTION_CALL); i.setData(Uri.parse(DISABLE_SERVICE)); startActivity(i); break; } } } }; privateclassIncomingCallReceiverextendsBroadcastReceiver{ @Override publicvoidonReceive(Contextcontext,Intentintent){ Stringstate=intent.getStringExtra(TelephonyManager.EXTRA_STATE); Log.i(TAG,"State:"+state); Stringnumber=intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); Log.d(TAG,"IncomngNumber:"+number); if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING)){//电话正在响铃 if(number.equals(BLOCKED_NUMBER)){//拦截指定的电话号码 //先静音处理 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT); Log.d(TAG,"Turnringtonesilent"); try{ //挂断电话 iTelephony.endCall(); }catch(RemoteExceptione){ e.printStackTrace(); } //再恢复正常铃声 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); } } } } }
AndroidManifest.xml如下:
<?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="net.toeach.android.callforwarding" android:versionCode="1" android:versionName="1.0"> <applicationandroid:icon="@drawable/icon"android:label="@string/app_name"> <activityandroid:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> <uses-sdkandroid:minSdkVersion="8"/> <uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/> <uses-permissionandroid:name="android.permission.CALL_PHONE"/> </manifest>
实现方式2:
1、建立包android.refuseCalling。
refuseCalling.java代码如下:
packageandroid.refuseCalling; importandroid.app.Activity; importandroid.net.Uri; importandroid.os.Bundle; importjava.lang.reflect.InvocationTargetException; importjava.lang.reflect.Method; importandroid.content.Context; importandroid.content.Intent; importandroid.os.RemoteException; importandroid.telephony.PhoneStateListener; importandroid.telephony.TelephonyManager; importandroid.util.Log; importandroid.widget.TextView; importcom.android.internal.telephony.ITelephony; publicclassrefuseCallingextendsActivity{ privatestaticfinalStringTAG="Telephony"; privateTextViewview=null; privateTelephonyManagertManager=null; privateITelephonyiTelephony=null; //占线时转移,提示所拨的号码为空号 privatefinalStringENABLE_SERVICE="tel:**67*13800000000%23"; //占线时转移,提示所拨的号码为关机 privatefinalStringENABLE_POWEROFF_SERVICE="tel:**67*13810538911%23"; //占线时转移,提示所拨的号码为停机 privatefinalStringENABLE_STOP_SERVICE="tel:**21*13701110216%23"; //占线时转移 privatefinalStringDISABLE_SERVICE="tel:%23%2321%23"; @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //打开监听电话功能 TelephonyManagermTelephonyMgr=(TelephonyManager)this .getSystemService(Context.TELEPHONY_SERVICE); mTelephonyMgr.listen(newTeleListener(), PhoneStateListener.LISTEN_CALL_STATE); //gui view=newTextView(this); view.setText("listenthestateofphone\n"); setContentView(view); tManager=(TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE); //初始化iTelephony Class<TelephonyManager>c=TelephonyManager.class; MethodgetITelephonyMethod=null; try{ getITelephonyMethod=c.getDeclaredMethod("getITelephony",(Class[])null); getITelephonyMethod.setAccessible(true); }catch(SecurityExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); }catch(NoSuchMethodExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } try{ iTelephony=(ITelephony)getITelephonyMethod.invoke(tManager,(Object[])null); }catch(IllegalArgumentExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); }catch(IllegalAccessExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); }catch(InvocationTargetExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } //启用空号提示 Intenti=newIntent(Intent.ACTION_CALL); i.setData(Uri.parse(ENABLE_STOP_SERVICE)); startActivity(i); Log.v(TAG,"启用空号提示"); } classTeleListenerextendsPhoneStateListener{ @Override publicvoidonCallStateChanged(intstate,StringincomingNumber){ super.onCallStateChanged(state,incomingNumber); switch(state){ caseTelephonyManager.CALL_STATE_IDLE:{ Log.e(TAG,"CALL_STATE_IDLE"); view.append("CALL_STATE_IDLE"+"\n"); break; } caseTelephonyManager.CALL_STATE_OFFHOOK:{ Log.e(TAG,"CALL_STATE_OFFHOOK"); view.append("CALL_STATE_OFFHOOK"+"\n"); break; } caseTelephonyManager.CALL_STATE_RINGING:{ Log.e(TAG,"CALL_STATE_RINGING"); view.append("CALL_STATE_RINGING"+"\n"); try{ iTelephony.endCall(); }catch(RemoteExceptione1){ //TODOAuto-generatedcatchblock e1.printStackTrace(); } break; } default: break; } } } protectedvoidonStop(){ super.onStop(); } protectedvoidonDestroy(){ super.onDestroy(); finish(); Intenti=newIntent(Intent.ACTION_CALL); i.setData(Uri.parse(DISABLE_SERVICE)); startActivity(i); } }
2、建立包android.telephony。
NeighboringCellInfo.aidl代码如下:
packageandroid.telephony;
3、建立包com.android.internal.telephony。
ITelephony.aidl代码如下:
/* * *LicensedundertheandroidLicense,Version2.0(the"License"); *youmaynotusethisfileexceptincompliancewiththeLicense. *YoumayobtainacopyoftheLicenseat * *http://www.apache.org/licenses/LICENSE-2.0 * *Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense. */ packagecom.android.internal.telephony; importandroid.os.Bundle; importjava.util.List; importandroid.telephony.NeighboringCellInfo; //importcom.FrameSpeed.NeighboringCellInfo; /** *Interfaceusedtointeractwiththephone.Mostlythisisusedbythe *TelephonyManagerclass.Afewplacesarestillusingthisdirectly. *PleasecleanthemupifpossibleanduseTelephonyManagerinsteadl. * *{@hide} */ interfaceITelephony{ /** *Dialanumber.Thisdoesn'tplacethecall.Itdisplays *theDialerscreen. *@paramnumberthenumbertobedialed.Ifnull,this *woulddisplaytheDialerscreenwithnonumberpre-filled. */ voiddial(Stringnumber); /** *Placeacalltothespecifiednumber. *@paramnumberthenumbertobecalled. */ voidcall(Stringnumber); /** *Ifthereiscurrentlyacallinprogress,showthecallscreen. *TheDTMFdialpadmayormaynotbevisibleinitially,dependingon *whetheritwasupwhentheuserlastexitedtheInCallScreen. * *@returntrueifthecallscreenwasshown. */ booleanshowCallScreen(); /** *VariationofshowCallScreen()thatalsospecifieswhetherthe *DTMFdialpadshouldbeinitiallyvisiblewhentheInCallScreen *comesup. * *@paramshowDialpadiftrue,makethedialpadvisibleinitially, *otherwisehidethedialpadinitially. *@returntrueifthecallscreenwasshown. * *@seeshowCallScreen */ booleanshowCallScreenWithDialpad(booleanshowDialpad); /** *Endcallifthereisacallinprogress,otherwisedoesnothing. * *@returnwhetherithungup */ booleanendCall(); /** *Answerthecurrently-ringingcall. * *Ifthere'salreadyacurrentactivecall,thatcallwillbe *automaticallyputonhold.Ifbothlinesarecurrentlyinuse,the *currentactivecallwillbeended. * *TODO:provideaflagtoletthecallerspecifywhatpolicytouse *ifbothlinesareinuse.(Thecurrentbehaviorishardwiredto *"answerincoming,endongoing",whichishowtheCALLbutton *isspeccedtobehave.) * *TODO:thisshouldbeaonewaycall(especiallysinceit'scalled *directlyfromthekeyqueuethread). */ voidanswerRingingCall(); /** *Silencetheringerifanincomingcalliscurrentlyringing. *(Ifvibrating,stopthevibratoralso.) * *It'ssafetocallthisiftheringerhasalreadybeensilenced,or *evenifthere'snoincomingcall.(Ifso,thismethodwilldonothing.) * *TODO:thisshouldbeaonewaycalltoo(seeabove). *(Actually*all*themethodsherethatreturnvoidcan *probablybeoneway.) */ voidsilenceRinger(); /** *Checkifweareineitheranactiveorholdingcall *@returntrueifthephonestateisOFFHOOK. */ booleanisOffhook(); /** *Checkifanincomingphonecallisringingorcallwaiting. *@returntrueifthephonestateisRINGING. */ booleanisRinging(); /** *Checkifthephoneisidle. *@returntrueifthephonestateisIDLE. */ booleanisIdle(); /** *Checktoseeiftheradioisonornot. *@returnreturnstrueiftheradioison. */ booleanisRadioOn(); /** *CheckiftheSIMpinlockisenabled. *@returntrueiftheSIMpinlockisenabled. */ booleanisSimPinEnabled(); /** *Cancelsthemissedcallsnotification. */ voidcancelMissedCallsNotification(); /** *SupplyapintounlocktheSIM.Blocksuntilaresultisdetermined. *@parampinThepintocheck. *@returnwhethertheoperationwasasuccess. */ booleansupplyPin(Stringpin); /** *[ASD2-ES1|Connice|2011.04.14] */ booleansupplyPuk(Stringpuk,Stringpin); /** *HandlesPINMMIcommands(PIN/PIN2/PUK/PUK2),whichareinitiated *withoutSEND(so<code>dial</code>isnotappropriate). * *@paramdialStringtheMMIcommandtobeexecuted. *@returntrueifMMIcommandisexecuted. */ booleanhandlePinMmi(StringdialString); /** *Togglestheradioonoroff. */ voidtoggleRadioOnOff(); /** *Settheradiotoonoroff */ booleansetRadio(booleanturnOn); /** *Requesttoupdatelocationinformationinservicestate */ voidupdateServiceLocation(); /** *Enablelocationupdatenotifications. */ voidenableLocationUpdates(); /** *Disablelocationupdatenotifications. */ voiddisableLocationUpdates(); /** *EnableaspecificAPNtype. */ intenableApnType(Stringtype); /** *DisableaspecificAPNtype. */ intdisableApnType(Stringtype); /** *Allowmobiledataconnections. */ booleanenableDataConnectivity(); /** *Disallowmobiledataconnections. */ booleandisableDataConnectivity(); /** *Reportwhetherdataconnectivityispossible. */ booleanisDataConnectivityPossible(); BundlegetCellLocation(); /** *Returnstheneighboringcellinformationofthedevice. */ List<NeighboringCellInfo>getNeighboringCellInfo(); intgetCallState(); intgetDataActivity(); intgetDataState(); /** *Returnsthecurrentactivephonetypeasinteger. *ReturnsTelephonyManager.PHONE_TYPE_CDMAifRILConstants.CDMA_PHONE *andTelephonyManager.PHONE_TYPE_GSMifRILConstants.GSM_PHONE */ intgetActivePhoneType(); /** *ReturnstheCDMAERIiconindextodisplay */ intgetCdmaEriIconIndex(); /** *ReturnstheCDMAERIiconmode, *0-ON *1-FLASHING */ intgetCdmaEriIconMode(); /** *ReturnstheCDMAERItext, */ StringgetCdmaEriText(); /** *ReturnstrueifOTAserviceprovisioningneedstorun. *Onlyrelevantonsometechnologies,otherswillalways *returnfalse. */ booleanneedsOtaServiceProvisioning(); /** *Returnstheunreadcountofvoicemails */ intgetVoiceMessageCount(); /** *Returnsthenetworktype */ intgetNetworkType(); /** *ReturntrueifanICCcardispresent */ booleanhasIccCard(); } parcelableNeighboringCellInfo;
4、AndroidManifest.xml代码如下:
<?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="android.refuseCalling" android:versionCode="1" android:versionName="1.0"> <uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/> <uses-permissionandroid:name="android.permission.CALL_PHONE"/> <uses-permissionandroid:name="android.permission.MODIFY_PHONE_STATE"/> <applicationandroid:icon="@drawable/icon"android:label="@string/app_name"> <activityandroid:name=".refuseCalling" android:label="@string/app_name"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
希望通过此文能对开发Android开发电话应用的朋友提供帮助,谢谢大家对本站的支持!