因为公司需求,要自定义一款来电秀的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();}}
然后,就没有了,进本上就大功告成了