Android Broadcast Receiver bluetooth events catching
Asked Answered
M

2

29

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?

Maragretmarala answered 13/5, 2015 at 18:16 Comment(4)
Not sure, it may be because of the way broadcast registered. I would try to register in service instead at runtime and see if that changes anything.Disport
@VladimirLichonos Yep, I've tried to add service where I register receiver. It looked like this IntentFilter fltr = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED); fltr.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); fltr.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); fltr.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); registerReceiver(brecv, fltr); where brecv is an object of CustomBluetoothReceiver. There were no any changes.Maragretmarala
Do you start the Service in some place ?Butterfield
Thanks. That was an emulator problem. On real device it works fine.Maragretmarala
C
73

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

Craddock answered 17/5, 2015 at 22:7 Comment(6)
I want to use Connect Disconnect broadcasts in my application I have same code but I am registering broadcasts in Manifest itself. Problem is I am receiving broadcast randomly for random devices..I am using Android M(6.0) I am receiving broadcast just after pairing to device also and sometimes without pairing also and that too though device is not in pairing mode then also.Can you please help me?Guardado
Did something change in Oreo? This doesn't seem to fire anymoreTrinee
developer.android.com/guide/components/…: "Beginning with Android 8.0 (API level 26), the system imposes additional restrictions on manifest-declared receivers. If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that do not target your app specifically)."Damara
This answer is just beautiful. Thanks.Twedy
@TobiasUhmann But ACTION_ACL_CONNECTED and ACTION_ACL_DISCONNECTED (among others) are exempt from that restriction.Velazquez
Is there a way to test Bluetooth related events on the emulator?Herndon
B
0

I have been trying to replicate the same but not able to achieve success in this regard.

This is my class file

class BluetoothCheckActivity : AppCompatActivity() {
private val bluetoothBroadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val action: String? = intent?.action
        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
            val state: Int? =
                intent?.getIntExtra(
                    BluetoothAdapter.EXTRA_STATE,
                    BluetoothAdapter.ERROR
                )
            when (state) {
                BluetoothAdapter.STATE_ON -> tv_bluetoothCheck.text = "Bluetooth is On"
                BluetoothAdapter.STATE_TURNING_ON -> tv_bluetoothCheck.text =
                    "Bluetooth is Turning ON"
                BluetoothAdapter.STATE_OFF -> tv_bluetoothCheck.text =
                    "Bluetooth is Off"
                BluetoothAdapter.STATE_TURNING_OFF -> tv_bluetoothCheck.text =
                    "Bluetooth is Turning Off"
            }
        }
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_bluetooth_check)
    val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
    try {
        registerReceiver(bluetoothBroadcastReceiver, filter)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}
override fun onDestroy() {
    unregisterReceiver(bluetoothBroadcastReceiver)
    super.onDestroy()
}}
Bemba answered 30/8, 2021 at 16:44 Comment(3)
not working for me too, any solution?Wham
Nope, still searching a solution.Bemba
i hope we find oneWham

© 2022 - 2024 — McMap. All rights reserved.