3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Android ThingsのUser Driverを理解する

Last updated at Posted at 2017-01-16

Android ThingsUser-Space Driversがいまひとつぴんとこなかったので、サンプルのsample-buttonを、ドキュメントのコード例のようにServiceで実装しながらまとめたメモ。

User Driverとして実装することの利点

ほとんどのアプリは、Peripheral I/Oを使って直接H/Wとやりとりするだけで足りるので、User Driverとして局所化し、Android Frameworkを介するまでもない。しかし、可搬性・再利用性・統合性を高めたかったらUser Driverとして実装したほうがよい、ということ。

User Driverタイプ

User Driver APIが対象としているのは、GPS、キーボードなどHuman Interface Devices(HID)センサーの3種類の入力デバイス。drivers-samplesの中のSegment display sampleが使用しているht16k33ディスプレイドライバなどの出力デバイスドライバを広義に(あるいは混同して)User Driverと呼ぶことはあるかもしれないが、少なくともAPIの対象ではない。

com.google.android.things.userdriverパッケージクラス
GpsDriver
InputDriver
InputDriver.Builder
UserDriverManager
UserSensor
UserSensor.Builder
UserSensorDriver
UserSensorReading

ただし、出力デバイスも入力デバイス同様にServiceなどに隠蔽して疎結合とし、可搬性を高めることは可能であり、実際にサンプルのLEDドライバをService化してみた。

実装例

GPS/HID/センサーともにパターンは同じ。尚、ドキュメントのコード例はServiceを使用しているが、サンプルのcontrib-driversでは使用しておらず、必須というわけではない。前述の通りServiceを使用したほうが若干結合度が弱いと思うが、このあたりはケースバイケースで使い分ければよいだろう。

User Driver側

といっても、往々にしてアプリと同梱なので、アプリ下位側とでもいうべきか。

  1. 開始時にドライバを生成し、UserDriverManagerに登録する。
  • GPSは、GpsDriverを生成し登録する。
    private GpsDriver mDriver;
...
    mDriver = new GpsDriver();
    UserDriverManager.getManager().registerGpsDriver(mDriver);
  • HIDは、ビルダーを使ってInputDriverを生成し、登録する。
    private InputDriver mDriver;
...
    mDriver = InputDriver.builder(InputDevice.SOURCE_CLASS_BUTTON)
                .setName(DRIVER_NAME)
                .setVersion(DRIVER_VERSION)
                .setKeys(new int[] {KEY_CODE})
                .build();
    UserDriverManager.getManager().registerInputDriver(mDriver);
  • センサーは、UserSensorDriverの継承クラスインスタンスを生成し、ビルダーを使ったUserSensor生成時に渡し、UserSensorインスタンスを登録する。
    private UserSensorDriver mDriver = new UserSensorDriver() {};
    private UserSensor mSensor;
...
    mSensor = UserSensor.builder()
        .setName("GroveAccelerometer")
        .setVendor("Seeed")
        .setType(Sensor.TYPE_ACCELEROMETER)
        .setDriver(mDriver)
        .build();
    UserDriverManager.getManager().registerSensor(mSensor);
  1. トリガー発生時もしくは定期的にH/Wイベントを注入する。
  • GPSは、フレーム周期ごとにLocationイベントを送る。
    mDriver.reportLocation(mLastKnownLocation);
  • HIDは、監視しているポートの立ち上がり(立ち下がり)を検知し、イベントを発する。
    int action = pressed ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
    KeyEvent[] events = new KeyEvent[] {new KeyEvent(action, KEY_CODE)};
    mDriver.emit(events);
  • センサーは、UserSensorDriver#readがコールバックされたときに、センサーデバイスからデータを読み込んで値を返す。
UserSensorDriver mDriver = new UserSensorDriver() {
    // Sensor data values
    float x, y, z;

    @Override
    public UserSensorReading read() {
        try {
            // ...read the sensor hardware...

            // Return a new reading
            return new UserSensorReading(new float[]{x, y, z});
        } (catch Exception e) {
            // Error occurred reading the sensor hardware
            throw new IOException("Unable to read sensor");
        }
    }
};
  1. 終了時にUserDriverManagerの登録を解除する。
  • GPS
    UserDriverManager.getManager().unregisterGpsDriver(mDriver);
  • HID
    UserDriverManager.getManager().unregisterInputDriver(mDriver);
  • センサー
    UserDriverManager.getManager().unregisterSensor(mSensor);

アプリ側

  1. 開始時にサービスを起動する。
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        startService(new Intent(this, YourDriverService.class));
    }
  1. コールバックでイベントを受信する。
  • GPSは、LocationListenerで受信する。
    LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                    0, 0, new LocationListener() {
        @Override
        public void onLocationChanged(Location location) { }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) { }

        @Override
        public void onProviderEnabled(String provider) { }

        @Override
        public void onProviderDisabled(String provider) { }
    });

  • HIDは、当該メソッドで受信する。以下はキーの場合。
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        return super.onKeyDown(keyCode, event);
    }

    public boolean onKeyUp(int keyCode, KeyEvent event) {
        return super.onKeyUp(keyCode, event);
    }
  • センサーは、SensorEventListenerで受信する。
    SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    sensorManager.registerDynamicSensorCallback(new SensorManager.DynamicSensorCallback() {
        @Override
        public void onDynamicSensorConnected(Sensor sensor) {
            if (sensor.getType() == Sensor.TYPE_AMBIENT_TEMPERATURE) {
                sensorManager.registerListener(new SensorEventListener() {
                    @Override
                    public void onSensorChanged(SensorEvent event) { }

                    @Override
                    public void onAccuracyChanged(Sensor sensor, int accuracy) { }
                }, sensor, SensorManager.SENSOR_DELAY_NORMAL);
            }
        }
    });
  1. 終了時にサービスを停止する。
    protected void onDestroy(){
        super.onDestroy();

        stopService(new Intent(this, YourDriverService.class));
    }

Service化したソースはここにあります。
https://github.com/tatsu/sample-button

3
2
0

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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?