83

I have an app with a button on it that I use to turn BT on and off. I have the following code in there;

public void buttonFlip(View view) {
    flipBT();
    buttonText(view);
}

public void buttonText(View view) {  
    Button buttonText = (Button) findViewById(R.id.button1);
    if (mBluetoothAdapter.isEnabled() || (mBluetoothAdapter.a)) {
        buttonText.setText(R.string.bluetooth_on);  
    } else {
        buttonText.setText(R.string.bluetooth_off);
    }
}

private void flipBT() {
    if (mBluetoothAdapter.isEnabled()) {
        mBluetoothAdapter.disable();    
    } else {
        mBluetoothAdapter.enable();
    }
}

I'm calling button Flip, which flips the BT state, and then calls ButtonText, which should update the UI. However, the issue I'm having is, it takes a few seconds for BT to turn on - and during these seconds, the BT status is not enabled, making my button say Bluetooth off, even if it will be on in 2 seconds.

I found the STATE_CONNECTING constant in the BluetoothAdapter android documentation, but... I simply don't know how to use it, being a newbie and all.

So, I've got two questions:

  1. Is there a way to dynamically tie a UI element (such as a button or image) to a BT state, so that when the BT state changes, the button will change as well?
  2. Otherwise, I would want to press the button and get the correct state (I would like for it to say BT on, even if it's only connecting, since it will be on in 2 seconds). How do I do this?
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
raingod
  • 1,377
  • 1
  • 11
  • 24
  • can't you use a boolean and set it to true once BT starts turning on, then check the boolean state to change the button? – Bill Gary Mar 13 '12 at 23:56
  • Have a look at this AOSP code to get a feel for how they're tracking bluetooth on/off changes: http://androidxref.com/5.1.0_r1/xref/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java – IgorGanapolsky Mar 23 '15 at 22:23

2 Answers2

219

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);
}
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
  • Alex, this almost works. a few things. first, I think you meant to register BluetoothAdapter, not BluetoothDevice, since BluetoothDevice is when you pair the device, and it only has a BluetoothDevice.ACTION_BOND_STATE_CHANGED, which won't apply here. I also added a ; after the broadcastReceiver code (i'm only writing this in for future folks who will have the same problem and read this), however, I'm getting a "Java.lang.RuntimeException: Unable to instantiate activity ComponentInfo", which usually means my activity isn't registered in manifest-do I need to register the receiver in there? – raingod Mar 14 '12 at 01:28
  • ha! i'm an idiot :) I figured out my problem. so, yeah, apart from the code things i mentioned up there, this works beautifully :) thank Alex! – raingod Mar 14 '12 at 01:45
  • no problem! sorry about the typos... as I was typing it up I knew there must be a couple :). – Alex Lockwood Mar 14 '12 at 01:47
  • I personally find Alex's answer to be the best one so far. Just remember that you can also register your broadcast receiver in AndroidManifest.xml as well. Just be careful about the code you put in your broadcast receiver as it will execute sometimes before an instance of your application has been created, at least in my personal experience. – Daniel Eagle Oct 15 '14 at 13:35
  • @AlexLockwood. I have the same situation and I've Implemented the same thing as you answered. But I am facing a problem that this is not working when my bluetooth is already on when I open my app. I hope you understand my point. – Zubair Ahmed Jul 11 '15 at 13:26
  • 12
    You should register and unregister in onStart and onStop. onDestroy is not guaranteed to be called! – MobileMon Dec 08 '15 at 01:36
  • This is not working for me. I have a button, which turns on bluetooth ON and OFF. I changed the code to what you mentioned and hoping to change the button background color. Find the question here: http://stackoverflow.com/questions/43122125/android-enable-disable-bluetooth – Jesh Kundem Mar 30 '17 at 15:33
  • @AlexLockwood : I'm trying to do something before the BT is turned off but the problem is that registering ACTION_BOND_STATE_CHANGED does not detect changes in case I turn off the BT; but if I register ACTION_ACL_DISCONNECTED, it will trigger onReceive but it is too late!!!...Can anyone of you help me with what is wrong? – msc87 May 21 '18 at 09:49
-3
public void discoverBluetoothDevices(View view)
    {
        if (bluetoothAdapter!=null)

            bluetoothAdapter.startDiscovery();
            Toast.makeText(this,"Start Discovery"+bluetoothAdapter.startDiscovery(),Toast.LENGTH_SHORT).show();
    }
HansHirse
  • 18,010
  • 10
  • 38
  • 67