ヘッドフォンの再生状態の確認やヘッドセットからの音声の認識、ヘルス機器との通信などのやり方をサンプルを交えて解説します
前回の「Bluetoothを使ってAndroidアプリ同士で通信するには」では、Androidで使えるBluetoothの種類や設定の仕方、ペアリングや通信の行い方などを通信対戦ゲームのサンプルを交えて解説しました。今回はBluetoothを使用してデバイスに接続し、デバイスを操作する方法を解説します。
Android API Level 16では、デバイスとの接続のために以下の定数とクラスが用意されています。
定数 | クラス |
---|---|
BluetoothProfile.A2DP | BluetoothA2dp |
BluetoothProfile.HEADSET | BluetoothHeadset |
BluetoothProfile.HEALTH | BluetoothHelth |
上記のクラスは、すべてBluetoothProfileインターフェイスを実装していて、以下のメソッドが実装されています。
すべての専用クラスはBluetoothProfileインターフェイスを備えており、同様の操作を提供するとともに、同様の方法で取得も可能です。
// リスナを定義 ServiceListener listener = new ServiceListener() { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { // それぞれの型にキャスト if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = (BluetoothHeadset) proxy; } else if (profile == BluetoothProfile.A2DP) { mBluetoothA2dp = (BluetoothA2dp) proxy; } else if (profile == BluetoothProfile.HEALTH) { mBluetoothHealth= (BluetoothHealth) proxy; } } @Override public void onServiceDisconnected(int profile) { // それぞれのフィールドの参照を削除 if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = null; } else if (profile == BluetoothProfile.A2DP) { mBluetoothA2dp = null; } else if (profile == BluetoothProfile.HEALTH) { mBluetoothHealth = null; } } }; BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); // それぞれのプリファイルでリスナが呼び出されるように登録 adapter.getProfileProxy(this, listener, BluetoothProfile.HEADSET); adapter.getProfileProxy(this, listener, BluetoothProfile.A2DP); adapter.getProfileProxy(this, listener, BluetoothProfile.HEALTH);
今回もサンプルアプリを用意したので、詳細なコードとその動作は、以下よりダウンロードして確認してください。
以下は、それぞれの専用クラスで提供する機能の説明です。
前回も説明しましたが、A2DPとは、「Advanced Audio Distribution Profile」の略で、ステレオ音質のオーディオ配信を行います。Androidとイヤフォン/ヘッドフォンなど音を聞くデバイスとの間の通信プロファイルです。BluetotohA2dpは以下のメソッドを提供します。
また、ブロードキャストレシーバでIntentを取得することで、接続状態変化、再生状態変化をリアルタイムに取得可能です。
以下はIntentFilter設定の抜粋です。
IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED); registerReceiver(mReceiver, filter);
以下は、BroadcastReceiver実装の抜粋です。
String action = intent.getAction(); Bundle extras = intent.getExtras(); int state = extras.getInt(BluetoothProfile.EXTRA_STATE); int prevState = extras.getInt(BluetoothProfile.EXTRA_PREVIOUS_STATE); BluetoothDevice device = extras.getParcelable(BluetoothDevice.EXTRA_DEVICE); if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) { String stateStr = state == BluetoothProfile.STATE_CONNECTED ? "CONNECTED" : state == BluetoothProfile.STATE_CONNECTING ? "CONNECTING" : state == BluetoothProfile.STATE_DISCONNECTED ? "DISCONNECTED" : state == BluetoothProfile.STATE_DISCONNECTING ? "DISCONNECTING" : "Unknown"; String prevStateStr = prevState == BluetoothProfile.STATE_CONNECTED ? "CONNECTED" : prevState == BluetoothProfile.STATE_CONNECTING ? "CONNECTING" : prevState == BluetoothProfile.STATE_DISCONNECTED ? "DISCONNECTED" : prevState == BluetoothProfile.STATE_DISCONNECTING ? "DISCONNECTING" : "Unknown"; Log.d(TAG, "BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:" + " EXTRA_DEVICE=" + device.getName() + " EXTRA_STATE=" + stateStr + " EXTRA_PREVIOUS_STATE=" + prevStateStr); } else if (action.equals(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED)) { String stateStr = state == BluetoothA2dp.STATE_NOT_PLAYING ? "NOT_PLAYING" : state == BluetoothA2dp.STATE_PLAYING ? "PLAYING" : "Unknown"; String prevStateStr = prevState == BluetoothA2dp.STATE_NOT_PLAYING ? "NOT_PLAYING" : prevState == BluetoothA2dp.STATE_PLAYING ? "PLAYING" : "Unknown"; Log.d(TAG, "BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED:" + "EXTRA_DEVICE=" + device.getName() + " EXTRA_STATE=" + stateStr + " EXTRA_PREVIOUS_STATE=" + prevStateStr); }
BroadcastReceiverで状態を取得する際に、接続状態(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)、再生状態(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED)どちらに対してもBluetoothProfile.EXTRA_STATEとBluetoothProfile.EXTRA_PREVIOUS_STATEで現在の状態と直前の状態を取得しますが、それぞれで値の意味が異なるということに注意してください。
BluetoothHeadsetは以下のメソッドを提供します。
HeadsetもA2DPと同様、ブロードキャストレシーバでIntentを取得することで、接続状態変化、音声状態変化をリアルタイムに取得することも可能です(詳細はサンプルアプリのソースコードを参照ください)。
また、Headset固有のIntentとして、ベンダ独自のコマンドも取得可能です。ただし、ベンダ独自なので、取得したコマンドがどのような意味を持つのかは機器の仕様書がなければ知りえないため、一般の開発者向けの機能ではありません。
BluetoothHeadset向けの機能をアプリに実装する際には、スマホのSIMを抜いておくことをお勧めします。ヘッドセットの操作や音声認識で、思わぬ電話発信が行われる可能性があります。
筆者は真夜中にアドレス帳内の番号に何度か電話発信をしてしまいました。皆さんはお気を付けください。
Healthは以下のメソッドを提供します。
AndroidがAPIを提供することで、ヘルス機器とは接続してデータの取得までは簡単に行えますが、実際に取得したデータを解析するには、IEEE 11073の仕様に従った解析処理を実装する必要があります。
例えば、心拍計ならIEEE 11073-10407、歩数計ならIEEE 11073-10441という具合です。本連載でIEEE 11073の内容まで扱うのは範囲を大きく超えてしまうため、BluetoothHealthに関しては、今回はサンプルアプリへの実装は省略させていただきました。
同様にIEEE 11073の実装は省略されていますが、Andoird SDKに「BluetoothHDP」という名前でHealth機器からデータを読み出すサンプルが含まれているので、必要な方はそちらを参照してみてください。
Androidでサポートされているプロファイルを使用して、高レベルなAPIを使用してデバイスの情報を取得できることが分かりました。ただし、制限も存在します。
まず、ペアリングを行う仕組みが提供されていません。もし、本格的なBluetooth管理アプリを作成したとしても、ペアリングはAndroid標準の設定アプリに頼らざるを得ません。特定のアクションを使用することで、Bluetooth設定画面を開けるので、アプリからペアリングを行ってもらいたい場合は、以下のコードを実行してください。
Intent intent = new Intent(); intent.setAction(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS); startActivity(intent);
次に、デバイスを操作する仕組みもほとんど提供されていません。A2DPなら状態取得が提供されるのみで、ヘッドセットは状態取得に加え音声認識が提供されます。しかし、音声認識はユーザーの音声入力が必要であるため、直接操作ではなく、ヘルス機器からも情報取得しかできません。
HDPはAndroid APIとして簡単にヘルス機器のデータを取得可能ですが、実際にはIEEE 11073-104xxのデータ解析処理の実装がヘルス機器種別ごとに必要で、これはかなりハードルが高いです。Google PlayでHDPに対応したアプリは現段階で数えるほどしかありません。
Copyright © ITmedia, Inc. All Rights Reserved.