How to Detect Bluetooth State Change Using a Broadcast Receiver

How to detect Bluetooth state change using a broadcast receiver?

AS far as permissions go, to detect the state change of bluetooth you need to add this to your AndroidManifest.xml.

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

An example receiver would look like this, you add this code to where you want to handle the broadcast, for example an activity:

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive (Context context, Intent intent) {
String action = intent.getAction();

if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
if(intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
== BluetoothAdapter.STATE_OFF)
// Bluetooth is disconnected, do handling here
}

}

};

To use the receiver, you need to register it. Which you can do as follows. I register the receiver in my main activity.

registerReceiver(this, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));

You could also decide to add all of it to your AndroidManifest.xml. This way you can make a special class for the receiver and handle it there. No need to register the receiver, just make the class and add the below code to the AndroidManifest

<receiver
android:name=".packagename.NameOfBroadcastReceiverClass"
android:enabled="true">
<intent-filter>
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED"/>
</intent-filter>
</receiver>

Android Broadcast Receiver bluetooth events catching

In order to catch Bluetooth state changes (STATE_OFF, STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF), do this:

First, add Bluetooth permission to your AndroidManifest file:

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

Create a BroadcastReceiver in your Activity or Service:

    private final BroadcastReceiver mBroadcastReceiver1 = new BroadcastReceiver() {

@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();

if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
switch(state) {
case BluetoothAdapter.STATE_OFF:
..
break;
case BluetoothAdapter.STATE_TURNING_OFF:
..
break;
case BluetoothAdapter.STATE_ON:
..
break;
case BluetoothAdapter.STATE_TURNING_ON:
..
break;
}

}
}
};

Create an IntentFilter and register it with BroadcastReceiver in your Activity/Service's onCreate() method:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

IntentFilter filter1 = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mBroadcastReceiver1, filter1);

...
}

Unregister BroadcastReceiver in your onDestroy() method:

@Override
protected void onDestroy() {
super.onDestroy();

unregisterReceiver(mBroadcastReceiver1);
}

In order to catch changes of discoverability of device (SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE), create another BroadcastReceiver and register/unregister to your Activity as I mentioned above. Only difference between those BroadcastReceivers is the first one uses BluetoothAdapter.EXTRA_STATE and the other one uses BluetoothAdapter.EXTRA_SCAN_MODE. Here is the example code for BroadcastReceiver to catch discoverability changes:

Create an IntentFilter and register it in onCreate() method:

IntentFilter filter2 = new IntentFilter();
filter2.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter2.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
filter2.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
registerReceiver(mBroadcastReceiver2, filter2);

Create the BroadcastReciver in Activity/Service to catch discoverability changes:

    private final BroadcastReceiver mBroadcastReceiver2 = new BroadcastReceiver() {

@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();

if(action.equals(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED)) {

int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.ERROR);

switch(mode){
case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
..
break;
case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
..
break;
case BluetoothAdapter.SCAN_MODE_NONE:
..
break;
}
}
}
};

And lastly unregister BroadcastReciver in onDestroy():

unregisterReceiver(mBroadcastReceiver2);

Note that, you don't need to add any <intent-filter> or <receiver> to your AndroidManifest file, except you need to add Bluetooth permission of course.

If you want to catch (ACTION_ACL_CONNECTED, ACTION_ACL_DISCONNECTED, ACTION_ACL_DISCONNECT_REQUESTED), now you need to add an <intent-filter> to your AndroidManifest file:

<intent-filter>
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
</intent-filter>

Create filter and register it in onCreate() method:

IntentFilter filter3 = new IntentFilter();
filter3.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter3.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
registerReceiver(mBroadcastReceiver3, filter3);

Then create the BroadcastReceiver in your Activity/Service:

    private final BroadcastReceiver mBroadcastReceiver3 = new BroadcastReceiver() {

@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();

switch (action){
case BluetoothDevice.ACTION_ACL_CONNECTED:
..
break;
case BluetoothDevice.ACTION_ACL_DISCONNECTED:
..
break;
}
}
};

And lastly, unregister:

unregisterReceiver(mBroadcastReceiver3);

If you want to read more about state constants, this is from the documentation:

public static final String EXTRA_STATE:

Used as an int extra field in ACTION_STATE_CHANGED intents to request
the current power state. Possible values are: STATE_OFF,
STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF

public static final String EXTRA_SCAN_MODE:

Used as an int extra field in ACTION_SCAN_MODE_CHANGED intents to
request the current scan mode. Possible values are: SCAN_MODE_NONE,
SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE

Detect Enable/Disable Bluetooth

To detect the state change of bluetooth you need to add following permission to your AndroidManifest.xml.

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

Use a Local broadcast preferably. You do not need to register it in Manifest . register it at runtime where you need it.(If need throughout the app then register it in Manifest)

private final BroadcastReceiver bStateReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_OFF) {
// Bluetooth is disconnected, do handling here
}
}
}

};

Runtime register:

LocalBroadcastManager.getInstance(this).registerReceiver(bStateReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));

Runtime unregister : Don't forget to unregister the broadcast.

LocalBroadcastManager.getInstance(this).unregisterReceiver(bStateReceiver);

Static Register:

<receiver
android:name=".FullyQualifiedBroadcastReceiverClassName"
android:enabled="true">
<intent-filter>
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED"/>
</intent-filter>

How to track BluetoothAdapter state changes dynamically in Jetpack Compose?

I was able to solve this just by using mutableStateOf. It doesn't have to be initialized inside of a @Composable function to be reactive, which is what I misunderstood in the first place.

  1. Define a mutableStateOf value and a BroadcastReceiver that will track the state of BluetoothAdapter. When Bluetooth state changes, update the value.
    private var isBluetoothEnabled = mutableStateOf(false)

private val mReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == BluetoothAdapter.ACTION_STATE_CHANGED) {
when (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) {
BluetoothAdapter.STATE_OFF -> {
isBluetoothEnabled.value = false
Log.i("Bluetooth", "State OFF")
}
BluetoothAdapter.STATE_ON -> {
isBluetoothEnabled.value = true
Log.i("Bluetooth", "State ON")
}
}

}
}
}

  1. Inside of a @Composable function, use this value as usual:
@Composable
private fun MainScreen(
isBluetoothEnabled: Boolean
) {
if (isBluetoothEnabled) {
// Display some UI
} else {
// Display different UI
}
}

And that's it!

Detecting state changes made to the BluetoothAdapter?

You will want to register a BroadcastReceiver to listen for any changes in the state of the BluetoothAdapter:

As a private instance variable in your Activity (or in a separate class file... whichever one you prefer):

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();

if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_OFF:
setButtonText("Bluetooth off");
break;
case BluetoothAdapter.STATE_TURNING_OFF:
setButtonText("Turning Bluetooth off...");
break;
case BluetoothAdapter.STATE_ON:
setButtonText("Bluetooth on");
break;
case BluetoothAdapter.STATE_TURNING_ON:
setButtonText("Turning Bluetooth on...");
break;
}
}
}
};

Note that this assumes that your Activity implements a method setButtonText(String text) that will change the Button's text accordingly.

And then in your Activity, register and unregister the BroadcastReceiver as follows,

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

/* ... */

// Register for broadcasts on BluetoothAdapter state change
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mReceiver, filter);
}

@Override
public void onDestroy() {
super.onDestroy();

/* ... */

// Unregister broadcast listeners
unregisterReceiver(mReceiver);
}


Related Topics



Leave a reply



Submit