首先解释一下这个功能,在灭屏时,在屏幕上面进行一些滑动的操作,实现一些功能,像亮屏,进入apk。
还是直接上图吧,看的清楚点。
下面来说下实现这个的思路。这个功能需要驱动上报键值,比如说我在屏幕上画了一个V,驱动就要向上面上报一个事件,所有的上报事件都在PhoneWindowManager.java里面处理。
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
...
// add by jueme for gesture wakeup at 20180926
//C
case KeyEvent.KEYCODE_C: {//gesture_c_key_value
if (1 == gesture_switch) {
isWakeKey = true;
SystemProperties.set("persist.sys.gesture.anim", "15");
SystemProperties.set("service.bootanim.exit", "0");
SystemProperties.set("ctl.start", "bootanim");
mHandler.sendEmptyMessageDelayed(MSG_GESTURE_C, 6000);
HandlerDissmisskeyguardLw();
}
break;
}
//E
case KeyEvent.KEYCODE_E: {
if (1 == gesture_switch) {
isWakeKey = true;
SystemProperties.set("persist.sys.gesture.anim", "16");
SystemProperties.set("service.bootanim.exit", "0");
SystemProperties.set("ctl.start", "bootanim");
mHandler.sendEmptyMessageDelayed(MSG_GESTURE_E, 6000);
HandlerDissmisskeyguardLw();
}
break;
}
//M
case KeyEvent.KEYCODE_M: {
if (1 == gesture_switch) {
isWakeKey = true;
SystemProperties.set("persist.sys.gesture.anim", "18");
SystemProperties.set("service.bootanim.exit", "0");
SystemProperties.set("ctl.start", "bootanim");
mHandler.sendEmptyMessageDelayed(MSG_GESTURE_M, 6000);
HandlerDissmisskeyguardLw();
}
break;
}
//O
case KeyEvent.KEYCODE_O: {
if (1 == gesture_switch) {
isWakeKey = true;
SystemProperties.set("persist.sys.gesture.anim", "19");
SystemProperties.set("service.bootanim.exit", "0");
SystemProperties.set("ctl.start", "bootanim");
mHandler.sendEmptyMessageDelayed(MSG_GESTURE_O, 6000);
HandlerDissmisskeyguardLw();
}
break;
}
//?
case KeyEvent.KEYCODE_BUTTON_5: {
break;
}
//V
case KeyEvent.KEYCODE_V: {
if (1 == gesture_switch) {
isWakeKey = true;
SystemProperties.set("persist.sys.gesture.anim", "17");
SystemProperties.set("service.bootanim.exit", "0");
SystemProperties.set("ctl.start", "bootanim");
mHandler.sendEmptyMessageDelayed(MSG_GESTURE_V, 6000);
HandlerDissmisskeyguardLw();
}
break;
}
//W
case KeyEvent.KEYCODE_W: {
if (1 == gesture_switch) {
isWakeKey = true;
SystemProperties.set("persist.sys.gesture.anim", "20");
SystemProperties.set("service.bootanim.exit", "0");
SystemProperties.set("ctl.start", "bootanim");
mHandler.sendEmptyMessageDelayed(MSG_GESTURE_W, 6000);
HandlerDissmisskeyguardLw();
}
break;
}
//UP
case KeyEvent.KEYCODE_DPAD_UP: {
Log.e(TAG, "gesture_switch=" + gesture_switch + ", gesture_up=" + gesture_up);
if (1 == gesture_switch && 1 == gesture_up) {
isWakeKey = true;
HandlerDissmisskeyguardLw();
}
break;
}
//DOWN
case KeyEvent.KEYCODE_DPAD_DOWN: {
if (1 == gesture_switch && 1 == gesture_music&&down) {
controlMusic(event, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
}
break;
}
//LEFT
case KeyEvent.KEYCODE_DPAD_LEFT: {
if (1 == gesture_switch && 1 == gesture_left&&down) {
controlMusic(event, KeyEvent.KEYCODE_MEDIA_PREVIOUS);
}
break;
}
//RIGHT
case KeyEvent.KEYCODE_DPAD_RIGHT: {
if (1 == gesture_switch && 1 == gesture_right&&down) {
controlMusic(event, KeyEvent.KEYCODE_MEDIA_NEXT); // -- NEXTSONG
}
break;
}
//DOUBLE
case KeyEvent.KEYCODE_U: {
if (1 == gesture_switch && 1 == gesture_doubletap) {
isWakeKey = true;
}
break;
}
//add end
...
}
我这个项目加了几个字母,上下左右滑动,双击的事件。我是在8.0上面添加的,不同版本的代码,这一块的处理都差不多,
isWakeKey = true //把这个设置为true屏幕才会亮
这个是屏幕解锁的代码HandlerDissmisskeyguardLw
private void HandlerDissmisskeyguardLw(){
mHandler.postDelayed((new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
if(isKeyguardLocked()){
dismissKeyguardLw(myIKeyguardDismissCallback);
}
}}), 50);
}
在7.0的代码不需要传这个回调myIKeyguardDismissCallback,在8.0在dismissKeyguardLw里面把myIKeyguardDismissCallback=callback;
@Override
public void dismissKeyguardLw(IKeyguardDismissCallback callback) {
...
myIKeyguardDismissCallback = callback;
...
}
到此,接收到手势并且亮屏解锁的代码已完成。
下面是动画的处理,这里遇到的坑比较多。首先说一下属性动画,实现方式是画一个黑色的背景,然后画一个点,让这个点沿着固定的轨迹运动。这里有两个问题第一,关于轨迹的的坐标不知道如何做;第二不能全屏,想着用悬浮窗盖在最上层,然后在悬浮窗里面实现动画,但是悬浮窗不能遮盖虚拟按键。接着是帧动画,这种实现方式也是不能全屏,而且播放帧动画消耗的资源太多。接下来就是我最终选用的方式了,走系统的开机流程,在开机的时候会播放开机动画,可以利用这个。
调用系统的开机动画很简单,只需要
SystemProperties.set("service.bootanim.exit", "0");
SystemProperties.set("ctl.start", "bootanim");
注意在播放完了后要重新调用
SystemProperties.set("service.bootanim.exit", "1");
否则就会一直在开机界面不能进入系统。
这里做了一个延时发送,就是为了播放完后再退出播放动画
mHandler.sendEmptyMessageDelayed(MSG_GESTURE_C, 6000);
private class PolicyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
...
case MSG_GESTURE_C:
intent.setClassName(gesture_c_key_value, gesture_c_key_value2);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
SystemProperties.set("service.bootanim.exit", "1");
SystemProperties.set("persist.sys.gesture.anim", "0");
break;
case MSG_GESTURE_E:
intent.setClassName(gesture_e_key_value, gesture_e_key_value2);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
SystemProperties.set("service.bootanim.exit", "1");
SystemProperties.set("persist.sys.gesture.anim", "0");
break;
case MSG_GESTURE_V:
intent.setClassName(gesture_v_key_value, gesture_v_key_value2);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
SystemProperties.set("service.bootanim.exit", "1");
SystemProperties.set("persist.sys.gesture.anim", "0");
break;
case MSG_GESTURE_M:
intent.setClassName(gesture_m_key_value, gesture_m_key_value2);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
SystemProperties.set("service.bootanim.exit", "1");
SystemProperties.set("persist.sys.gesture.anim", "0");
break;
case MSG_GESTURE_O:
intent.setClassName(gesture_o_key_value, gesture_o_key_value2);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
SystemProperties.set("service.bootanim.exit", "1");
SystemProperties.set("persist.sys.gesture.anim", "0");
break;
case MSG_GESTURE_W:
intent.setClassName(gesture_w_key_value, gesture_w_key_value2);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
SystemProperties.set("service.bootanim.exit", "1");
SystemProperties.set("persist.sys.gesture.anim", "0");
break;
// add end
}
}
这个persist.sys.gesture.anim属性是用来控制当前播放什么动画。
同时还需要修改BootAnimation.cpp文件
status_t BootAnimation::readyToRun() {
...
//add by jueme for gesture wakeup
char gesture_anim[PROPERTY_VALUE_MAX];
property_get("persist.sys.gesture.anim", gesture_anim, "0");
switch (atoi(gesture_anim)) {
case 11:
SYSTEM_BOOTANIMATION_FILE = "/system/media/gesture_up.zip";
break;
case 12:
SYSTEM_BOOTANIMATION_FILE = "/system/media/gesture_right.zip";
break;
case 13:
SYSTEM_BOOTANIMATION_FILE = "/system/media/gesture_left.zip";
break;
case 14:
SYSTEM_BOOTANIMATION_FILE = "/system/media/gesture_down.zip";
break;
case 15:
SYSTEM_BOOTANIMATION_FILE = "/system/media/gesture_c.zip";
break;
case 16:
SYSTEM_BOOTANIMATION_FILE = "/system/media/gesture_e.zip";
break;
case 17:
SYSTEM_BOOTANIMATION_FILE = "/system/media/gesture_v.zip";
break;
case 18:
SYSTEM_BOOTANIMATION_FILE = "/system/media/gesture_m.zip";
break;
case 19:
SYSTEM_BOOTANIMATION_FILE = "/system/media/gesture_o.zip";
break;
case 20:
SYSTEM_BOOTANIMATION_FILE = "/system/media/gesture_w.zip";
break;
default:
SYSTEM_BOOTANIMATION_FILE = "/system/media/bootanimation.zip";
break;
}
//add end
...
}
如果需要添加开关可以在设置里面添加,比较简单
到此这个功能添加完成。。。