Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android 4.3 Bluetooth Low Energy unstable

People also ask

How do I turn off Bluetooth Low Energy Android?

Users can disable system-level Bluetooth background scanning by going to Settings > Security & Location > Location > Scanning and disabling the toggle for Bluetooth scanning.

What is Bluetooth Low Energy in Android?

Android provides built-in platform support for Bluetooth Low Energy (BLE) in the central role and provides APIs that apps can use to discover devices, query for services, and transmit information. Common use cases include the following: Transferring small amounts of data between nearby devices.

Is Bluetooth optimal for low power devices?

Bluetooth Classic is not optimized for low power, but has a higher data rate. Meanwhile, Bluetooth LE, as its name suggests, is meant for low-power, low-duty data cycles.


Important implementation hints

(Perhaps some of those hints aren't necessary anymore due to Android OS updates.)

  1. Some devices like Nexus 4 with Android 4.3 take 45+ seconds to connect using an existing gatt instance. Work around: Always close gatt instances on disconnect and create a fresh instance of gatt on each connect.
  2. Don't forget to call android.bluetooth.BluetoothGatt#close()
  3. Start a new thread inside onLeScan(..) and then connect. Reason: BluetoothDevice#connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) always fails, if called inside LeScanCallback() {...}.onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) in the same thread on Samsung Galaxy S3 with Android 4.3 (at least for build JSS15J.I9300XXUGMK6)
  4. Most devices filter advertising
  5. Better not use android.bluetooth.BluetoothAdapter#startLeScan(UUID[] serviceUuids, LeScanCallback callback) with the parameter to filter for certain service UUIDs because this is broken completely in Samsung Galaxy S3 with Android 4.3 and doesn't work for 128bit UUIDs in general.
  6. Gatt always can process one command at a time. If several commands get called short after another, the first one gets cancelled due to the synchronous nature of the gatt implementation.
  7. I often see even on modern devices with Android 5, that Wifi interferes withs bluetooth and vice versa. As a last resort, turn off wifi to stabilize bluetooth.

Tutorial for beginners

A pretty OK entry point for newcomers could be this video tutorial: Developing Bluetooth Smart Applications for Android http://youtu.be/x1y4tEHDwk0

The issue and work around described below is probably fixed now by OS updates

Work around: I could "stabilize" my app doing that...

  1. I provide the user a setting "Restart Bluetooth". If that setting is enabled, I restart Bluetooth at some points that indicate the begin of BLE stack becoming unstable. E.g. if startScan returns false. A good point may also be if serviceDiscovery failes. I just turn Bluetooth off and on.
  2. I provide another setting "Turn off WiFi". If that setting is enabled, my app turns off Wifi when the app is running (and turns it back on afterwards)

This work around is based on follwoing experiences...

  • Restarting Bluetooth helps to fix problems with BLE in most cases
  • If you turn off Wifi, the BLE stack gets much more stable. However, it also works fine on most devices with wifi turned on.
  • If you turn off Wifi, restarting Bluetooth fully recovers the BLE stack without the need to reboot the device in most cases.

Turning WIFI OFF:

I can confirm too, that turning WIFI OFF makes Bluetooth 4.0 more stable especially on Google Nexus (I have a Nexus 7).

The problem

is that the application I am developing needs both WIFI and continous Bluetooth LE scanning. So turning WIFI OFF was no option for me.

Moreover I have realised is that continous Bluetooth LE scanning can actually kill WIFI connection and make the WIFI adapter unable to re-connect to any WIFI network until BLE scan is ON. (I'm not sure about mobile networks and mobile internet).
This definitely happened on the following devices:

  • Nexus 7
  • Motorola Moto G

However BLE scanning with WIFI on seemed pretty stable on:

  • Samsung S4
  • HTC One

My workaround

I scan BLE for a short period of time 3-4 seconds then I turn scan OFF for 3-4 seconds. Then ON again.

  • Obviously I always turn BLE scan OFF when I'm connecting to a BLE device.
  • When I disconnect from a device I restart BLE (turn adapter OFF and then ON) to reset the stack before starting scan again.
  • I also reset BLE when discovering services or characteristics fails.
  • When I get advertisement data from a device that the app should connect to (lets say 500 times without being able to connect - thats about 5-10 seconds of advertising) I reset BLE again.

Make sure your Nexus is paired to the device. I can't verify whether or not the communication works properly, but you will be able to connect more than once without a reboot. It seems the first connect is not requiring pairing but all subsequent attempts do.

I will update this answer in a couple of days when I test service discovery and gatt read and write requests without a reboot.

EDIT: It turns out I was testing on a development firmware version (our sensor) that was causing issues if not paired. Our latest production firmware build works fine on the 2540s and 2541s.

EDIT: I did notice that on the Nexus 7 2013, connections are more stable when WiFi is turned off. I'd like to know if this helps anyone else.

EDIT: I seem to have had it backwards with pairing. Everything works fine when not paired. After pairing, I am experiencing the exact same symptoms as the OP. It's just not known yet if this is related to our firmware or the Android BLE API. Be careful if testing this because once paired, you may not be able to unpair due to a bug explained in 3b of this post.


In some models there is a defect: https://code.google.com/p/android/issues/detail?id=180440

On the other hand in my case the problem was, that my connection was not properly closed in onDestroy method. After correct closing, problem for me is not existing, not matter that wifi is turned on or off.

btGatt.disconnect();
btGatt.close();

I was facing a similar issue. My fix was

if (Build.VERSION.SDK_INT >= 23) {
  mBluetoothGatt = device.connectGatt(this, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
} else {
  mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
}

& calling close after disconnect.