首頁 > 軟體

Android O實現Framework層CENTER鍵長按功能方法

2022-08-24 14:02:28

需求

裝置有一個按鍵,我們定義為了 KEYCODE_DPAD_CENTER(23),長按 5s,實現系統自動重啟。

原理

在 Framework 層,查詢長按電源鍵關機相關邏輯,可以看到按鍵經過一堆處理之後會來到 (/frameworks/base/services/core/java/com/android/server/policy/)PhoneWindowManager.java 定義的 interceptKeyBeforeQueueing函數中,這裡還需注意另一個函數為 interceptKeyBeforeDispatching,注意區別。在按鍵按下時延時5s傳送特定訊息,在收到訊息時實現功能,在按鍵擡起時復原延時傳送的訊息。下面直接說具體做法。

新增訊息邏輯

首先定義一個屬於自己的訊息,可以看到,在 PhoneWindowManager.java 第820行附近,定義了一堆 private static final int MSG_XXXX = XX;,我們需要在最後這裡新增一個自己的 private static final int MSG_MY_REBOOT = 999; 定義為999是為了避免與現有值重複。 接下來,在 handleMessage 方法中,新增該訊息的處理:

private class PolicyHandler extends Handler {
	@Override
	public void handleMessage(Message msg) {
		switch (msg.what) {
			case MSG_ENABLE_POINTER_LOCATION:
				enablePointerLocation();
				break;
			// Add start
			case MSG_MY_REBOOT:
				mWindowManagerFuncs.reboot(false);
				break;
			// Add end ...
			// 省略若干行
		}
	}
}

這裡直接呼叫了 mWindowManagerFuncsreboot 方法,傳 false 進去,表現為不彈窗直接進入重啟過程,顯示“系統重啟中”頁面。傳 true 進去,則彈窗提示將要關機,點是關機重啟、點否取消。

新增按鍵處理

首先定義兩個函數,分別進行 KeyDown 和 KeyUp 時的處理。這兩個函數要寫在 PhoneWindowManager 類中,注意不要寫進了它的內部類裡面,其實原始碼中包含很多類似的 interceptXxxKeyDown 方法,寫到與他們並列的位置即可。

	// .....
	// Add start
	private void interceptCenterKeyDown() {
		Message msg = mHandler.obtainMessage(MSG_MY_REBOOT);
		msg.setAsynchronous(true);
		mHandler.sendMessageDelay(msg, 5000); // 5000ms = 5seconds	
	}
	private void interceptCenterKeyUp() {
		mHandler.removeMessages(MSG_MY_REBOOT);
	}
	// Add end
	private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
	// 省略若干行

呼叫按鍵處理

最後,在 interceptKeyBeforeQueueing 中新增對按鍵的攔截及處理呼叫

	@Override
	public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
		if (!mSystemBooted) {
			// If we have not yet booted, don't let key events do anything
			return 0;
		}
		final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
		// 省略若干行
		switch (keyCode) {
			case KeyEvent.KEYCODE_BACK: {
				if (down) {
					interceptBackKeyDown();
				} else {
					boolean handled = interceptBackKeyUp(event);
					// Don't pass back press to app if we've already handled it via long press
					if (handled) {
						result &= ~ACTION_PASS_TO_USER;
					}
				}
				break;
			}
			// Add start
			case KeyEvent.KEYCODE_DPAD_CENTER: {
				if (down) {
					interceptCenterKeyDown();
				} else {
					interceptCenterKeyUp();
				}
				break;
			}
			// Add end
			case KeyEvent.KEYCODE_VOLUME_DOWN:
			case KeyEvent.KEYCODE_VOLUME_UP:
			// 省略若干行
		}
	}

這裡,因為在一般情況下,我們需要把這個按鍵訊息傳送給應用層,因此這裡我們不進行 result &= ~ACTION_PASS_TO_USER 的操作。

這樣,整個長按重啟功能就實現了。

更多關於Android CENTER鍵長按功能的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com