I tried to connect my phone to a BLE heart-rate monitor yesterday.
I could see the device in the bluetooth settings and pairing didn’t work from there (that is the correct behaviour).
But the three apps I tried didn’t manage to find the device.
I’m trying to get more information on this isssue over the next days.
Has anybody tried this yet? Did it work?
Edit: Both BLExplorer and iBeaconDetector (both on F-Droid and on Google Play) detect a device, but I’m not sure if it’s the right one. BLExplorer does connect to a device but doesn’t return any information about it.
Edit 2:
iBeaconDetector was able to find the device.
BLExplorer was able to find the device and list its capabilities (but not read the concrete values).
I took a closer look at one of the apps I tried - RunnerUp. And I noticed these lines:
static boolean AVOID_SCAN_WITH_UUID = false;
static boolean CONNECT_IN_OWN_THREAD_FROM_ON_LE_SCAN = false;
static {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2) {
// 4.3
AVOID_SCAN_WITH_UUID = true;
CONNECT_IN_OWN_THREAD_FROM_ON_LE_SCAN = true;
}
}
So, Android 4.3 seems to be lacking certain features.
I replaced this with the following:
static boolean AVOID_SCAN_WITH_UUID = true;
static boolean CONNECT_IN_OWN_THREAD_FROM_ON_LE_SCAN = false;
And scanning for devices does work now.
Connecting does not.
So, what I’ve learned so far:
- BLE devices have an ID and capabilities.
- Apps can search for BLE devices.
- They can add filters to scan only for BLE devices for certain capabilities.
- The BLE stack in this ROM doesn’t support those filters.
The real solution would be to make filtering work.
The quick and dirty solution would be to simply ignore any filters set by apps in android.bluetooth.BluetoothAdapter
:
public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) {
serviceUuids = null;
[…]
This could be made into an XPosed module easily, I guess. Maybe.
I’ll try setting the next variable to true
.
Edit 3: Here’s the XPosed module:
The code is really just this:
findAndHookMethod("android.bluetooth.BluetoothAdapter", null, "startLeScan", UUID[].class, LeScanCallback.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable
{
param.args[0] = null;
}
});
Edit 4: I’ve tried setting the second variable to true
. It didn’t help the connection.
So, the things I’ve learned so far:
- The FP1 does have BLE support. It just doesn’t work the way it should.
- Scanning for devices works mostly (eg. BLExplorer or iBeaconDetector or RunnerUp after the mentioned modification).
- Filtering does not. Many apps know that and don’t bother setting a filter (eg. adidas train & run or Runtastic).
- Discovering the services / properties a BLE device has works (eg. BLExplorer or RunnerUp).
- Connecting to a BLE device does not.
- Scanning for a BLE device does not work from some apps (eg. adidas train & run or Runtastic - the former one calls
startLeScan
very often).
Edit 5: What does happen when using RunnerUp is this:
- Enable Bluetooth.
- Scan.
- Found a device.
- Stop scan.
- Connect to the device.
- Connected.
- Start service discovery.
- Disconnected. (Should be “Discovered services.”.)
BLExplorer is able to list the services.
Edit 6: I bought a relatively cheap beacon.
BLExplorer is able to find the device and list its services. It is also able to read the values of one service per connection. (So I have to close the app and reopen it to read all services.)
The app made specifically for this device (Gigaset G-tag app) was able to find and connect to the device at the third attempt but lost the connection after about one minute.
Sometimes, the app Bluetooth-Freigabe (I don’t know its English name nor its package name, yet, sorry) crashes (I don’t have a stacktrace yet). No devices are being found afterwards until the next reboot.
Edit 7: This G-tag seems to work mostly. Sometimes, there are disconnects, but it reconnects very quickly. This is good, but doesn’t help with my heart rate monitor.
And I got a stack trace from the crashes of com.android.bluetooth
somewhere in my logs. I just need to find it…
Edit 8: Here’s a stack trace:
E/[Bluetooth.OPP]BtOppRfcommListener(13444): Error accept connection java.io.IOException: read failed, socket might closed or timeout, read ret: -1
E/MTKBT (13444): [Session]the session[61458][13444] is not ready to monitor
E/MTKBT (13444): [Session]no any more session is in list
E/Bluetooth Transport(22023): Socket Type: Secureaccept() failed
E/Bluetooth Transport(22023): java.io.IOException: read failed, socket might closed or timeout, read ret: -1
E/Bluetooth Transport(22023): at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:508)
E/Bluetooth Transport(22023): at android.bluetooth.BluetoothSocket.waitSocketSignal(BluetoothSocket.java:485)
E/Bluetooth Transport(22023): at android.bluetooth.BluetoothSocket.accept(BluetoothSocket.java:398)
E/Bluetooth Transport(22023): at android.bluetooth.BluetoothServerSocket.accept(BluetoothServerSocket.java:131)
E/Bluetooth Transport(22023): at android.bluetooth.BluetoothServerSocket.accept(BluetoothServerSocket.java:117)
E/Bluetooth Transport(22023): at ewa.run(SourceFile:432)
E/CellLocation(14358): create GsmCellLocation
E/BluetoothRemoteDevices(13444): aclStateChangeCallback: Device is NULL
E/BluetoothTethering(12657): attempted to stop reverse tether with nothing tethered
E/bt_ext_apis.c(13444): create bt.ext.adp.hfp external socket failed : Address already in use, errno=98!
And here is the crash:
E/AndroidRuntime(13444): FATAL EXCEPTION: BluetoothAdapterState:
E/AndroidRuntime(13444): Process: com.android.bluetooth, PID: 13444
E/AndroidRuntime(13444): java.lang.NullPointerException
E/AndroidRuntime(13444): at com.android.bluetooth.btservice.RemoteDevices$DeviceProperties.access$400(RemoteDevices.java:100)
E/AndroidRuntime(13444): at com.android.bluetooth.btservice.RemoteDevices.sendUuidIntent(RemoteDevices.java:219)
E/AndroidRuntime(13444): at com.android.bluetooth.btservice.RemoteDevices.access$1000(RemoteDevices.java:37)
E/AndroidRuntime(13444): at com.android.bluetooth.btservice.RemoteDevices$1.handleMessage(RemoteDevices.java:455)
E/AndroidRuntime(13444): at android.os.Handler.dispatchMessage(Handler.java:110)
E/AndroidRuntime(13444): at android.os.Looper.loop(Looper.java:193)
E/AndroidRuntime(13444): at android.os.HandlerThread.run(HandlerThread.java:61)
Edit 9: The system does return devices when an app scans for them (unless there’s a filter set). But many apps don’t display any found devices.
Edit 10: I tried going back to pre2. It’s basically the same.
Edit 11: I tried going back to the unofficial 4.4.4 build. It’s the same.
Scanning takes very long and eventually finds the correct device. But it takes a few attempts. Even if the two devices are directly near the phone.
I guess many apps run into a timeout before.
Improving the scanning process would be nice. (But not that important. We didn’t have BLE in 4.2 - now we have it but it doesn’t work.)