自定义来电秀

news/2024/11/7 1:29:03/

因为公司需求,要自定义一款来电秀的app当做周边产品来配合主营的app业务。

来电秀主要功能是监听通话(包括呼出和呼入电话)来实现自己想要的界面效果,直接上代码:

首先是两个主要的类,一个是通过service服务获取监听PhoneStateListener来电消息,另一个是通过广播来监听去电消息

添加权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />

1.获取来电服务

package com.tyk.textcallphone;import java.util.Date;import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.RequestParams;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.HttpRequest.HttpMethod;
import com.tyk.textcallphone.utils.Utils;import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;/*** 获取来电号码服务*/
public class IncomingCallService extends Service {/*** 电话服务管理器*/private TelephonyManager telephonyManager;/*** 电话状态监听器*/private MyPhoneStateListener myPhoneStateListener;/*** 获取电话号码*/public String getNativePhoneNumber() {telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);String NativePhoneNumber = null;NativePhoneNumber = telephonyManager.getLine1Number();return NativePhoneNumber;}@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();// 获取来电号码getIncomingCall();}@Overridepublic void onDestroy() {super.onDestroy();// 不获取来电号码getIncomingCallCancel();}/*** 获取来电号码*/private void getIncomingCall() {// 获取电话系统服务telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);myPhoneStateListener = new MyPhoneStateListener();telephonyManager.listen(myPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);}/*** 不获取来电号码*/private void getIncomingCallCancel() {telephonyManager.listen(myPhoneStateListener, PhoneStateListener.LISTEN_NONE);}/*** 电话状态监听器*/class MyPhoneStateListener extends PhoneStateListener {@Overridepublic void onCallStateChanged(int state, String incomingNumber) {super.onCallStateChanged(state, incomingNumber);final int mystate=state;// 来电号码final String number = incomingNumber;if (MainActivity.instance != null) {MainActivity.instance.finish();}if (Utils.CheckNetworkConnection(IncomingCallService.this)) {SharedPreferences sp = getSharedPreferences("BGFA", 0);String myphonenumber = sp.getString("myphonenumber", "");RequestParams params=new RequestParams();params.addBodyParameter("serviceTel", myphonenumber);// 客服params.addBodyParameter("clinetTel", number);// 客户params.addBodyParameter("time", new Date().getTime() + "");HttpUtils httpUtils=new HttpUtils(2500);httpUtils.send(HttpMethod.POST,"http://192.168.1.201:8311/ApiControl?method=hotline.getHotlineMessage", params, new RequestCallBack<String>() {@Overridepublic void onSuccess(ResponseInfo<String> responseInfo) {// TODO Auto-generated method stubString json = responseInfo.result;String isSuccessful = Utils.getJsonString(json, "isSuccessful");if ("true".equals(isSuccessful)) {okTonghua(mystate, number, json);}else {noTonghua(mystate, number);}}@Overridepublic void onFailure(HttpException error, String msg) {// TODO Auto-generated method stubnoTonghua(mystate, number);}});} else {noTonghua(mystate, number);}}}//非正常通话public void noTonghua(int state,final String number) {switch (state) {case TelephonyManager.CALL_STATE_RINGING:if (TonghuaNoWangluoActivity.instance!=null) {TonghuaNoWangluoActivity.instance.finish();}if (TonghuaActivity.instance!=null) {TonghuaActivity.instance.finish();}if (GuaduanActivity.instance!=null) {GuaduanActivity.instance.finish();}if (number != null && number.length() != 0) {new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);laiDianActivity(IncomingCallService.this, number);}}.sendEmptyMessageDelayed(0, 2000);}break;case TelephonyManager.CALL_STATE_OFFHOOK:if (LaiDianActivity.instance!=null) {LaiDianActivity.instance.finish();}if (TonghuaActivity.instance!=null) {TonghuaActivity.instance.finish();}if (GuaduanActivity.instance!=null) {GuaduanActivity.instance.finish();}if (number != null && number.length() != 0&& !getNativePhoneNumber().equals(number)) {new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);tongHuaNoActivity(IncomingCallService.this, number);}}.sendEmptyMessageDelayed(0, 1000);}break;case TelephonyManager.CALL_STATE_IDLE:if (TonghuaNoWangluoActivity.instance!=null) {TonghuaNoWangluoActivity.instance.finish();}if (LaiDianActivity.instance!=null) {LaiDianActivity.instance.finish();}if (TonghuaActivity.instance!=null) {TonghuaActivity.instance.finish();}if (number != null && number.length() != 0&& !getNativePhoneNumber().equals(number)) {guaduanActivity(IncomingCallService.this, "", number);}break;default:break;}}//正常通话public void okTonghua(final int mystate, final String number, final String project) {switch (mystate) {// 如果电话铃响case TelephonyManager.CALL_STATE_RINGING:// Toast.makeText(IncomingCallService.this, "来电号码是:" +// incomingNumber, Toast.LENGTH_LONG).show();if (TonghuaNoWangluoActivity.instance!=null) {TonghuaNoWangluoActivity.instance.finish();}if (TonghuaActivity.instance!=null) {TonghuaActivity.instance.finish();}if (GuaduanActivity.instance!=null) {GuaduanActivity.instance.finish();}if (number != null && number.length() != 0) {new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);laiDianActivity(IncomingCallService.this, number);}}.sendEmptyMessageDelayed(0, 2000);}break;// 如果电话接通case TelephonyManager.CALL_STATE_OFFHOOK:// Toast.makeText(IncomingCallService.this, "接通号码是:" +// incomingNumber, Toast.LENGTH_LONG).show();if (TonghuaNoWangluoActivity.instance!=null) {TonghuaNoWangluoActivity.instance.finish();}if (LaiDianActivity.instance!=null) {LaiDianActivity.instance.finish();}if (GuaduanActivity.instance!=null) {GuaduanActivity.instance.finish();}if (number != null && number.length() != 0&& !getNativePhoneNumber().equals(number)) {new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);tongHuaActivity(IncomingCallService.this, project, number);}}.sendEmptyMessageDelayed(0, 1000);}break;// 如果电话挂断case TelephonyManager.CALL_STATE_IDLE:// Toast.makeText(IncomingCallService.this, "挂断号码是:" +// incomingNumber, Toast.LENGTH_LONG).show();if (TonghuaNoWangluoActivity.instance!=null) {TonghuaNoWangluoActivity.instance.finish();}if (LaiDianActivity.instance!=null) {LaiDianActivity.instance.finish();}if (TonghuaActivity.instance!=null) {TonghuaActivity.instance.finish();}if (number != null && number.length() != 0&& !getNativePhoneNumber().equals(number)) {guaduanActivity(IncomingCallService.this, project, number);}break;}}/*** 显示来电Activity* * @param ctx* @param number*/private void laiDianActivity(Context ctx, String number) {Intent intent = new Intent(ctx, LaiDianActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.putExtra("number", number);ctx.startActivity(intent);}/*** 显示通话Activity* * @param ctx* @param number*/private void tongHuaActivity(Context ctx, String project, String number) {Intent intent = new Intent(ctx, TonghuaActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.putExtra("project", project);intent.putExtra("number", number);ctx.startActivity(intent);}/*** 显示无网络通话Activity* * @param ctx* @param number*/private void tongHuaNoActivity(Context ctx, String number) {Intent intent = new Intent(ctx, TonghuaNoWangluoActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.putExtra("number", number);ctx.startActivity(intent);}/*** 显示备注Activity* * @param ctx* @param number*/private void guaduanActivity(Context ctx, String project, String number) {Intent intent = new Intent(ctx, GuaduanActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.putExtra("project", project);intent.putExtra("number", number);ctx.startActivity(intent);}
}


2.获取去电服务

package com.tyk.textcallphone;import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.widget.Toast;/*** 获取去电号码服务*/
public class OutgoingCallService extends Service {/*** 去电 Action*/private static final String OUTGOING_ACTION = "android.intent.action.NEW_OUTGOING_CALL";/*** 去电广播接收器*/private MyPhoneStateReceiver myPhoneStateReceiver;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();// 获取去电号码getOutgoingCall();}@Overridepublic void onDestroy() {super.onDestroy();// 不获取去电号码getOutgoingCallCancel();}/*** 获取去电号码*/private void getOutgoingCall() {IntentFilter intentFilter = new IntentFilter();// 监听去电广播intentFilter.addAction(OUTGOING_ACTION);myPhoneStateReceiver = new MyPhoneStateReceiver();// 动态注册去电广播接收器registerReceiver(myPhoneStateReceiver, intentFilter);}/*** 不获取去电号码*/private void getOutgoingCallCancel() {// 取消注册去电广播接收器unregisterReceiver(myPhoneStateReceiver);}/*** 监听去电广播*/class MyPhoneStateReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// 获取去电号码String outgoingNumber = getResultData();Toast.makeText(context, "去电号码是:" + outgoingNumber, Toast.LENGTH_LONG).show();}}
}

3.挂断电话和接听电话

因为android4.0以上版本把接听电话事件设置为系统权限,所以原来接听电话的方法已经不管用了,但是挂断电话的方法还是好使的

因为系统挂断电话的方法需要ITelephony这个类里的方法,但是这个方法是系统私有的,不能直接调用,所以在自己的工程里创建一个ITelephony.aidl文件(直接上网下载一个就好),放到com.android.internal.telephony这个包下(自己创建一个包)。ITelephony需要依赖NeighboringCellInfo这个类,同样的方式创建一个NeighboringCellInfo.aidl文件(网上下载),放到android.telephony这个包下(自己创建一个包)。

准备工作做好了

接下来就是挂断电话功能:

/*** 挂断电话*/public static synchronized void endCall(Context ctx) {TelephonyManager mTelMgr = (TelephonyManager) ctx.getSystemService(Service.TELEPHONY_SERVICE);Class<TelephonyManager> c = TelephonyManager.class;try {Method getITelephonyMethod = c.getDeclaredMethod("getITelephony", (Class[]) null);getITelephonyMethod.setAccessible(true);ITelephony iTelephony = null;System.out.println("End call.");iTelephony = (ITelephony) getITelephonyMethod.invoke(mTelMgr, (Object[]) null);iTelephony.endCall();} catch (Exception e) {e.printStackTrace();System.out.println("Fail to answer ring call.");}}
直接调用这个方法即可,也可以自己依照源码深入研究一下,这里就不做说明


接下来就是接听电话功能,因为android4.0以上版本把接听电话事件设置为系统权限,但是4.0以上版本有个方法,那就是可以通过耳机来接听电话的方法没有设置为系统权限(不知道算不算是一个bug)。所以可以模拟耳机接听电话的方式来接通电话,代码如下(亲测有效):

/*** 接听电话*/public static synchronized void answerCall(Context ctx) {try {Runtime.getRuntime().exec("input keyevent " + Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK));} catch (IOException e) {String enforcedPerm = "android.permission.CALL_PRIVILEGED";Intent btnDown = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra(Intent.EXTRA_KEY_EVENT,new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK));Intent btnUp = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra(Intent.EXTRA_KEY_EVENT,new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));ctx.sendOrderedBroadcast(btnDown, enforcedPerm);ctx.sendOrderedBroadcast(btnUp, enforcedPerm);}}


4.开启免提功能,电话接通的界面都会有免提的功能,具体实现方式如下:

添加权限:<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

/*** 打开扬声器*/public static void openSpeaker(Context context) {try {AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);audioManager.setMode(AudioManager.ROUTE_SPEAKER);currVolume = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);if (!audioManager.isSpeakerphoneOn()) {// setSpeakerphoneOn() only work when audio mode set to// MODE_IN_CALL.audioManager.setMode(AudioManager.MODE_IN_CALL);audioManager.setSpeakerphoneOn(true);audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL),AudioManager.STREAM_VOICE_CALL);}} catch (Exception e) {e.printStackTrace();}}/*** 关闭扬声器*/public static void closeSpeaker(Context context) {try {AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);if (audioManager != null) {if (audioManager.isSpeakerphoneOn()) {audioManager.setSpeakerphoneOn(false);audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, currVolume,AudioManager.STREAM_VOICE_CALL);}}} catch (Exception e) {e.printStackTrace();}}

然后,就没有了,进本上就大功告成了






http://www.ppmy.cn/news/681703.html

相关文章

02 IO多路转接

多路IO转接服务器也叫做多任务IO服务器。该类服务器实现的主旨思想&#xff1a;不再由应用程序自己监视客户端连接&#xff0c;取而代之由内核替应用程序监视文件。 一. select 1. select函数介绍&#xff1a; #include <sys/select.h> /* According to earlier stan…

(转)Google Voice呼转到中国电话的五种方法

在cnbeta中看到这文章&#xff0c;感觉这个方法不错&#xff0c;只是不知道好不好用&#xff0c;没试过&#xff0c;等这几天忙完了再试一下。原文地址是&#xff1a; http://quanda.info/6.html Google Voice的最亮点是 美国本地的电话号码无限美国本地通话全球免费短信&#…

转:用调制解调器打电话收传真-ModemFax

转&#xff1a;http://aminghome.blogspot.com/2007/09/modem.html 翻东西的时候&#xff0c;偶尔发现一只以前的56k的老猫--E56k v90 Modem。在宽带普及的今天&#xff0c;昔日用模拟信号拨号上网的日子已经一去不复返了。今天要挖掘一下Modem&#xff1a;将之变化出三种功能&…

信捷plc使用modbus RTU和变频器通讯

信捷plc使用modbus rtu和信捷变频器通讯 0.1:要求:plc和变频器都支持modbusRTU的 1:modbus和rs485的区别 modbus是一种串行通讯协议&#xff0c;而rs485是硬件接口&#xff0c;大多数的modbus都是通过串口485进行的&#xff0c;485又分全双工和半双工&#xff0c;区别是全双工是…

Linux网络:多路转接

高级IO 1. IO的相关概念 内存和外设进行沟通的动作叫做IO。在网络层面&#xff0c;数据往网络里写的本质是将数据从内存拷贝到网卡上&#xff0c;从网络里读的本质是将数据从网卡拷贝到内存中。 当程序运行到IO函数时一般都在阻塞式等待&#xff0c;这也算作IO过程中的一个环…

FX5U与台达变频器ModBus通讯

1、接线&#xff1a; 2、台达变频器参数设置&#xff1a;首先进行格式化 3、地址介绍 3、PLC设置&#xff1a; 4、程序&#xff1a; 参考视频&#xff1a;https://v.youku.com/v_show/id_XNDE5NTc3MTc3Mg%3D

这几款软件可以在线视频转音频

对于从事视频剪辑行业的小伙伴来说&#xff0c;常常需要将视频转换为音频文件。特别是影视剧对话配音或者是音乐视频MV都需要转为音频文件的形式储存。那么你们知道视频转音频软件哪个好用&#xff1f;下面我就来跟大家分享几个还不错的转换软件给你们&#xff0c;大家可千万别…

sprd9820 来电归属地

一、来电归属地没有出来 sprd\packages\apps\InCallUI\src\com\sprd\incallui\geocode\GeocodeHelper.java private static final String KEY "ro.device.support.geocode"; private static final boolean SUPPORT_SPRD_GROCODE SystemProperties.getBoolean(KEY,…