1

Problem

How can I differentiate between being unable to establish a Bluetooth connection with a remote Android device because:

  • scenario 1: the remote device is out of range, or its Bluetooth is disabled.
  • scenario 2: the remote device is in range, but there is no server socket on the remote device to accept my connection.

What I've tried

  1. I could not differentiate between exceptions thrown when connecting because it threw the identical exceptions in both cases:

    java.io.IOException: read failed, socket might closed or timeout, read ret -1
    
  2. I could not use fetchUuidsWithSdp() to check if my UUID supported by the remote device because it behaves the same way in either scenario...according to the documentation:

    This API is asynchronous and {@link #ACTION_UUID} intent is sent, with the UUIDs supported by the remote end. If there is an error in getting the SDP records or if the process takes a long time, {@link #ACTION_UUID} intent is sent with the UUIDs that is currently present in the cache...

    it's behaviour also seems sort of unpredictable according to this SO thread.

  3. lastly, I didn't want to use sdpSearch to differentiate between the two, because that was added in API 23, and I want to be able to support down to API 19.

Eric
  • 16,397
  • 8
  • 68
  • 76

1 Answers1

1

You can determine if a device is in range by trying to connect to a standard UUID that is usually available on Android devices. If the call to connect:

  • fails, then remote device is out of range or its Bluetooth is disabled.
  • succeeds, then the remote device is in range and you should close the connection and then try to connect to your app's UUID...if that fails, then there was no listening socket...if it succeeds, then all is well.

Example code:

public BluetoothSocket connect(BluetoothDevice remoteDevice) throws IOException
{
    OPP_UUID = UUID.fromString("00001105-0000-1000-8000-00805f9b34fb");

    // check if remote device is in range...throw exception if out of range
    try
    {
        BluetoothSocket socket = remoteDevice
            .createRfcommSocketToServiceRecord(OPP_UUID);
        socket.connect();
        socket.close();
    }
    catch(IOException ex)
    {
        throw new IOException("out of range",ex);
    }

    // try to connect to service on remote device...throw exception if UUID
    // is not available
    try
    {
        BluetoothSocket socket = remoteDevice
            .createRfcommSocketToServiceRecord(MY_UUID);
        socket.connect();
        return socket;
    }
    catch(IOException ex)
    {
        throw new IOException("no listening server socket",ex);
    }
}

I used BluetoothDevice.getUuids() to get the UUIDs available on one of my Android devices. It gave me this list:

0000110a-0000-1000-8000-00805f9b34fb - Advanced Audio Distribution Profile (0x110a)
00001105-0000-1000-8000-00805f9b34fb - Object Push Profile (0x1105) // least invasive one...it seems
00001115-0000-1000-8000-00805f9b34fb - Personal Area Networking Profile (0x1115)
0000112f-0000-1000-8000-00805f9b34fb - Phonebook Access (0x112f) // this works!
00001112-0000-1000-8000-00805f9b34fb - Headset - Audio Gateway (0x1112)
0000111f-0000-1000-8000-00805f9b34fb - Handsfree Audio Gateway (0x111f)
00001132-0000-1000-8000-00805f9b34fb - Message Access Profile (0x1132) // this works too!
00000000-0000-1000-8000-00805f9b34fb - Base UUID (0x0000) // couldn't get this to work :(

Standard UUIDs from Bluetooth spec.

Eric
  • 16,397
  • 8
  • 68
  • 76