AndroidでBluetooth デバイスを検出してみる
開発環境
- Android Studio 2020.3.1
- Java
パーミッション設定
AndroidでBluetoothを使用するに当たり、AndroidManifest.xmlに以下の権限を追加。
<!-- Bluetoothの機能を使用するための権限の宣言 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- Bluetoothデバイスを検出するための権限の宣言 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <!-- Bluetoothの機能を使用するための位置情報権限の宣言 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
Bluetoothデバイス検出処理
MainActivityのレイアウトファイル activity_main
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".Activity.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:weightSum="5" android:orientation="horizontal"> <Space android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> <Button android:id="@+id/scan_start_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="スキャン開始" /> <Space android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> <Button android:id="@+id/scan_stop_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="スキャン停止" /> <Space android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> </LinearLayout> <ListView android:id="@+id/DeviceListView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
ListViewで使用するレイアウトファイル listitem_bluetoothdevice
<!--スキャンしたBluetoothデバイスをListviewに表示するときのitemレイアウト--> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/itemview_devicename" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="24dp"/> <TextView android:id="@+id/itemview_deviceaddress" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="12dp"/> </LinearLayout>
ListViewへitem追加用クラス BluetoothDeviceListAdapter
package com.example.bluetoothsampleapplication.Common; import android.app.Activity; import android.bluetooth.BluetoothDevice; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.example.bluetoothsampleapplication.R; import java.util.ArrayList; public class BluetoothDeviceListAdapter extends BaseAdapter { private ArrayList<BluetoothDevice> mBluetoothDeviceList; private LayoutInflater mInflator; public BluetoothDeviceListAdapter( Activity activity ) { super(); mBluetoothDeviceList = new ArrayList<BluetoothDevice>(); mInflator = activity.getLayoutInflater(); } // リストへの追加 public void addDevice( BluetoothDevice device ) { if( !mBluetoothDeviceList.contains( device ) ) { // 加えられていなければ加える mBluetoothDeviceList.add( device ); notifyDataSetChanged(); // ListViewの更新 } } // リストのクリア public void clear() { mBluetoothDeviceList.clear(); notifyDataSetChanged(); // ListViewの更新 } @Override public int getCount() { return mBluetoothDeviceList.size(); } @Override public Object getItem(int i) { return mBluetoothDeviceList.get(i); } @Override public long getItemId(int i) { return i; } static class ViewHolder { TextView deviceName; TextView deviceAddress; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; // General ListView optimization code. if( null == convertView ) { //アイテム用レイアウトビューを取得 convertView = mInflator.inflate( R.layout.listitem_bluetoothdevice, parent, false ); viewHolder = new ViewHolder(); viewHolder.deviceAddress = (TextView)convertView.findViewById( R.id.itemview_deviceaddress ); viewHolder.deviceName = (TextView)convertView.findViewById( R.id.itemview_devicename ); convertView.setTag( viewHolder ); } else { viewHolder = (ViewHolder)convertView.getTag(); } BluetoothDevice device = mBluetoothDeviceList.get( position ); String deviceName = device.getName(); if( null != deviceName && 0 < deviceName.length() ) { viewHolder.deviceName.setText( deviceName ); } else { viewHolder.deviceName.setText( "Unknown device" ); } viewHolder.deviceAddress.setText( device.getAddress() ); return convertView; } }
MainActivity
package com.example.bluetoothsampleapplication.Activity; import static android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED; import static android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED; import static android.bluetooth.BluetoothDevice.ACTION_FOUND; import static android.bluetooth.BluetoothDevice.ACTION_NAME_CHANGED; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.Manifest; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; import com.example.bluetoothsampleapplication.Common.BluetoothDeviceListAdapter; import com.example.bluetoothsampleapplication.R; public class MainActivity extends AppCompatActivity { private BluetoothAdapter mBluetoothAdapter;// BluetoothAdapterオブジェクト private BluetoothDeviceListAdapter mBluetoothDeviceListAdapter;// リストビューの内容 private boolean mScanning = false; // スキャン中かどうかのフラグ private Button scan_start_button;//スキャン開始ボタン private Button scan_stop_button;//スキャン停止ボタン // ブロードキャストレシーバー private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent ) { String action = intent.getAction(); BluetoothDevice device = intent.getParcelableExtra( BluetoothDevice.EXTRA_DEVICE ); switch (action) { case ACTION_DISCOVERY_STARTED: Log.d("MainActivity", "ACTION_DISCOVERY_STARTED"); break; case ACTION_FOUND://デバイスが見つかったら Log.d("MainActivity", "ACTION_FOUND"); mBluetoothDeviceListAdapter.addDevice( device ); break; case ACTION_NAME_CHANGED: Log.d("MainActivity", "ACTION_NAME_CHANGED"); break; case ACTION_DISCOVERY_FINISHED: scan_start_button.setEnabled(true);//ボタンを有効化 scan_stop_button.setEnabled(false);//ボタンを無効化 Log.d("MainActivity", "ACTION_DISCOVERY_FINISHED"); // デバイス検出が終了した場合は、BroadcastReceiver を解除 context.unregisterReceiver(mBroadcastReceiver); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);//layout呼び出し // Bluetoothアダプタの取得 BluetoothManager bluetoothManager = (BluetoothManager)getSystemService( Context.BLUETOOTH_SERVICE ); mBluetoothAdapter = bluetoothManager.getAdapter(); if( null == mBluetoothAdapter ) { // Android端末がBluetoothをサポートしていない Toast.makeText( this, "Bluetooth is not supported.", Toast.LENGTH_SHORT ).show(); finish(); // アプリ終了宣言 return; } //Android端末のBluetooth機能の有効化要求 requestBluetoothFeature(); //権限有効化要求(位置情報権限要求) if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,}, 1000); return; } //UI設定 scan_start_button = findViewById(R.id.scan_start_button); scan_start_button.setOnClickListener(this::onClick); scan_stop_button = findViewById(R.id.scan_stop_button); scan_stop_button.setOnClickListener(this::onClick); scan_stop_button.setEnabled(false);//ボタンを無効化 // リストビューの設定 mBluetoothDeviceListAdapter = new BluetoothDeviceListAdapter( this ); // アダプターの初期化 ListView listView = (ListView)findViewById( R.id.DeviceListView ); // リストビューの取得 listView.setAdapter( mBluetoothDeviceListAdapter ); // リストビューにビューアダプターをセット // イベントフィルター設定 & ブロードキャストレシーバーの登録 IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_DISCOVERY_STARTED);//Bluetoothスキャン開始検出 filter.addAction(ACTION_FOUND);//Bluetoothデバイス検出 filter.addAction(ACTION_DISCOVERY_FINISHED);//Bluetoothスキャン終了検出 registerReceiver( mBroadcastReceiver, filter ); } // 初回表示時、および、ポーズからの復帰時 @Override protected void onResume() { super.onResume(); } // 別のアクティビティ(か別のアプリ)に移行したことで、バックグラウンドに追いやられた時 @Override protected void onPause() { super.onPause(); } //Android端末のBluetooth機能の有効化要求 private void requestBluetoothFeature() { //Android端末のBluetooth機能が有効になっている場合は何もしない if( mBluetoothAdapter.isEnabled() ) { return; } //デバイスのBluetooth機能が有効になっていないときは、有効化要求(ダイアログ表示) Intent enableBtIntent = new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE ); startActivity(enableBtIntent); } // スキャンの開始 private void startScan() { // リストビューの内容を空にする。 mBluetoothDeviceListAdapter.clear(); // スキャンの開始 mScanning = true; mBluetoothAdapter.startDiscovery(); // 約 12 秒間の問い合わせのスキャンが行われる Log.d("Bluetooth","スキャン開始"); // メニューの更新 invalidateOptionsMenu(); } // スキャンの停止 private void stopScan() { Log.d("Bluetooth","スキャン停止"); // スキャンの停止 mScanning = false; mBluetoothAdapter.cancelDiscovery(); } public void onClick(View v) { switch (v.getId()) { case R.id.scan_start_button: startScan(); scan_start_button.setEnabled(false);//ボタンを無効化 scan_stop_button.setEnabled(true);//ボタンを有効化 break; case R.id.scan_stop_button: stopScan(); scan_start_button.setEnabled(true);//ボタンを有効化 scan_stop_button.setEnabled(false);//ボタンを無効化 break; } } }