android 新增滅屏手勢動畫功能
首先解釋一下這個功能,在滅屏時,在螢幕上面進行一些滑動的操作,實現一些功能,像亮屏,進入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
...
}
如果需要新增開關可以在設定裡面新增,比較簡單
到此這個功能新增完成。。。