这两天在为项目下一版本的功能做准备,刚好有一个功能是自定义来电界面,目的是显示更多的自定义信息。作为新手的我,就开始上网找啊找,看啊看,刚开始的思路是:监听来电广播——弹出自定义的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); } }