Androidからイヤフォンやヘルス機器とBluetooth通信するには:Androidで動く携帯Javaアプリ作成入門(36)
ヘッドフォンの再生状態の確認やヘッドセットからの音声の認識、ヘルス機器との通信などのやり方をサンプルを交えて解説します
BluetoothProfileを使用したデバイスの操作方法
前回の「Bluetoothを使ってAndroidアプリ同士で通信するには」では、Androidで使えるBluetoothの種類や設定の仕方、ペアリングや通信の行い方などを通信対戦ゲームのサンプルを交えて解説しました。今回はBluetoothを使用してデバイスに接続し、デバイスを操作する方法を解説します。
Android API Level 16では、デバイスとの接続のために以下の定数とクラスが用意されています。
定数 | クラス |
---|---|
BluetoothProfile.A2DP | BluetoothA2dp |
BluetoothProfile.HEADSET | BluetoothHeadset |
BluetoothProfile.HEALTH | BluetoothHelth |
上記のクラスは、すべてBluetoothProfileインターフェイスを実装していて、以下のメソッドが実装されています。
- getConnectedDevices(): List
このプロファイルで接続されているデバイスをリストで取得 - etConnectedState(BluetoothDevice): int
デバイスの接続状態をSTATE_CONNECTED、STATE_CONNECTING、STATE_DISCONNECTED、STATE_DISCONNECTINGのいずれかで取得 - getDeviceMatchingConnectionStates(int[]): List
配列で指定した接続状態(STATE_CONNECTED、STATE_CONNECTING、STATE_DISCONNECTED、STATE_DISCONNECTING)にマッチするデバイスをリストで取得
すべての専用クラスは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);
今回もサンプルアプリを用意したので、詳細なコードとその動作は、以下よりダウンロードして確認してください。
以下は、それぞれの専用クラスで提供する機能の説明です。
イヤフォン/ヘッドフォンなどの再生状態を確認する「BluetoothA2dp」
前回も説明しましたが、A2DPとは、「Advanced Audio Distribution Profile」の略で、ステレオ音質のオーディオ配信を行います。Androidとイヤフォン/ヘッドフォンなど音を聞くデバイスとの間の通信プロファイルです。BluetotohA2dpは以下のメソッドを提供します。
- isA2dpPlaying(BluetoohDevice): boolean
デバイスが再生中かどうかを返します。
また、ブロードキャストレシーバで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」
BluetoothHeadsetは以下のメソッドを提供します。
- isAudioConnected(BluetoohDevice): boolean
デバイスが接続中かどうかを返す - startVoiceRecognition(BluetoohDevice): boolean
音声認識を開始します。デバイスが接続されていないか音声認識をサポートしていなかエラーが発生した場合はfalse、そうでない場合はtrueを返す - stopVoiceRecognition(BluetoohDevice): boolean
音声認識を終了します。デバイスが接続されていないかエラーが発生した場合はfalse、そうでない場合はtrueを返す
HeadsetもA2DPと同様、ブロードキャストレシーバでIntentを取得することで、接続状態変化、音声状態変化をリアルタイムに取得することも可能です(詳細はサンプルアプリのソースコードを参照ください)。
また、Headset固有のIntentとして、ベンダ独自のコマンドも取得可能です。ただし、ベンダ独自なので、取得したコマンドがどのような意味を持つのかは機器の仕様書がなければ知りえないため、一般の開発者向けの機能ではありません。
BluetoothHeadset向けの機能をアプリに実装する際には、スマホのSIMを抜いておくことをお勧めします。ヘッドセットの操作や音声認識で、思わぬ電話発信が行われる可能性があります。
筆者は真夜中にアドレス帳内の番号に何度か電話発信をしてしまいました。皆さんはお気を付けください。
ヘルス機器と通信する「BluetoothHealth」
Healthは以下のメソッドを提供します。
- connectChannelToSource(BluetoothDevice, BluetoothHealthApConfiguration): boolean
ヘルス機器に接続する。このメソッドがtrueを返した場合、コンフィギュレーションに関連付けされたコールバックが呼び出される - disconnectChannel(BluetoothDevice, BluetoothHealthApConfiguration, int): boolean
ヘルス機器から切断する。このメソッドがtrueを返した場合、コンフィギュレーションに関連付けされたコールバックが呼び出される - getMainChannelFd(BluetoothDevice, BluetoothHealthApConfiguration): ParcelFileDescriptor
ヘルス機器とコンフィギュレーションに関連付けされたファイルディスクリプタを取得 - registerSinkAppConfiguration(String, int, BluetoothHealthCallback): boolean
ヘルス受信機器として機能するアプリケーションコンフィギュレーションを登録する。このメソッドがtrueを返した場合、コンフィギュレーションに関連付けされたコールバックが呼び出される - unregisterAppConfiguration(BluetoothHealthAppConfiguration): boolean
アプリケーションコンフィギュレーションを登録解除。このメソッドがtrueを返した場合、コンフィギュレーションに関連付けされたコールバックが呼び出される
AndroidがAPIを提供することで、ヘルス機器とは接続してデータの取得までは簡単に行えますが、実際に取得したデータを解析するには、IEEE 11073の仕様に従った解析処理を実装する必要があります。
例えば、心拍計ならIEEE 11073-10407、歩数計ならIEEE 11073-10441という具合です。本連載でIEEE 11073の内容まで扱うのは範囲を大きく超えてしまうため、BluetoothHealthに関しては、今回はサンプルアプリへの実装は省略させていただきました。
同様にIEEE 11073の実装は省略されていますが、Andoird SDKに「BluetoothHDP」という名前でHealth機器からデータを読み出すサンプルが含まれているので、必要な方はそちらを参照してみてください。
AndroidでBluetoothを使う際の制限
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に対応したアプリは現段階で数えるほどしかありません。
- グーグルのAPIを使うときに欠かせないGoogle OAuthの作り方と使い方
- 細か過ぎて伝わってないけど開発者が知っておきたいAndroid Mの新機能まとめ
- 腕時計から電話をかけるAndroid Wearアプリの作り方
- Android Wear用アプリの花形、時計アプリ「Watch Face」の基本的な作り方
- Android 5.0発表&スマホと連動する音声認識Android Wearアプリの作り方
- ウェアラブル端末用Android Wearアプリ開発の基礎知識
- 変わらないと生き残れないAndroid Lの新機能まとめ
- Android WearやIoTで注目のAndroidセンサー機能8選
- ウェアラブル時代に見直したいAndroidの加速度/重力センサー、ジャイロスコープ
- あなたの知らないAndroid SDKの便利tools、14選まとめ
- Android 4.4のメモリ使用状況を把握する3つのツールの使い方
- Androidでリアルタイムマルチプレーゲームを開発するには
- 低性能端末でも使えるか? Android 4.4 KitKatの新機能39選
- もはや無料BaaS。ゲーム以外でも使いたくなるGoogle Play Game Servicesのデータ管理機能
- アプリにGoogle+のソーシャルグラフを持ち込めるGoogle Play Game Servicesの基礎知識
- あなたのアプリはクラウドにデータをバックアップできますか?
- Eclipse ADTに代わるIDEとなるか? Android Studioの基礎知識
- ActionBarで、アプリのUIはこんなにスマートになる
- Android 4.x時代のアプリにないと残念なActionBarとは
- 動的クラスローディングでAndroidアプリ“裏”開発
- Android 4.xのAndroidビームをアプリに組み込むには
- AndroidアプリでNFCタグを読み書きするための基礎知識
- 新タブレット時代を見据えるAndroid 4.2の新機能9選
- Androidからイヤフォンやヘルス機器とBluetooth通信するには
- Bluetoothを使ってAndroidアプリ同士で通信するには
- Androidアプリをアプリ内購読に対応してもうける方法
- 開発者が知らないと残念過ぎるAndroid 4.1の新機能36選
- Androidのプロセス間通信を自由自在にするAIDL
- Android 4.0のサービス/プロセス間通信の基本
- Androidアプリでマルチメディアを扱うための基礎知識
- Androidのウィジェットにノーティフィケーションするには
- Android 4.0で注目の顔認識をアプリに組み込むには
- Android 4.0でアプリ開発を始めるための環境構築
- 開発者が知らないと損するAndroid 4.0の新機能44選
- Android Compatibility packageで2.x系でもマルチサイズ対応
- Androidの画面の大きさの違いを解決するFragments
- Android 3.0の新APIで簡単ドラッグ&ドロップ実装
- 開発者が知って得するAndroid 2.3の新機能18選
- アニメーションでAndroidに独創的な画面エフェクトを
- Androidアプリで“アニメーション”するための基礎知識
- XMLレイアウトでAndroidアプリに“設定画面”を追加
- 開発者が知っておきたいAndroid 2.2の新機能12連発
- もはやケータイに必須のカメラをAndroidで制御しよう
- 地図/位置情報/GPSを使うAndroidアプリを作るには
- Android NDKでJNIを使用してアプリを高速化するには
- Android 2.1の新機能「Live Wallpaper」で作る、美しく燃える“待ち受け”
- iPhoneより多彩なAndroidのセンサをアプリで操作
- SurfaceViewならAndroidで高速描画ゲームが作れる
- Android 1.6のジェスチャーとテキスト読み上げを使う
- Androidのホーム画面に常駐するアプリを作るには
- Netbookにも広まるAndroidで、かつてないWeb体験を
- アプリを国際化してAndroid Marketから世界へ発信
- 常駐アプリが作成できるAndroidの“サービス”とは
- AndroidでSQLiteのDB操作をするための基礎知識
- Androidアプリの使いやすさを左右する5つのレイアウト
- 簡単でワクワクするAndroidウィジェット10連発!
- ブラウザや地図、ストリートビューの基、Intentとは?
- Androidアプリ作成の基本“Activity”とは何か?
- Android Market配布を目指しEclipseでHelloWorld!
Copyright © ITmedia, Inc. All Rights Reserved.