AccessibilityService経由でハードキーの入力を取得する

2021/02/05
Android
ハードウェアキー
AccessibilityService

Androidアプリ開発において、ServiceなどのActivity以外でハードウェアキーの入力を取得する方法のひとつです。
ここで解説するAccessibilityService経由の方法はユーザにユーザー補助サービスの有効化をしてもらわないといけないので、いつでも使える方法ではないことに留意が必要です。

環境

  • compileSdkVersion 29
  • minSdkVersion 21

ユーザ補助サービス

Androidには通常のアプリ操作とは違う操作を可能にする、ユーザ補助サービスを独自に実装するための仕組みが提供されています。ですので、あくまで通常のアプリ操作の代替操作としてハードウェアキーを利用する場合にこの方法を利用すべきです。

AccessibilityServiceの実装

AccessibilityServiceを継承したServiceを実装します。
AccessibilityService.onKeyEventをoverrideすることでハードウェアキーの入力を検出できます。
他で稼働しているServiceで使いたい場合はLocalBroadcastManagerなどでコンポーネント間通信を実装すると良いでしょう。

class AccessibilityKeyDetectionService : AccessibilityService(){

    companion object{
        private const val TAG: String = "KeyDetectionServ"
    }

    override fun onKeyEvent(event: KeyEvent?): Boolean {

        Log.d(TAG, "EventKeycode: ${event?.keyCode}")

        if(event?.action == KeyEvent.ACTION_DOWN){
            if(event.keyCode == KeyEvent.KEYCODE_VOLUME_UP || event.keyCode == KeyEvent.KEYCODE_VOLUME_DOWN){
              //  ボリュームキーが押された
            }
        }

        return super.onKeyEvent(event)
    }

    override fun onServiceConnected() {
        //  nop
    }

    override fun onInterrupt() {
        //  nop
    }

    override fun onAccessibilityEvent(event: AccessibilityEvent?) {
        //  nop
    }
}

AccessibilityServiceの設定情報の記述

res/xml以下にxmlリソースファイルを作成します。ルートタグはaccessibility-serviceです。

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityFlags="flagRequestFilterKeyEvents"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackAllMask"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:settingsActivity=""
    android:packageNames="com.hassakulab.xxx"
    android:canRequestFilterKeyEvents="true"
    android:description="@string/accessibility_service_description"
    />

ここの設定情報はAccessibilityService.onServiceConnectedでランタイムに設定することも可能です。

Manifestへの記述

AndroidManifest.xmlにserviceを記載します。meta-dataタグのandroid:resource属性に上記のxmlを指定します。

<application>
  <!-->中略<-->
  <service android:name=".AccessibilityKeyDetectionService"
      android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
      android:label="@string/accessibnility_service_label">
      <intent-filter>
          <action android:name="android.accessibilityservice.AccessibilityService" />
      </intent-filter>
      <meta-data android:name="android.accessibilityservice"
          android:resource="@xml/accessibility_key_detection_service"
          />
  </service>
</application>

参考

© 2019-2021 hassakulab.com, built with Gatsby