Edited at

User Driverを使って、電子部品とAndroid Frameworkをつなぐ

More than 1 year has passed since last update.

AndroidThingsでは、デバイスごとにつけているセンサーやGPS、周辺機器が異なるため、一部のAndroid Frameworkで利用できる機能がデフォルトでは使えなくなっています。

例えばGPSはRaspberry Piには乗っていないため、GPSに関連する機能はデフォルトでは使えません。

ただし、電子部品として追加する分にはGPS等をつけることは可能です。

この時、追加したGPSや温度センサー等をAndroid Frameworkで利用できるようにするのがUser Driverです。

※ドキュメントだと、User-Space Drivers、User Driversと若干表記ゆれがある気がします.

https://developer.android.com/things/sdk/drivers/index.html


User Driverのメリット

主にUser Driverのメリットには以下があります。


  • 移植性

  • 再利用性

  • 統合

色々メリットはありますが、単純に「様々な周辺機器ラップしてAndroid Framework上から触れたほうが、既存のコードやライブラリも使えるし、移植性も高いでしょ」という感じでイメージすればいいと思います。


User Driverの種類

主に3種類あります。


  • GPS


    • GPSです。AndroidのLocation Serviceと統合できます。



  • HID - Human Interface Devices


    • ユーザの入力を扱うDriverです。AndroidのKey EventsやMotion Events(Touchとか)を統合することが出来ます。

    • 例えば物理ボタンとKey Eventsを紐付けたり出来ます。



  • Sensor


    • センサーです。 AndroidのSensorManagerと統合できます。

    • PIOで追加した様々なセンサーをAndroid Framework上(SensorManager)経由で扱う事ができるようになります。




User Driverを試してみる

とりあえず一番簡単なボタンのUser Driverを試してみます。めんどくさいので公式のsample-buttonをそのまま使います。


ハードウェア構成

以下です。

userdriver.png


コード

一応kotlinにして、いらないところやコメントを追加してあります。


MainActivity.kt

package com.github.soundtricker.androidthings.samleuserdriver

import android.app.Activity
import android.os.Bundle
import java.io.IOException
import android.util.Log
import android.view.KeyEvent
import com.google.android.things.contrib.driver.button.Button
import com.google.android.things.contrib.driver.button.ButtonInputDriver
import com.google.android.things.pio.Gpio
import com.google.android.things.pio.PeripheralManagerService

class MainActivity : Activity() {

companion object {
private val TAG = MainActivity::class.java.simpleName
private val GPIO_BUTTON_PIN_NAME= "BCM21"
private val GPIO_LED_PIN_NAME = "BCM6"
}

private var mButtonInputDriver: ButtonInputDriver? = null
private var mLedGpio: Gpio? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupButton()
setupLed()
}

override fun onDestroy() {
super.onDestroy()
destroyButton()
destroyLed()
}

private fun setupButton() {
try {
mButtonInputDriver = ButtonInputDriver(GPIO_BUTTON_PIN_NAME,
Button.LogicState.PRESSED_WHEN_LOW,
KeyEvent.KEYCODE_SPACE
)
mButtonInputDriver!!.register()
} catch (e: IOException) {
Log.e(TAG, "failed initialize button driver", e)
return
}
}
private fun setupLed() {
try {
val pioSerivce = PeripheralManagerService()
mLedGpio = pioSerivce.openGpio(GPIO_LED_PIN_NAME)
} catch (e: IOException) {
Log.e(TAG, "failed initialize led", e)
return
}
}

override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (keyCode == KeyEvent.KEYCODE_SPACE) {
// Turn on the LED
setLedValue(true)
return true
}

return super.onKeyDown(keyCode, event)
}

override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
if (keyCode == KeyEvent.KEYCODE_SPACE) {
// Turn off the LED
setLedValue(false)
return true
}

return super.onKeyUp(keyCode, event)
}

private fun setLedValue(value: Boolean) {
try {
mLedGpio!!.value = value
} catch (e: IOException) {
Log.e(TAG, "Error updating GPIO value", e)
}

}

private fun destroyButton() {
Log.i(TAG, "Closing button")
mButtonInputDriver?.unregister()
try {
mButtonInputDriver?.close()
} catch (e: IOException) {
Log.e(TAG, "Error closing Button driver", e)
} finally {
mButtonInputDriver = null
}

}
private fun destroyLed() {
try {
mLedGpio!!.close()
} catch (e: IOException) {
Log.e(TAG, "Error closing LED", e)
} finally {
mLedGpio = null
}
}}


上の

mButtonInputDriver = ButtonInputDriver(GPIO_BUTTON_PIN_NAME,

Button.LogicState.PRESSED_WHEN_LOW,
KeyEvent.KEYCODE_SPACE
)
mButtonInputDriver!!.register()

部分がAndroid FrameworkにUser Driverを登録している部分です。

Android FrameworkとしてUser Driverを登録することで以下のように物理Buttonの押し離しをKey Eventとして、扱う事ができるようになります。

    override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {

if (keyCode == KeyEvent.KEYCODE_SPACE) {
// Turn on the LED
setLedValue(true)
return true
}

return super.onKeyDown(keyCode, event)
}

override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
if (keyCode == KeyEvent.KEYCODE_SPACE) {
// Turn off the LED
setLedValue(false)
return true
}

return super.onKeyUp(keyCode, event)
}

なお、上記コードを動かすためには、AndroidManifest.xmlに以下を追加する必要があります。


AndroidManifest.xml

<uses-permission android:name="com.google.android.things.permission.MANAGE_INPUT_DRIVERS" />



まとめ

User Driverによって、Androidらくしセンサーなどを扱えるのはAndroid Thingsのメリットだと思います。

多分