这两天在为项目下一版本的功能做准备,刚好有一个功能是自定义来电界面,目的是显示更多的自定义信息。作为新手的我,就开始上网找啊找,看啊看,刚开始的思路是:监听来电广播——弹出自定义的activity界面——点击自定义界面的接听按钮或者挂断按钮。然后问题就来了:1.不能屏蔽系统默认的来电界面。2.接听和挂断的权限在不同手机有不同的结果。
解决办法:1.实现来电界面可以用弹出activity的方式,全屏弹窗的方式和半屏弹窗的方式。而弹出activity和全屏弹窗的方式都需要面临自定义接听和挂断按钮的问题。如果是半屏弹窗的话就只需要显示自定义的内容,然后可是使用系统自带界面的接听和挂断按钮进行通话。
一.监听来电广播:
新建一个继承BroadcastReceiver的类PhoneStateReceiver
package com.example.telephone;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class PhoneStateReceiver extends BroadcastReceiver {
private Context context;
private TextView txNumber;
private RelativeLayout mFloatLayout;//定义悬浮窗口布局
private WindowManager.LayoutParams wmParams;
private WindowManager mWindowManager;//创建悬浮窗口设置布局参数的对象
private boolean firstNew = false;//判断弹窗是否已经显示
@Override
public void onReceive(Context context, Intent intent) {
this.context = context;
if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){
//监听拨打电话
}
else{
//监听接听电话
TelephonyManager phoneManager = (TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
phoneManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
/**
* 监听手机来电状态
*/
PhoneStateListener listener=new PhoneStateListener(){
@Override
public void onCallStateChanged(int state, final String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch(state){
case TelephonyManager.CALL_STATE_IDLE://电话挂断状态
Intent i = new Intent();
i.setAction("com.likebamboo.phoneshow.ACTION_END_CALL");//发送电话处于挂断状态的广播
context.sendBroadcast(i);
popPhoneRemove();//关闭来电悬浮窗界面
break;
case TelephonyManager.CALL_STATE_OFFHOOK://电话接听状态
break;
case TelephonyManager.CALL_STATE_RINGING://电话铃响状态
telRinging(incomingNumber);//打开来电悬浮窗界面,传递来电号码
break;
default:
break;
}
}
};
/**
* 打开来电悬浮窗界面
* @param number
*/
private void telRinging(final String number){
if(!firstNew){
//第一次启动悬浮窗,延迟两秒后显示界面,并且把firstNew设置为true
firstNew = true;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
popPhone(number);
}
}, 2000);
}
else{
//如果悬浮窗已经显示
}
}
/**
* 悬浮窗的具体实现
* @param phone
*/
private void popPhone(String phone) {
wmParams = new WindowManager.LayoutParams();
wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;//定义WindowManager.LayoutParams类型,TYPE_SYSTEM_ERROR为系统内部错误提示,显示于所有内容之上
mWindowManager = (WindowManager)context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);//系统服务,注意这里必须加getApplicationContext(),否则无法把悬浮窗显示在最上层
wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; //不能抢占聚焦点
wmParams.flags = wmParams.flags | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
wmParams.flags = wmParams.flags | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; //排版不受限制
wmParams.width = WindowManager.LayoutParams.MATCH_PARENT;
wmParams.height = getWindowHeight()/2;//屏幕的一半高度
wmParams.gravity = Gravity.TOP;//居上显示
LayoutInflater inflater = LayoutInflater.from(context);
mFloatLayout = (RelativeLayout) inflater.inflate(R.layout.activity_main, null);//获取浮动窗口视图所在布局
txNumber = (TextView)mFloatLayout.findViewById(R.id.txNumber);
txNumber.setText(phone);
mWindowManager.addView(mFloatLayout, wmParams); //创建View
}
/**
* 移除悬浮窗
*/
private void popPhoneRemove(){
if(mFloatLayout != null)
{
mWindowManager.removeView(mFloatLayout);
firstNew = false;
}
mFloatLayout=null;//必须加入此语句,否则会windowManager会找不到view
}
/**
* 获取屏幕高度
* @return
*/
private int getWindowHeight(){
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);//系统服务
DisplayMetrics metric = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metric);
return metric.heightPixels; // 屏幕高度(像素)
}
}
二.接听电话和挂断电话:
先要添加ITelephony.aidl文件
/**
* 接听电话
* @return
*/
private void answerCall(){
TelephonyManager telManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
Class<TelephonyManager> c = TelephonyManager.class;
try {
Method getTelMethod = c.getDeclaredMethod("getITelephony", (Class[])null);
getTelMethod.setAccessible(true);
ITelephony iTelephony = null;
iTelephony = (ITelephony)getTelMethod.invoke(telManager, (Object[])null);
iTelephony.answerRingingCall();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 挂断电话
*/
public void endCall() {
TelephonyManager mTelMgr = (TelephonyManager)getSystemService(Service.TELEPHONY_SERVICE);
Class<TelephonyManager> c = TelephonyManager.class;
try {
Method getITelephonyMethod = c.getDeclaredMethod("getITelephony", (Class[])null);
getITelephonyMethod.setAccessible(true);
ITelephony iTelephony = null;
iTelephony = (ITelephony)getITelephonyMethod.invoke(mTelMgr, (Object[])null);
iTelephony.endCall();
} catch (Exception e) {
e.printStackTrace();
System.out.println("Fail to answer ring call.");
}
}
/**
* 电话挂断广播接收器,接收在PhoneStateReceiver发送过来的广播,只是为了挂断后进行关闭来电界面
*/
public BroadcastReceiver mEndCallReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (intent != null && intent.getAction().equals("com.likebamboo.phoneshow.ACTION_END_CALL")) {
finish();
}
}
};
三.添加监听来电状态的广播:
有两种方法,第一种是在AndroidManifest.xml里注册,这里注册的话 如果程序退出了还能监听到来电。
<!-- 注册监听手机状态 -->
<receiver android:name="com.likebamboo.phoneshow.PhoneStateReceiver" >
<intent-filter android:priority="1000" >
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<!-- 挂断手机的权限 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!-- 接电话的权限 -->
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<!-- 读取手机状态的权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 系统级弹窗权限 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
第二种是在activity里注册,这样的话如果程序退出能手动关闭监听。
public class MainActivity extends Activity {
private PhoneStateReceiver phoneReceiver = new PhoneStateReceiver();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//注册广播
IntentFilter filter = new IntentFilter();
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.setPriority(Integer.MAX_VALUE);
registerReceiver(phoneReceiver, filter);
}
/**
* 注销广播
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK){
getApplication().onTerminate();
android.os.Process.killProcess(android.os.Process.myPid());
unregisterReceiver(phoneReceiver);//注销广播
return true;
}
return super.onKeyDown(keyCode, event);
}
}