Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't cancel Bluetooth discovery process

I need to do a scan of bluetooth devices in the surrounding area for 6 to 12 seconds. After this time I need to stop the discovery of new devices.

The following code should:

  • Start scanning for bluetooth devices
  • Print out any which are found
  • After 6 seconds, cancel all discovery and repeat process

The problem is that the bluetooth discovery is never cancelled. After this code runs for a minute or two, onReceive will get called tens of times in the same second...

public void startTrackingButton(View view) {
        Log.d("MAIN", "Track button pressed, isTracking: " + !isTracking);
        if (isTracking) {
            isTracking = false;
        } else {
            isTracking = true;

            Thread keepScanning = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (isTracking) {
                        if (mBluetoothAdapter.isDiscovering()) {
                            Log.d("MAIN", "Cancelling discovery!");
                            Log.d("MAIN", String.valueOf(mBluetoothAdapter.cancelDiscovery() + ":" + mBluetoothAdapter.getState()));
                            mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
                        }
                        startTracking();
                        try {
                            Thread.sleep(6000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            });
            keepScanning.start();
        }
    }

private void startTracking() {

    Log.d("MAIN", "Starting Discovery...");
    mBluetoothAdapter.startDiscovery();
    // Create a BroadcastReceiver for ACTION_FOUND
    BroadcastReceiver mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            Log.d("MAIN", "Device Found...");
            String action = intent.getAction();
            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent
                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // Add the name and address to an array adapter to show in a
                // ListView
                Log.d("MAIN:",
                        device.getName() + "\n" + device.getAddress());
            }
        }
    };

    // Register the BroadcastReceiver
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    registerReceiver(mReceiver, filter); // Don't forget to unregister
                                            // during onDestroy
}

Here is my logcat output:

//onReceive gets called many times in the same second???
05-01 22:09:56.949: D/MAIN(3757): Cancelling discovery!
05-01 22:09:56.969: D/MAIN(3757): false:12              ///THIS SHOULD BE TRUE
05-01 22:09:56.969: D/MAIN(3757): Starting Discovery...
05-01 22:10:03.009: D/MAIN(3757): Starting Discovery...
05-01 22:10:03.579: D/MAIN(3757): Device Found...
05-01 22:10:03.579: D/MAIN:(3757): TOMSELLECK
05-01 22:10:03.579: D/MAIN:(3757): 06:07:08:09:A1:A1
05-01 22:10:03.579: D/MAIN(3757): Device Found...
05-01 22:10:03.579: D/MAIN:(3757): TOMSELLECK
05-01 22:10:03.579: D/MAIN:(3757): 06:07:08:09:A1:A1
05-01 22:10:03.589: D/MAIN(3757): Device Found...
05-01 22:10:03.589: D/MAIN:(3757): TOMSELLECK
05-01 22:10:03.589: D/MAIN:(3757): 06:07:08:09:A1:A1
05-01 22:10:03.589: D/MAIN(3757): Device Found...
05-01 22:10:03.589: D/MAIN:(3757): TOMSELLECK
05-01 22:10:03.589: D/MAIN:(3757): 06:07:08:09:A1:A1
05-01 22:10:03.589: D/MAIN(3757): Device Found...
05-01 22:10:03.589: D/MAIN:(3757): TOMSELLECK
05-01 22:10:03.589: D/MAIN:(3757): 06:07:08:09:A1:A1

Does anybody know how I can properly cancel all current and pending Bluetooth discovery??

Thanks for your help!

P.S The reason I need to repeat the process is to get fresh signal strength values from nearby devices.

like image 255
TomSelleck Avatar asked May 01 '13 21:05

TomSelleck


People also ask

How do I block Bluetooth on my Android?

It's also easy to disable Bluetooth from the Settings app, but it takes a few more taps. To do it, open Settings and navigate to Connected Devices > Connection Preferences > Bluetooth and turn off the switch beside “Use Bluetooth.”

How do I make my Bluetooth undiscoverable?

Tap Settings. Tap Bluetooth. Tap the indicator next to "Bluetooth" to turn the function on or off. Tap the indicator next to "Open detection" to turn Bluetooth visibility on or off.

What is BluetoothAdapter in Android?

The BluetoothAdapter lets you perform fundamental Bluetooth tasks, such as initiate device discovery, query a list of bonded (paired) devices, instantiate a BluetoothDevice using a known MAC address, and create a BluetoothServerSocket to listen for connection requests from other devices, and start a scan for Bluetooth ...


2 Answers

Every time you call startTracking(), you create and register another BroadcastReceiver. Thus, after you have called startTracking() ten times, you have ten receivers waiting for devices. Once a device is found, all these receivers get notified, which explains why you get so many log entries.

Regarding cancelDiscovery returning false, the bluetooth code of Android is probably its most buggy part. Look what I found. Never assume anything related to Bluetooth on Android will work correctly across different versions and devices. For debug purposes, you can add a listener for BluetoothAdapter.ACTION_DISCOVERY_FINISHED. Maybe isDiscovering() will return false after cancelling, but I could imagine there being a short delay between the cancel request and isDiscovering() returning false.

YOUR PERSONAL BUG RECOMMENDATIONS Customers who encountered this bug also enjoyed:

  • Some devices ignore EXTRA_DISCOVERABLE_DURATION and can only enable discoverability for 120 seconds. This should be fixed by 2.3.6, but I saw it happen on a Samsung Galaxy Ace with 2.3.6, so maybe Samsung broke it or it wasn't fixed after all. Doesn't happen on my 4.x devices though.
  • Should you actually create connections, some Android versions will cause pairing dialogs even on insecure connections. Attempting to connect to an unknown service on 4.2 will do this, too.
  • Sometimes, Bluetooth just breaks, making it impossible to connect until reboot (may be related to not cleanly shutting down connections when the application crashes or is killed during testing, my gut feeling is that it runs out of some kind of file-descriptor-style resources).
  • Service discovery may be unreliable.

Also note: Since you use Thread.sleep, the thread will probably pause more than 6 seconds of real time, since time as measured by Thread.sleep stops when the CPU sleeps. Depending on how the device behaves while scanning, this may be much more than 6 seconds. If you want to use real-time based timing, you will have to use an AlarmManager, which unfortunately is a pain in the ass - you will probably want to write a thin wrapper for it.

like image 183
Jan Schejbal Avatar answered Oct 20 '22 05:10

Jan Schejbal


I don't recommend canceling discovery. This is buggy in Android. On the Nexus 4's I have, canceling sometimes causes bluetooth to be disabled until a reboot and in some of the worst cases until a factory reset. I recommend letting discovery finish and then restarting as soon as it is over.

Discovery doesn't take long anyway, although it varies based on the number of devices seen durring discovery. Here's a scan with 8 devices:

05-07 16:47:53.655: I/MANAGER:BluetoothManager(22019): Bluetooth Discovery Starting...
05-07 16:48:13.687: I/MANAGER:BluetoothManager(22019): Bluetooth Discovery Finished...

Note that if you run discovery all the time you will drain the battery pretty fast.

like image 20
Nick Palmer Avatar answered Oct 20 '22 06:10

Nick Palmer