自己琢磨了很久,也查了很多资料。
这是资源下载地址:点击打开链接,大家可以去下载
首先我没有使用BroadcastReceiver,因为在使用广播监听来去点的时候手机会发送多次广播,所以接受并处理会非常麻烦与危险。虽然可以解决来电,但是去电的时候发现并没有相关api,因为android将其隐藏了,CallManager应该是这个类,虽然没有试过。但是在去电结束后又会被来电的监听器接受到挂断的信息,于是又是一个问题。所以我抛弃了BroadcastReceiver来监听来去电的方法。
BroadcastReceiver不行,那就使用Service来处理。
TelephonyManager tm = (TelephonyManager) getSystemService(Service.TELEPHONY_SERVICE);
PhoneStateListener customPhoneListener = new Listener(this);
// 监听跳转
tm.listen(customPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
这是部分代码,放在 Service的onCreate()的方法中运行,因为该方法在创建Service的时候只会运行一次。
public class Listener extends PhoneStateListener implements OnTouchListener {
private Context context;
// 自定义窗口
private View view;
private WindowManager windowManager;
public Listener(Context context2) {
this.context = context2;
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
// 来电监听
case TelephonyManager.CALL_STATE_RINGING:
createWindow(incomingNumber);
break;
// 来电/去电挂断
case TelephonyManager.CALL_STATE_IDLE:
if (view != null && view.isShown()) {
closeWindow();
}
break;
// 来电通话或者去电等待+通话
case TelephonyManager.CALL_STATE_OFFHOOK:
if (view != null && view.isShown()) {
closeWindow();
} else {
createWindow(incomingNumber);
}
break;
}
super.onCallStateChanged(state, incomingNumber);
}
// 窗口点击事件
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (view != null && view.isShown()) {
windowManager.removeView(view);
}
break;
}
return false;
}
// 创建窗口
public void createWindow(String phoneNumber) {
// 建立新窗口来显示对应信息
windowManager = (WindowManager) context.getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
// 定义窗口布局
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
view = LayoutInflater.from(context).inflate(
R.layout.activity_call, null);
TextView numberTextView = (TextView) view
.findViewById(R.id.phone_number);
TextView numberAddress = (TextView) view
.findViewById(R.id.telephone_address);
TextView numberDepartment = (TextView) view
.findViewById(R.id.phone_department);
TextView numberJob = (TextView) view
.findViewById(R.id.phone_job);
// 设置窗口在所有窗口之上
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
| WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
// 图片置顶
params.gravity = Gravity.LEFT | Gravity.TOP;
params.x = 0;
params.y = 0;
params.height = 1000;
// 得到电话号码
numberTextView.setText(phoneNumber);
// 查询电话号码,并得到联系人姓名
// numberAddress.setText(PhoneInformation.getPhoneName(context, phoneNumber));
// 查询自定义数据库
UserInfo userInfo = DBUtils.getInstance(context).selectInfo(phoneNumber);
if (userInfo != null) {
numberAddress.setText(userInfo.getName());
numberDepartment.setText(userInfo.getDepartment());
numberJob.setText(userInfo.getJob());
}
// 给当前view增加监听事件
view.setOnTouchListener(this);
// 添加自定义图片
windowManager.addView(view, params);
}
// 关闭窗口
public void closeWindow() {
windowManager.removeView(view);
}
}
这是电话监听器的所有代码在这里我使用了WindowManager来显示一个小窗口,窗口的代码也在上面注释了。在这里用了代码复用也是很规范(自恋)。
state是电话的状态,incomingNumber是电话号码。如果有问题可以打Log日志自己慢慢打电话试一试。
其中有几段代码是查询联系人相关信息的稍后再贴。
最后不能忘了要在清单文件中注册,增加权限,以及在主函数中打开/关闭Service。