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);
今回もサンプルアプリを用意したので、詳細なコードとその動作は、以下よりダウンロードして確認してください。
BtProfiles.zip
以下は、それぞれの専用クラスで提供する機能の説明です。
イヤフォン/ヘッドフォンなどの再生状態を確認する「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に対応したアプリは現段階で数えるほどしかありません。
「Androidで動く携帯Javaアプリ作成入門」バックナンバー
グーグルの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!
UnityでAndroidのBluetooth制御&Twitter4J連携
iPhoneアプリでBluetooth通信を使うための基礎知識
【改訂版】Eclipseではじめるプログラミング
Androidアプリ開発テスト入門
イチから始める! Androidセキュリティ
Androidセキュリティの今、これから