目录
- 正文
- 第一:监听来电状态
- 第二:通过手机状态来做不同的处理
- 第三:来电秀界面的实现了
- 第四:开机自动启动
- 第五:注册这些四大组件和申请用到的一些权限
正文
简单的说下实现来电秀的大概原理流程:首先通过监听来电状态,通过拦截来电然后在窗口弹出一层系统级别的弹窗,这层弹窗即是来电秀。
先来两张效果图:
下面来说下实现,因为商用的原因,不能直接贴代码,所以在这里,会贴一些比较核心的代码,大概分为五个步骤:
第一:监听来电状态
/** | |
* 电话状态监听(来电或去电) | |
* | |
* @author Jenly | |
* | |
*/ | |
public class PhoneStateReceiver extends BroadcastReceiver { | |
public static final String PHONE_STATE = "android.intent.action.PHONE_STATE"; | |
public void onReceive(Context context, Intent intent) { | |
LogUtils.d(intent.getAction()); | |
context.startService(new Intent(context,CallShowService.class)); | |
} | |
} |
这是一个广播接收器,用来接收手机来电状态的,把接收到的状态发送给CallShowService服务来做相应的处理
第二:通过手机状态来做不同的处理
CallShowService.class是一个来电秀服务(CallShowService extends Service),里面的主要核心代码是通过监听来电状态来做出相应的处理,如:弹屏
下面是CallShowService几个比较核心的代码:
public void onCreate() { | |
super.onCreate(); | |
isRunning = true; | |
initPhoneStateListener(); | |
callShowView = CallShowView.getInstance(); | |
} | |
/** | |
* 初始化电话状态监听 | |
*/ | |
private void initPhoneStateListener(){ | |
phoneStateListener = new PhoneStateListener(){ | |
public void onCallStateChanged(int state, String incomingNumber) { | |
super.onCallStateChanged(state, incomingNumber); | |
phoneState = state; | |
if(isEnable){//启用 | |
switch (state) { | |
case TelephonyManager.CALL_STATE_IDLE://待机时(即无电话时,挂断时会调用) | |
LogUtils.d("CALL_STATE_IDLE"); | |
dismiss();//关闭来电秀 | |
break; | |
case TelephonyManager.CALL_STATE_OFFHOOK://摘机(接听) | |
LogUtils.d("CALL_STATE_OFFHOOK"); | |
callShow();//显示来电秀 | |
break; | |
case TelephonyManager.CALL_STATE_RINGING://响铃(来电) | |
LogUtils.d("CALL_STATE_RINGING"); | |
isCalling = false; | |
phoneNumber = incomingNumber; | |
LogUtils.d("incomingNumber:"+ incomingNumber);//来电号码 | |
callShow();//显示来电秀 | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
}; | |
//-------------------------- | |
telephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE); | |
//设置监听器 | |
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); | |
} | |
public int onStartCommand(Intent intent, int flags, int startId) { | |
if(intent!=null && Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())){//去电 | |
phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); | |
LogUtils.d("Calling..."+phoneNumber); | |
isCalling = true; | |
} | |
return super.onStartCommand(intent, START_STICKY, startId); | |
} |
第三:来电秀界面的实现了
CallShowView 来电秀界面 (CallShowView extends View),里面弹屏的核心代码:
private void initViews() { | |
context = getContext(); | |
windowManager = (WindowManager) context | |
.getSystemService(Context.WINDOW_SERVICE); | |
int width = windowManager.getDefaultDisplay().getWidth(); | |
int height = windowManager.getDefaultDisplay().getHeight(); | |
// ------------- | |
params = new LayoutParams(); | |
params.gravity = Gravity.LEFT | Gravity.TOP; | |
params.x =; | |
params.y =; | |
params.width = width; | |
params.height = height; | |
params.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; | |
// 设置图片格式,效果为背景透明 | |
params.format = PixelFormat.TRANSLUCENT; | |
// 设置Window flag 系统级弹框 | 覆盖表层 | |
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; | |
// 不可聚集(不让返回键) | 全屏 | 透明标状态栏 | |
params.flags = LayoutParams.FLAG_NOT_FOCUSABLE | |
| WindowManager.LayoutParams.FLAG_FULLSCREEN | |
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | |
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION | |
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN ; | |
initCalledView(); | |
} |
第四:开机自动启动
/** | |
* 自动启动 | |
* @author Jenly | |
*/ | |
public class AutoStartReceiver extends BroadcastReceiver { | |
public static final String AUTO_START_RECEIVER = "jenly.autostart_action"; | |
public void onReceive(Context context, Intent intent) { | |
LogUtils.d("AutoStartReceiver"); | |
if(!CallShowService.isRunning) | |
startCallShowService(context, intent); | |
} | |
private void startCallShowService(Context context, Intent intent) { | |
intent.setClass(context, CallShowService.class); | |
context.startService(intent); | |
} | |
} |
在CallShowService的生命周期里面需要加上一句核心的代码,保证CallShowService不被进程杀死,如下:
public void onDestroy() { | |
isRunning = false; | |
sendBroadcast(new Intent(AutoStartReceiver.AUTO_START_RECEIVER)); | |
super.onDestroy(); | |
} |
第五:注册这些四大组件和申请用到的一些权限
<!-- 电话状态接收广播 --> | |
<receiver android:name=".service.PhoneStateReceiver" > | |
<intent-filter> | |
<action android:name="android.intent.action.PHONE_STATE" /> | |
<action android:name="android.intent.action.NEW_OUTGOING_CALL" /> | |
</intent-filter> | |
</receiver> | |
<receiver android:name=".service.AutoStartReceiver" > | |
<intent-filter android:priority=""> | |
<action android:name="android.intent.action.RECEIVE_BOOT_COMPLETED" /> | |
<action android:name="android.intent.action.USER_PRESENT" /> | |
<action android:name="jenly.autostart_action" /> | |
</intent-filter> | |
</receiver> | |
<service android:name=".service.CallShowService" | |
android:enabled="true" > | |
<intent-filter android:priority="" > | |
<action android:name=".service.CallShowService" /> | |
</intent-filter> | |
</service> | |
<uses-permission android:name="android.permission.WAKE_LOCK" /> | |
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> | |
<uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" /> | |
<uses-permission android:name="android.permission.CALL_PHONE" /> | |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | |
<!-- 弹出窗口权限 --> | |
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> |
这样来电秀算是基本实现了,简单的总结一下几个重要的点:
1、手机来电状态的监听拦截、
2、来去电弹屏、
3、开机启动保证弹屏服务不被后台杀死、