Android四大组件应用系列——实现电话拦截和电话录音
【大咖・来了 第7期】10月24日晚8点观看《智能导购对话机器人实践》
使用BordercastReceiver和Service组件实现下述功能:
1.当手机处于来电状态,启动监听服务,对来电进行监听录音。
2.设置电话黑名单,当来电是黑名单电话,则直接挂断。
当拨打电话或电话状态发生改变时,系统就会发出有序广播,因此我们可以使用BordercastReceiver接受广播,因BordercastReceiver执行时间短不能执行耗时任务也不能使用子线程,因此我们应启动一个Service来监听电话并进行处理
二、加入AIDL文件
Android没有对外公开结束通话的API,要结束通话就必须使用AIDL与电话管理服务进行通信,并调用服务中的API实现结束通话,这样需要android 源码文件NeighboringCellInfo.aidl和ITelephony.aidl添加到项目中,如图所示:
Android Studio 会自动编译产生对应的类文件
三、编写TelReceiver组件
- public class TelReceiver extends BroadcastReceiver {
- public TelReceiver() {
- }
- @Override
- public void onReceive(Context context, Intent intent) {
- Intent i=new Intent(context,ListenPhoneService.class);
- i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- i.setAction(intent.getAction());
- i.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER,
- intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER));//电话号码
- i.putExtra(TelephonyManager.EXTRA_STATE,
- intent.getStringExtra(TelephonyManager.EXTRA_STATE));//电话状态
- context.startService(i);//启动服务
- }
- }
注册广播:
四、编写ListenPhoneService组件
- <receiver android:name=".TelReceiver" >
- <intent-filter android:priority="1000" >
- <action android:name="android.intent.action.PHONE_STATE" />
- <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
- </intent-filter>
- </receiver>
- public class ListenPhoneService extends Service {
- private AudioManager mAudioManager;
- private TelephonyManager tm;
- public ListenPhoneService() {
- }
- @Override
- public void onCreate() {
- super.onCreate();
- mAudioManager=(AudioManager)getSystemService(Context.AUDIO_SERVICE);
- tm=(TelephonyManager)getSystemService(Service.TELEPHONY_SERVICE);
- }
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){//去电广播,android没有来电话广播
- }else{//去掉拨打电话就是来电状态了
- //方法1
- //获得来电电话
- // String number=intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
- //获得电话状态
- // String state=intent.getStringExtra(TelephonyManager.EXTRA_STATE);
- // Log.d("jereh", "incoming phone:" + number);
- // Log.d("jereh","call state:"+state);
- // TelephonyManager.EXTRA_STATE_IDLE: 没有来电 或者 挂断
- // TelephonyManagerEXTRA_STATE_OFFHOOK: 接起电话
- // TelephonyManager.EXTRA_STATE_RINGING:当电话呼入时,响铃时
- // if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
- // if(number.equals("13280998858")){//拦截指定的电话号码
- // mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
- // Log.d("jereh","电话被拦截");
- // stopCall();
- // mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);//恢复铃声
- // }
- // }else if(state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
- //接起电话
- // recordCall();//开始录音
- // }else if(state.equals(TelephonyManager.EXTRA_STATE_IDLE)){
- // stopCall();//停止录音
- // }
- //方法2
- // 设置一个监听器,监听电话状态
- tm.listen(listener,PhoneStateListener.LISTEN_CALL_STATE);
- }
- return super.onStartCommand(intent, flags, startId);
- }
- /**
- * 挂断电话
- */
- private void stopCall(){
- try {
- //Android的设计将ServiceManager隐藏了,所以只能使用反射机制获得。
- Method method=Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
- IBinder binder=(IBinder)method.invoke(null, new Object[]{"phone"});//获得系统电话服务
- ITelephony telephoney=ITelephony.Stub.asInterface(binder);
- telephoney.endCall();//挂断电话
- stopSelf();//停止服务
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- PhoneStateListener listener=new PhoneStateListener(){
- @Override
- public void onCallStateChanged(int state,String incomingNumber){
- switch (state){
- //手机空闲了
- case TelephonyManager.CALL_STATE_IDLE:
- stopCall();//停止录音
- break;
- //接起电话
- case TelephonyManager.CALL_STATE_OFFHOOK:
- recordCall();//开始录音
- break;
- // 响铃时
- case TelephonyManager.CALL_STATE_RINGING:
- Log.e("jereh", "来电号码是:"+ incomingNumber);
- // 如果该号码属于黑名单
- if (incomingNumber.equals("123456")) {
- // 如果是黑名单,就进行屏蔽
- stopCall();
- }
- break;
- }
- }
- };
- /**
- * 停止录音
- */
- private void stopRecord(){
- if(recording){
- recorder.stop();
- recorder.release();
- recording=false;
- stopSelf();//停止服务
- }
- }
- /**
- * 电话录音
- */
- private MediaRecorder recorder;
- private boolean recording ;
- private void recordCall(){
- Log.d("jereh", "record calling")
- if( Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
- recorder=new MediaRecorder();
- recorder.setAudioSource(MediaRecorder.AudioSource.MIC);//读麦克风的声音
- recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//设置输出格式
- recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 编码方式
- File file=new File(Environment.getDownloadCacheDirectory().getAbsolutePath(),"recorder");
- if(!file.exists()){
- file.mkdir();
- }
- recorder.setOutputFile(file.getAbsolutePath() + "/"
- + System.currentTimeMillis() + "3gp");// 存放的位置是放在sd卡recorder目录下
- try {
- recorder.prepare();
- recorder.start();
- recording=true;
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- @Override
- public IBinder onBind(Intent intent) {
- throw new UnsupportedOperationException("Not yet implemented");
- }
- }
- 复制代码
- Service XML配置
- <service
- android:name=".ListenPhoneService"
- android:enabled="true"
- android:exported="true" >
- </service>
五、***别忘了一些权限的设置
- <!-- 添加访问手机电话状态的权限 -->
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <!-- 拨打电话权限 -->
- <uses-permission android:name="android.permission.CALL_PHONE" />
- <!-- 监听手机去电的权限 -->
- <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
- <!-- 在SDCard中创建与删除文件权限 -->
- <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
- <!-- 往SDCard写入数据权限 -->
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
程序员和工程师有何不同?
【大咖・来了 第7期】10月24日晚8点观看《智能导购对话机器人实践》 我刚刚工作的时候,面试官曾经跟我说:好好干两年,可以迅速从程序员成长为工程师。当时我觉得太诧异了,从很多招聘启事来看,“程序员”不就等于“工程师”吗,只是“工程师”更好听一些而已。等我工作久了,才知道“程序员”和“工程师”真的是不一样的——程序员只写程序,工程师写能在现实世界中创造价值的程序。 可惜,很多软件开发人员未必清楚两者的差别,甚至做了很久也只算程序员而不算严格意义上的工程师。所以我就自己的观察和经验,谈谈程序员和工程师的差别。 ***、工程师不写黑箱程序 “程序=数据结构+算法”,这个著名的公式大家都知道,不幸的是,它不适合描述工程领域或者现实世界的程序。有很多程序,数据结构和算法都写得很棒,功能足够强大,系统足够复杂,但是——它很难调试,一跑起来就无法停止,而且谁也不知道程序现在到底在干什么,里面发生了什么。 别觉得好笑,我遇到过很多工作三四年甚至五六年的开发人员,仍然不停地生产黑箱程序:出现问题的***反应是直接杀掉进程重启(天哪你们的程序不能安全关闭吗)。当然还有更生猛的,直接用开发机连上生产数据库...
- 下一篇
Android奇巧:ListView实现Item局部刷新
【大咖・来了 第7期】10月24日晚8点观看《智能导购对话机器人实践》 对于ListView数据的刷新大家都知道,改变Adapter的数据源,然后调用Adapter的notifyDateSetChanged()方法即可。 但是博主在做公司项目的时候,有个下载模块,因为可能同时下载好几个数据,所以用的listview展示所有正在下载的内容。因为下载进度要实时更新,所以要不停的调用notifyDateSetChanged刷新数据。这样会不停的重新绘制整个listview的界面,性能开销非常大。而且如果每个item有图片的话,每个item的图片都需要重新加载,就算图片做了内存缓存,刷新一下图片也会闪一下,不停的刷新就会导致各个item的图片不停的闪,体验一点都不好。 那么对于上面问题,有没有解决办法呢?当然是有的。我们可以针对某一个item进行局部更新,而不影响其它没有修改的item。那么具体如何实现的呢?我们看下面的代码。 1privatevoidupdateView(intitemIndex){ 2//得到***个可显示控件的位置, 3intvisiblePosition=mListVi...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- CentOS关闭SELinux安全模块
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8