1. 程式人生 > >android 新增滅屏手勢動畫功能

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
    ...
}

如果需要新增開關可以在設定裡面新增,比較簡單

          

到此這個功能新增完成。。。