I’m trying to fetch the UUIDS from a remote bluetooth device like this:
device.fetchUuidsWithSdp();
This will work silently and without user interaction on all devices except those with Android 6.0 which visibly ask with a pairing dialog to connect with the remote device to fetch the UUID. Is that an expected behaviour? Where is this documented? Is there a way to trigger UUID discovery without explicitly having to allow it from the other end?
Answer
I’ve found a workaround to this by using the hidden sdpSearch method instead of fetchUuidsWithSdp. This requires a bit of reflection. This worked for me on android 6.0 and 5.1.1, without the devices trying to pair. Hope this helps, and feel free to improve the rather poor exception handling.
public class DeviceFinder{ public interface Callback{ void onDeviceFound(BluetoothDevice bd); void onFinishedCallback(); void onStartCallback(); } private ArrayList<BluetoothDevice> tempDevices = new ArrayList<>(); private Callback mCallback; private Context mContext; private String ACTION_SDP_RECORD; private String EXTRA_SDP_SEARCH_RESULT; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)){ // Aggregating found devices BluetoothDevice bd = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); tempDevices.add(bd); }else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){ // Prepare for new search tempDevices = new ArrayList<>(); mCallback.onStartCallback(); }else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){ // Do a sdpSearch for all found devices for (BluetoothDevice bd : tempDevices){ try { Method m = bd.getClass().getDeclaredMethod("sdpSearch", ParcelUuid.class); m.invoke(bd, new ParcelUuid(/* your uuid here */)); } catch (Exception e) { e.printStackTrace(); } } mCallback.onFinishedCallback(); }else if( ACTION_SDP_RECORD.equals(action)){ // check if the device has the specified uuid BluetoothDevice bd = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (intent.getIntExtra(EXTRA_SDP_SEARCH_RESULT, 1) == 0){ mCallback.onDeviceFound(bd); } } } }; public DeviceFinder(Context context, Callback mCallback){ this.mCallback = mCallback; this.mContext = context; try { Field f = BluetoothDevice.class.getDeclaredField("ACTION_SDP_RECORD"); ACTION_SDP_RECORD = ((String)f.get(null)); f = BluetoothDevice.class.getDeclaredField("EXTRA_SDP_SEARCH_STATUS"); EXTRA_SDP_SEARCH_RESULT = ((String)f.get(null)); } catch (Exception e) { e.printStackTrace(); } IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothDevice.ACTION_FOUND); intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); intentFilter.addAction(ACTION_SDP_RECORD); context.registerReceiver(mReceiver, intentFilter); startScan(); } public void startScan(){ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (!bluetoothAdapter.isDiscovering()) { bluetoothAdapter.startDiscovery(); } } public void unregisterReciever(){ mContext.unregisterReceiver(mReceiver); } }
edit: sdpSearch was added in android 6.0, so it does not work for earlier versions