95

I understand how to get a list of paired devices, but how can I tell if they are connected?

It must be possible since I see them listed in my phone's Bluetooth device list and it states their connection status.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dchappelle
  • 1,580
  • 2
  • 13
  • 22

7 Answers7

174

Add the Bluetooth permission to your AndroidManifest,

<uses-permission android:name="android.permission.BLUETOOTH" />

Then use intent filters to listen to the ACTION_ACL_CONNECTED, ACTION_ACL_DISCONNECT_REQUESTED, and ACTION_ACL_DISCONNECTED broadcasts:

public void onCreate() {
    ...
    IntentFilter filter = new IntentFilter();
    filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
    this.registerReceiver(mReceiver, filter);
}

//The BroadcastReceiver that listens for bluetooth broadcasts
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
           ... //Device found
        }
        else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
           ... //Device is now connected
        }
        else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
           ... //Done searching
        }
        else if (BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) {
           ... //Device is about to disconnect
        }
        else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
           ... //Device has disconnected
        }
    }
};

A few notes:

  • There is no way to retrieve a list of connected devices at application startup. The Bluetooth API does not allow you to query, instead it allows you to listen to changes.
  • A hoaky workaround to the above problem would be to retrieve the list of all known/paired devices... then trying to connect to each one (to determine if you're connected).
  • Alternatively, you could have a background service watch the Bluetooth API and write the device states to disk for your application to use at a later date.
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Skylar Sutton
  • 4,632
  • 3
  • 27
  • 39
  • 2
    This is good to as long as my application is running but how can I get a current list? – dchappelle Jan 18 '11 at 16:45
  • 2
    How do you plan on executing code without your application "running"? If you mean you need to access this from something other than an Activity... go google Android Services, build one of those to listen to the broadcasts, and persist it to a list. – Skylar Sutton Jan 18 '11 at 19:44
  • 8
    I can listen for the intents BUT how can I get the initial list of connected Bluetooth devices? If any are already connected by the time my Activity or Service is started I won't know. I would imagine (hope) this data is available somewhere? I wouldn't want to have to create a service (that runs constantly as long as the phone is turned on) just to listen for these intents. – dchappelle Jan 19 '11 at 13:28
  • 11
    There is no way to retrieve the list of connected devices at application startup. The Bluetooth API will only let you listen to connection changes. So yes, the only way to do it is create a long running service and add/remove to a public list. It's a big complaint by a lot of developers. Depending on your performance needs you could retrieve the list of paired devices and try to connect to each one. If it fails, it's not available. Word of warning though: .connect() is a blocking operation. – Skylar Sutton Jan 20 '11 at 18:57
  • I can try and connect to any paired devices as you mentioned but how do I know the UUID? – dchappelle Jan 21 '11 at 16:44
  • I've tried connecting to my bluetooth headset (paired and connected to the phone's audio but I get IOException: Service Discovery. I'm using UUID.fromString("00001101-0000-1000-8000-00805F9B34FB" ? – dchappelle Jan 21 '11 at 16:55
  • Only thing was in my case the constants ACTION_ACL_CONNECTED and a few others were in BluetoothDevice not BluetoothAdapter. Otherwise this works great! – JPM Jun 16 '11 at 18:25
  • 1
    @skylarsutton +1 Thanks a bunch for this answer, helped me getting started on bluetooth – AgentKnopf Feb 14 '12 at 17:23
  • Adding onto what @JPM said in his comment, both `ACTION_ACL_DISCONNECT_REQUESTED` and `ACTION_ACL_DISCONNECTED` are found in the `BluetoothDevice` class not `BluetoothAdapter`. – esme_louise Nov 04 '14 at 21:01
  • I wrote a code that lets you detect if Bluetooth mouse or keyboard device connected on startup without using broadcast.If someone need it i can add it to gitHub. – Alexander Gorelik May 06 '15 at 11:38
  • Happens only when popup for pairing appears and not when pairing completed. Any other way? – DavidBalas Aug 09 '15 at 00:15
  • There is a way to get connected devices at startup, using BluetoothManager.getConnectedDevices, then checking BluetoothManager.getConnectionState for the devices you find. – connorbode Nov 29 '19 at 03:22
  • it's a good answer. thanks! – neo Oct 13 '21 at 07:44
  • @AlexanderGorelik yes, I need it – Hoo Jun 09 '22 at 07:17
  • DONT FORGET to UNREGISTER your RECEIVER in ONDESTROY(). – Prajwal Waingankar Jun 23 '22 at 09:22
44

In my use case I only wanted to see if a Bluetooth headset is connected for a VoIP app. The following solution worked for me.

Kotlin:

fun isBluetoothHeadsetConnected(): Boolean {
    val mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
    return (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled
        && mBluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED)
}

Java:

public static boolean isBluetoothHeadsetConnected() {
    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()
            && mBluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED;
} 

Of course you'll need the Bluetooth permission:

<uses-permission android:name="android.permission.BLUETOOTH" />

Mr. Robot
  • 397
  • 1
  • 14
jobbert
  • 3,297
  • 27
  • 43
  • 4
    This is the one I was seeking for. Just to check upon launch that the Bluetooth is connected or not. Thanks it worked! – sud007 Aug 19 '17 at 05:44
  • This solution worked until I upgraded Android Studio to version 2021.1.1. Now `getProfileConnectionState(BluetoothHeadset.HEADSET)` call shows error "Call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with checkPermission) or explicitly handle a potential SecurityException". The permission that is required is `Manifest.permission.BLUETOOTH_CONNECT`. – Juha Jan 27 '22 at 08:10
  • I'm seeing an issue where a Samsung Galaxy Watch4 shows up as a headset with this call even though `device.bluetoothClass.hasService(BluetoothClass.Service.AUDIO)=false`. I'm trying to figure out how to determine if there are any connected device that supports audio, but the `isConnected` call is SystemApi only. Currently I can see all bonded devices but can't tell if they are connected or not - and so I can't determine if a headset is really connected or just the watch (i.e. i have headphones that are not connected). Does anyone have a solution for this? – notmystyle Feb 15 '22 at 21:29
17

There is an isConnected function in the BluetoothDevice system API in https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth/BluetoothDevice.java.

If you want to know if a bounded (paired) device is currently connected or not, the following function works fine for me:

public static boolean isConnected(BluetoothDevice device) {
    try {
        Method m = device.getClass().getMethod("isConnected", (Class[]) null);
        boolean connected = (boolean) m.invoke(device, (Object[]) null);
        return connected;
    } catch (Exception e) {
        throw new IllegalStateException(e);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
L. W.
  • 171
  • 1
  • 3
  • Have you seen this give a different result from just checking whether `bluetoothManager.getConnectionState(device, BluetoothProfile.GATT) == BluetoothProfile.STATE_CONNECTED`? – Gumby The Green May 28 '20 at 08:35
  • 1
    From what I can tell, they do give the same result. Note that for Kotlin users, those first two lines are just `val m: Method = device.javaClass.getMethod("isConnected")` and `val connected = m.invoke(device)`. – Gumby The Green May 28 '20 at 22:57
  • 3
    Thank you, exactly what I needed! This is the kotlin equivalent for this method: `fun isConnected(device: BluetoothDevice): Boolean { return try { val m: Method = device.javaClass.getMethod( "isConnected" ) m.invoke(device) as Boolean } catch (e: Exception) { throw IllegalStateException(e) } }` – Takeya Jul 17 '20 at 14:17
  • reflection is forbidden now – user924 Nov 01 '22 at 20:42
12

For some reason, BluetoothAdapter.ACTION_ACL_CONNECTED could not be resolved by Android Studio. Perhaps it was deprecated in Android 4.2.2?

Here is a modification of Skylarsutton's code (Big thanks to Skylarsutton for his answer.) . The registration code is the same; the receiver code differs slightly. I use this in a service which updates a Bluetooth-connected flag that other parts of the app reference.

    public void onCreate() {
        //...
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        this.registerReceiver(BTReceiver, filter);
    }

    //The BroadcastReceiver that listens for bluetooth broadcasts
    private final BroadcastReceiver BTReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
            //Do something if connected
            Toast.makeText(getApplicationContext(), "BT Connected", Toast.LENGTH_SHORT).show();
        }
        else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
            //Do something if disconnected
            Toast.makeText(getApplicationContext(), "BT Disconnected", Toast.LENGTH_SHORT).show();
        }
        //else if...
    }
};
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
pmont
  • 2,083
  • 22
  • 43
  • 1
    your code is correct; it wasn't deprecated in 4.2.2. The BluetoothAdapter class doesn't contain, ACTION_ACL_CONNECTED. That string is in the BluetoothDevice class. – RobLabs Aug 12 '13 at 03:05
1

BluetoothAdapter.getDefaultAdapter().isEnabled -> returns true when Bluetooth is open.

val audioManager = this.getSystemService(Context.AUDIO_SERVICE) as AudioManager

audioManager.isBluetoothScoOn -> returns true when a device connected

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ravid rinek
  • 89
  • 1
  • 6
1

This code is for the headset profiles, and probably it will work for other profiles too.

First you need to provide a profile listener (Kotlin code):

private val mProfileListener = object : BluetoothProfile.ServiceListener {
    override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
        if (profile == BluetoothProfile.HEADSET)
            mBluetoothHeadset = proxy as BluetoothHeadset
    }

    override fun onServiceDisconnected(profile: Int) {
        if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset = null
        }
    }
}

Then while checking Bluetooth:

mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET)
if (!mBluetoothAdapter.isEnabled) {
    return Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
}

It takes a bit of time until onSeviceConnected is called. After that you may get the list of the connected headset devices from:

mBluetoothHeadset!!.connectedDevices
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • I used this, for A2DP, but it also gets called when there are no devices connected and only bluetooth is active, and when you connect the device, without disabling bluetooth system setting, then you don't get a new event. – Peterdk Apr 30 '22 at 09:38
0

I was really looking for a way to fetch the connection status of a device, not listen to connection events. Here's what worked for me:

BluetoothManager bm = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
List<BluetoothDevice> devices = bm.getConnectedDevices(BluetoothProfile.GATT);
int status = -1;

for (BluetoothDevice device : devices) {
  status = bm.getConnectionState(device, BLuetoothGatt.GATT);
  // compare status to:
  //   BluetoothProfile.STATE_CONNECTED
  //   BluetoothProfile.STATE_CONNECTING
  //   BluetoothProfile.STATE_DISCONNECTED
  //   BluetoothProfile.STATE_DISCONNECTING
}
soshial
  • 5,906
  • 6
  • 32
  • 40
connorbode
  • 3,015
  • 1
  • 28
  • 31