I'm trying to catch bluetooth state changes with Broadcast Receiver.
My manifest:
<uses-permission android:name="android.permission.BLUETOOTH" />
<application>
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".BluetoothBroadcastReceiver"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
<action android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
</intent-filter>
</receiver>
</application>
Receiver onReceive
method:
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d("BroadcastActions", "Action "+action+"received");
int state;
BluetoothDevice bluetoothDevice;
switch(action)
{
case BluetoothAdapter.ACTION_STATE_CHANGED:
state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
if (state == BluetoothAdapter.STATE_OFF)
{
Toast.makeText(context, "Bluetooth is off", Toast.LENGTH_SHORT).show();
Log.d("BroadcastActions", "Bluetooth is off");
}
else if (state == BluetoothAdapter.STATE_TURNING_OFF)
{
Toast.makeText(context, "Bluetooth is turning off", Toast.LENGTH_SHORT).show();
Log.d("BroadcastActions", "Bluetooth is turning off");
}
else if(state == BluetoothAdapter.STATE_ON)
{
Log.d("BroadcastActions", "Bluetooth is on");
}
break;
case BluetoothDevice.ACTION_ACL_CONNECTED:
bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Toast.makeText(context, "Connected to "+bluetoothDevice.getName(),
Toast.LENGTH_SHORT).show();
Log.d("BroadcastActions", "Connected to "+bluetoothDevice.getName());
break;
case BluetoothDevice.ACTION_ACL_DISCONNECTED:
bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Toast.makeText(context, "Disconnected from "+bluetoothDevice.getName(),
Toast.LENGTH_SHORT).show();
break;
}
}
I launch app then minimize it by pressing Home button. Go to settings and turn on bluetooth but nothing happens. Though I expect toast and logcat messages. What's wrong here?
As per the provided link in the teacher's notes, https://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html#MonitorChanges declaring BroadcastReceivers in the manifest is deprecated from Android 7.0 and up.
A broadcast receiver will always get notified of a broadcast, regardless of the status of your application. It doesn't matter if your application is currently running, in the background or not running at all.
A broadcast receiver (receiver) is an Android component which allows you to register for system or application events. All registered receivers for an event are notified by the Android runtime once this event happens.
As a general rule, broadcast receivers are allowed to run for up to 10 seconds before they system will consider them non-responsive and ANR the app.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With