How can I programmatically tell if a Bluetooth device is connected?

139,702

Solution 1

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.

Solution 2

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" />

Solution 3

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);
    }
}

Solution 4

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...
    }
};

Solution 5

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
Share:
139,702
dchappelle
Author by

dchappelle

Updated on July 08, 2022

Comments

  • dchappelle
    dchappelle almost 2 years

    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.

  • dchappelle
    dchappelle over 13 years
    This is good to as long as my application is running but how can I get a current list?
  • Skylar Sutton
    Skylar Sutton over 13 years
    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.
  • dchappelle
    dchappelle over 13 years
    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.
  • Skylar Sutton
    Skylar Sutton over 13 years
    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.
  • dchappelle
    dchappelle over 13 years
    I can try and connect to any paired devices as you mentioned but how do I know the UUID?
  • dchappelle
    dchappelle over 13 years
    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" ?
  • JPM
    JPM about 13 years
    Only thing was in my case the constants ACTION_ACL_CONNECTED and a few others were in BluetoothDevice not BluetoothAdapter. Otherwise this works great!
  • AgentKnopf
    AgentKnopf over 12 years
    @skylarsutton +1 Thanks a bunch for this answer, helped me getting started on bluetooth
  • RobLabs
    RobLabs almost 11 years
    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.
  • pmont
    pmont almost 11 years
    Thanks for clarifying that!
  • esme_louise
    esme_louise over 9 years
    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.
  • Alexander Gorelik
    Alexander Gorelik about 9 years
    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.
  • DavidBalas
    DavidBalas almost 9 years
    Happens only when popup for pairing appears and not when pairing completed. Any other way?
  • sud007
    sud007 almost 7 years
    This is the one I was seeking for. Just to check upon launch that the Bluetooth is connected or not. Thanks it worked!
  • connorbode
    connorbode over 4 years
    There is a way to get connected devices at startup, using BluetoothManager.getConnectedDevices, then checking BluetoothManager.getConnectionState for the devices you find.
  • Gumby The Green
    Gumby The Green about 4 years
    Have you seen this give a different result from just checking whether bluetoothManager.getConnectionState(device, BluetoothProfile.GATT) == BluetoothProfile.STATE_CONNECTED?
  • Gumby The Green
    Gumby The Green about 4 years
    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).
  • Takeya
    Takeya almost 4 years
    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) } }
  • neo
    neo over 2 years
    it's a good answer. thanks!
  • Juha
    Juha over 2 years
    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.
  • notmystyle
    notmystyle over 2 years
    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.AUDI‌​O)=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?
  • Peterdk
    Peterdk about 2 years
    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.
  • Hoo
    Hoo about 2 years
    @AlexanderGorelik yes, I need it
  • Prajwal Waingankar
    Prajwal Waingankar about 2 years
    DONT FORGET to UNREGISTER your RECEIVER in ONDESTROY().