因为公司需求,要自定义一款来电秀的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;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
// 获取来电号码
getIncomingCall();
}
@Override
public 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 {
@Override
public 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>() {
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
// TODO Auto-generated method stub
String json = responseInfo.result;
String isSuccessful = Utils.getJsonString(json, "isSuccessful");
if ("true".equals(isSuccessful)) {
okTonghua(mystate, number, json);
}else {
noTonghua(mystate, number);
}
}
@Override
public void onFailure(HttpException error, String msg) {
// TODO Auto-generated method stub
noTonghua(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() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.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() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.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() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.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() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.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;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
// 获取去电号码
getOutgoingCall();
}
@Override
public 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 {
@Override
public 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();
}
}
然后,就没有了,进本上就大功告成了