Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't receive data via BLE on Android 14 #600

Open
siroaleksi opened this issue Nov 7, 2024 · 7 comments
Open

Can't receive data via BLE on Android 14 #600

siroaleksi opened this issue Nov 7, 2024 · 7 comments
Labels

Comments

@siroaleksi
Copy link

siroaleksi commented Nov 7, 2024

I have created Jetpack compose Android application which connects to a BLE device. BLE device updates its state and sends data to the app. Previously I have used Android 11 device and now I have updated my device to one that has Android 14.

I'm facing problem when trying to send data to app with Android 14. I'm using v2.9.0. On Android end, I receive characteristic changes like this:

    private val dataReceiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            val action = intent!!.action
            Log.i(tag, "This is the action $action")
            try {
                when (action) {
                    bluetoothManager.actionConnected -> {

                    }
                    bluetoothManager.actionDisconnected -> {

                    }
                    bluetoothManager.actionDataAvailable -> {

                    }
                    bluetoothManager.actionInfoAvailable -> {

                    }
                    bluetoothManager.actionError -> {
                       
                    }
                }
            } catch (e: Exception) {
                Log.e(tag, "onReceive ${e.stackTraceToString()}")
            }

When using exactly same code (excluding BLE permissions), with Android 11, I receive data normally and in the Log I get "This is the action ACTION_DATA_AVAILABLE" as expected. With Android 14 I get status updates e.g. "This is the action CONNECTED" and "This is the action DISCONNECTED" but for some reason it doesn't register "This is the action ACTION_DATA_AVAILABLE". When changing back to phone with Android 11 everything works as expected. I have also verified that code works with Android 12. Problems occurs now only with Android 14.

What might cause this? Are there some sort of security things that I need to take into account etc.?

@philips77
Copy link
Member

Hello,
Are you getting the data over BLE successfully on both phones? Is it just that your broadcasts aren't delivered?

Could you show the relevant BleManager implementation and logs from the log(level, message) method (you may override such in the manager and print to console.

@siroaleksi
Copy link
Author

siroaleksi commented Nov 8, 2024

Hi, I looked that the callback method for data receiving isn't triggered with Android 14. In override fun initialize I have enabled notifications for txCharacteristic like .add(enableNotifications(txCharacteristic)) and set call back like setNotificationCallback(txCharacteristic).with(txReadCharacteristic)

The txReadCharacteristic I have init like this

    private val txReadCharacteristic =
        DataReceivedCallback { _, data ->
            Log.i(tag, "DataReceivedCallback txReadCharacteristic")
            broadcastUpdate(actionDataAvailable, data.value!!)
        }

For setting characteristic notification I get: setCharacteristicNotification() - uuid: txUUID enable: true in the Log.

With Android 11 and 12 the txReadCharacteristic DataReceivedCallback is triggered.

@siroaleksi
Copy link
Author

siroaleksi commented Nov 8, 2024

I have previously requested MTU size of 247 like this:

beginAtomicRequestQueue()
   .add(
       requestMtu(requestMtuSize)!! // Remember, GATT needs 3 bytes extra. This will allow packet size of 244 bytes.
          .with { _: BluetoothDevice?, mtu: Int ->
               Log.d(tag,"Requesting MTU: $mtu")
           }
           .done {
               Log.d(tag,"MTU set to $mtu")
                   currentMtu = mtu
                }
           .fail { device: BluetoothDevice?, status: Int ->
                Log.d(tag, "Requested MTU not supported: $status")
           }
   )

where requestMtuSize = 247. When I changed this to 23

private val txReadCharacteristic =
    DataReceivedCallback { _, data ->
        Log.i(tag, "DataReceivedCallback txReadCharacteristic")
        broadcastUpdate(actionDataAvailable, data.value!!)
    }

started working. I'd like to stick with old 247 for faster data transfer.

I'm btw using nrf52 development kit for testing.

@philips77
Copy link
Member

What device are you using for testing on both Android versions?

We are aware, that e.g. Samsuns Tab A8 (and perhaps other devices with the same controller) does not work with MTU > 23 due to a bug on the device side. It claims, that can only send LL packets with 27 bytes (that's 20 bytes of data), but then sends long ones. The issue is during feature negotiation, it should claim that Data Length Extension (DLE) is supported and both TX and RX are 251, while it claims 27 for TX. The peripheral side disconnects when getting too long packet, which is compliant with the spec.

@philips77
Copy link
Member

I suggest you try with other devices with Android 14 or 15, like the Pixel family.

@siroaleksi
Copy link
Author

Currently I have tested with Samsung Galaxy a15 5g (Android 14) and OnePlus Nord N100 (Android 11). I'll try with other Android 14 device.

@siroaleksi
Copy link
Author

siroaleksi commented Nov 15, 2024

I finally managed to test with other device, Honor 200 Smart. Same problem remains.

I took a look the MTU negotiation and it seems that even though I request MTU = 247 and on Android side in log I get :

I  request MTU size of 247
D  configureMTU() - device: XX:XX:XX:XX:31:2A mtu: 247
D  onConfigureMTU() - Device=XX:XX:XX:XX:31:2A mtu=247 status=0
D  MTU set to 247

MTU value is set to 517. On embedded side I have mtu update callback like this:

void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) {
    LOG_INF("Updated MTU: TX: %d RX: %d bytes", tx, rx);
	MTU_SIZE = tx - 3;
}

Here it says that tx has been set to 517. I tried this with various other MTU sizes and it is always set to 517 when using Android 14.

After googling and reading https://developer.android.com/about/versions/14/behavior-changes-all#mtu-set-to-517 it seems that in Android 14, device always first request 517.

As the max MTU size in nrf52832 is 247, shouldn't the MTU negotiation end up that so that we should use MTU = 247? I made this fix into embedded code and now I'm able to receive 244 BLE packet sizes.

void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) {
    LOG_INF("Updated MTU: TX: %d RX: %d bytes", tx, rx);
	if (tx >= 247) 
		tx = 247;
	MTU_SIZE = tx - 3;
}

All in all the problem seems to be now on how BLE is handled in Android 14+?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants