1. 程式人生 > >探討Android實現後臺(Service)按鍵監聽的功能

探討Android實現後臺(Service)按鍵監聽的功能

一般來說需要做這個功能的大多數是機頂盒或者智慧電視,也就是AndroidTv。剛好這兩天公司的機頂盒有這麼一個需求,針對遙控器某些特殊按鍵,實現按鍵的監聽,並實現相應的功能。研究了一下,大概有這麼一些辦法。
  第一種辦法是廣播,一般來說系統對於音量鍵和Home鍵會發送廣播,我們可以再廣播中監聽這些按鍵資訊。具體的IntentFilter怎麼寫,大家可以百度一下。
  第二種辦法仍然是廣播,不過這就需要修改SDK了,在WindManagerService裡面,分發按鍵事件的時候的傳送特殊的廣播的,這個改動可能比較麻煩。
  第三種辦法是直接讀取輸入裝置檔案,一般該檔案位於/dev/input/資料夾下面,不過裡面一般有多個檔案,具體哪個檔案描述的哪一個輸入裝置,需要大家進行嘗試。裝置的檔案的讀取需要使用c或者c++來完成。具體的實現程式碼可以參考:

https://github.com/radhoo/android-event-injector。這種辦法需要有root許可權才行,而且讀取的鍵值是沒有做過轉換的,也就是說和我們平常使用的鍵值是不一樣的。其實大家可以在adb shell中,通過getevent檢視。
  第四種辦法是使用系統的無障礙服務,也就是AccessibilityService。我最終採用的方式就是這個,因為這個不僅可以監聽按鍵,還能攔截。關於AccessibilityService的實現,網上講的比較多了。我這裡只提幾個需要注意的點:
  1、按鍵攔截需要覆寫onKeyEvent方法
  2、AndroidManifest.xml檔案中配置如下:

<service
    android:name="your service name"
    android:enabled="true"
    android:exported="true"
    android:permission=
                    "android.permission.BIND_ACCESSIBILITY_SERVICE" >
    <intent-filter>
        <action android:name=
        "android.accessibilityservice.AccessibilityService
" />
</intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /> </service>

  3、在res下面建立一個xml資料夾,然後新增一個xml用於AndroidMenifest引用,xml檔案這樣寫(android:accessibilityFlags不能使用預設的,android:canRequestFilterKeyEvents必須為true,預設的是false): 

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagRequestFilterKeyEvents"
    android:canRetrieveWindowContent="true"
    android:canRequestFilterKeyEvents="true"
    android:description="@string/app_name">
</accessibility-service>

  4、這種方法有個缺陷,該服務是需要使用者手動開啟的。不過因為我是做自己公司的盒子,所以我可以輕鬆的成為系統應用,然後自己開啟這個服務。開啟方法如下:

//注意 這裡可能為空(也就是如果當前沒有任何一個無障礙服務被授權的時候 就為空了  感謝評論裡面指出bug的同學)
String enabledServicesSetting = Settings.Secure.getString(
                getContentResolver(),               Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);

        ComponentName selfComponentName = new ComponentName(getPackageName(),
                "Your AccessibilityService Class Name");
        String flattenToString = selfComponentName.flattenToString();
        if (enabledServicesSetting==null||
            !enabledServicesSetting.contains(flattenToString)) {
            enabledServicesSetting += flattenToString;
        }
        Settings.Secure.putString(getContentResolver(),
                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
                enabledServicesSetting);
        Settings.Secure.putInt(getContentResolver(),
                Settings.Secure.ACCESSIBILITY_ENABLED, 1);