LoginSignup
3

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-12-04

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

例えばGPSはRaspberry Piには乗っていないため、GPSに関連する機能はデフォルトでは使えません。
ただし、電子部品として追加する分にはGPS等をつけることは可能です。

この時、追加したGPSや温度センサー等をAndroid Frameworkで利用できるようにするのがUser Driverです。
※ドキュメントだと、User-Space Drivers、User Driversと若干表記ゆれがある気がします.

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のメリットだと思います。
多分

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3