I'm working on application which shows list of certain connected bluetooth low energy devices, so user can choose which one of them he wants to configure.
The problem is that you can't just list all connected devices. As far as I know there are three possible ways:
Use BluetoothProfiles
bluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER);
This fails because android won't connect to GATT server, when device connects, so device is neither under GATT_SERVER nor GATT profile. However once I call connectGatt method,
bluetoothDevice.connectGatt(getApplicationContext(), false, gattCallback);
device can be found under both GATT_SERVER and GATT profile. Other profiles are not supported by low energy devices.
List paired devices and try connectGatt on each of them
List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>(); for(BluetoothDevice device : bluetoothAdapter.getBondedDevices()) { BluetoothGatt gatt = device.connectGatt(getApplicationContext(), false, gattCallback); if(gatt != null) { connectedDevices.add(device); } gatt.disconnect(); }
This method cannot be used as it cannot determine if device is already connected or only in range but not connected
On system boot start service listening to ACL_CONNECTED and ACL_DISCONNECTED intents and maintaining list of connected devices
Manifest
<service android:name=".ManagerService" android:enabled="true" /> <receiver android:name=".BootFinishedReceiver" android:directBootAware="true" android:enabled="true" android:exported="false" android:permission="android.permission.RECEIVE_BOOT_COMPLETED"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver>
Receiver
public class BootFinishedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent serviceIntent = new Intent(context, ManagerService.class); context.startService(serviceIntent); } }
Service
public class ManagerService extends Service { private static List<BluetoothDevice> connectedDevices; @Override public void onCreate() { connectedDevices = new ArrayList<BluetoothDevice>(); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); registerReceiver(connectionReceiver, filter); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { unregisterReceiver(connectionReceiver); super.onDestroy(); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } private final BroadcastReceiver connectionReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if(BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) { connectedDevices.add(device); }else{ connectedDevices.remove(device); } } }; public static List<BluetoothDevice> getConnectedDevices() { return connectedDevices; } }
Since 3.1 apps can no longer receive system intents before activity is started, so this cannot be used either.
Is there any other way or how can I achieve it now in later android versions?
Thanks for any suggestions