I am developing an Android app (API 23+) that communicates via BLE with a device. There is no pairing / bonding involved.
The happy path of the interaction is that the app connects then sends a message to the device, and the device in turn sends a reply back, then they both disconnect.
While characterizing strange behavior I asked in Android BLE unexpectedly reconnects potentially from PBAP / MAP Bluetooth profiles, I created a simple service to monitor low-level bluetooth connections; it listens for broadcasts of BluetoothDevice.ACTION_ACL_CONNECTED and BluetoothDevice.ACTION_ACL_DISCONNECTED.
While most of the time the connect / disconnect corresponds well between app and device, sometimes the app receives a disconnect notification that can be ~5-20 seconds after both the app and device have closed the connection. I have verified that the device actually closed, and the app logs all show the system properly shutting down the connection.
In these instances, if the app tries to connect again with the device before ACL_DISCONNECTED is broadcast, it will either receive an error or the subsequent connect request is queued and kicked off after the ACL_DISCONNECTED broadcast.
This does not seem to be specific to devices --- I test with a variety of makes and models --- nor the API version (23-25).
Is this known (expected) behavior?
Are there ways to mitigate this issue?...to ensure the disconnect indeed happens in a timely manner?
Is there a more direct way --- e.g., through an API call --- to tell if the connection is still up, as opposed to receiving ACL-related broadcasts?
If the BLE devices stops broadcasting instead of sending disconnect signal this issue happens. If the BLE device didn't send the disconnect signal Android device thinks the that the connection is open and it waits for sometime (5-20 sec) and then calls onconnectionstatechange() with time out status code. If you can make the BLE device send the disconnect signal instead of stop broadcasting it should fix the issues. Hope this helps
Related
I am building a UDP-based audio streaming system and face a weird behavior with two different Android devices, that I do not understand at all.
I have a server broadcasting UDP packets on my local WiFi to 192.168.178.255. The Android app listens to these broadcasts using a DatagramSocket and receives the packets just fine. A MulticastLock has been acquired, but the app stays in the foreground, so this shouldn't matter.
However, after a seemingly random amount of time (around a few minutes) the app stops receiving the broadcasts. Weirdly enough, this does not only affect my own app, but also any third-party tools which can listen to UDP broadcasts. UDP packets addressed specifically to the device are still received. The device will no longer receive any broadcasts until I disable and re-enable the wifi connection.
What's even more weird: The test packets I send have a sequence number, so I can keep track of the last packet the device has received. I am running this test on two different devices (a Huawai FIG-LX1 phone and a Fire-Tablet) and the devices stop receiving packets at EXACTLY the same packet. I am looking at the network traffic on Wireshark and I can see nothing special about this packet or anything happening on the network.
Any ideas what may be killing broadcast reception on two completely different devices in this way?
Unfortunately neither of the devices are rooted, so I cannot run a network analyzer directly on the device, to determine if -for example- the router might not be forwarding the packets anymore.
I am trying to make an app, that when it sees a specific bluetooth device to connect to it and send a command and before loose that connection to send another command.
The device is standard bluetooth serial device.
Is there a way to check when i am going to loose the connection?
No unfortunately Bluetooth doesn't work this way. You are usually notified that the remote device disconnected and you can even get the disconnection reason (e.g. BT_HCI_REMOTE_USER_TERMINATED_CONNECTION), but by then it is already too late and the link between your device and the remote device is already lost. Generally speaking, the way a disconnection works is that there are empty Bluetooth packets sent back and forth between the two devices (similar to an ACK) to indicate that the link is alive. If that packet does not arrive after a certain timeout, the BLE stack throws an event to the application notifying it that the connection has been lost (i.e. a disconnection event).
If you are using Bluetooth Low Energy, and if you are in control of both devices (your one and the remote one), then you could implement additional communication on the advertising channels. This is not as efficient as performing the communication through a connection, but you can advertise this additional command upon disconnection, and the remote device would scan for this new command upon disconnection as well.
I hope this helps.
I'm working on an Android app that communicates with a custom bluetooth device. After calling BluetoothGatt.Disconnect() I am seeing that the OnConnectionStateChange callback is called, and the new state is Disconnected, however, there seems to be a lag between when that happens and when the Device itself is actually disconnected. For example, if I call BluetoothManager.GetConnectionState(...) with the device that was connected, it still returns Connected. Sometimes it takes several seconds before GetConnectionState returns Disconnected. Is this normal? Is it possible that I am doing something wrong in my application that could be causing this? e.g. disconnecting from a non-UI tread, or something like that? Or, is it possible that the physical bluetooth device itself is not handling the disconnect properly and maybe not completing the disconnect event promptly?
Android's BLE system is so messed up. I've seen what you've described, except much worse - where you disconnect from Android, but under the hood it maintains a persistent connection with your peripheral.
Usually takes 30 seconds to finally disconnect, sometimes takes minutes! All depending on which phone you were using at the time.
If you have the ability, I highly recommend adding a disconnection characteristic to the peripheral, so that you actually disconnect by writing a disconnection request, and letting the peripheral force the disconnection - and then Android will pick it up.
The benefit I've seen is that it ALWAYS works (because a 'hard' disconnection is always picked up by Android, whereas a 'soft' disconnection request can cause some issues on certain phones). Typically 'good' phones don't exhibit this behaviour (especially Marshmallow and on), but back in those KitKat days.... Wow....
Another benefit... If you're using iOS, you can scan for or re-connect to disconnected peripherals much faster.
When you call "disconnect()" you only disconnect your client object (BluetoothGatt object). You can have multiple BluetoothGatt objects connected to the same physical device. Multiple apps can also have own BluetoothGatt objects connected to the same device.
As soon as you call "disconnect()" the request is processed in the Bluetooth stack in the system and it immediately then calls the onConnectionStateChange callback in your app when it has completed processing the request. However, it will not disconnect the link until all other clients have disconnected. Newer versions of Android also delay the physical disconnection a few seconds (not sure why). Also, once the disconnect request has been sent to the Bluetooth controller it may take some time to actually disconnect since the remote device needs to acknowledge the disconnection (or time out). The default time out was 20 seconds until it was recently changed to 5 seconds in the latest Android version.
I am working on an application where we will have a BLE peripheral with a button, and an App running on an Android phone. The user will manually pair the peripheral with the phone, and then the phone may go into standby, or be used for other purposes.
Can a button press on the BLE peripheral cause the phone to wakeup and open the App?
On a related note, if the phone is power cycled, can it be configured to automatically re-pair with the peripheral, without requiring any user action?
If the peripheral is power cycled, can it automatically re-pair with the phone, without requiring any user action?
All the answers are YES , with some custom algorithms.
However I have to remind that in Android 4.3, connecting without user interaction is extremely dangerous. Android 4.3 cannot cancel any outgoing connection due to a bug, and no callbacks for connection time out. If the peripheral goes out of range/ runs out of battery / simply malfunctions during the connection, the Bluetooth stack of your phone will just STUCK until you reboot your phone.
If the connection is initiate by the user in the ui we can alert the user when it gets wrong, but if you start connection in the background automatically you may risk in breaking the Bluetooth without user understanding whats going on.
Using both Android 4.3/Samsung BLE 2.0 SDK, it is observed that when a peripheral is turned off, the SDK will receive onConnectionStateChange (DEVICE_DISCONNECTED) either immediately or after ~20s delay. From my experience this depends on the peripheral implementation, some of them will tried to report they are being turned off and some just doesn't, so the SDK have to wait for ~20s for the timeout.
To remove this behaviour, I tried to use a Timer to check if I can read a certain characteristic. If the read timed out, I will call disconnect(Android 4.3)/cancelConnection(Samsung) to terminate the connection. The call itself is successful and the onConnectionStateChange callback return a status GATT_SUCCESS. Then I turned the peripheral on and connect to it immediately, discover the services , and encounter problem when I tried to read/write/notify any notification. By using LightBlue in iOS I can confirm that the peripheral is not connected.
After exactly 20s from turning off the peripheral, I will receive a DEVICE_DISCONNECTED callback. I connect again afterwards, and everything operates just fine.
There are two question :
1. Are we supposed to connect to the peripheral during the 20s delay?
2. Is there any way to get notified when a peripheral is turned off?
Thanks in advance.
Are we supposed to connect to the peripheral during the 20s delay?
No, It seems from you result itself that OS is doing some actions within the phone to control DEVICE_CONNECTED or DEVICE_DISCONNECTED events, This may be due to several reasons like device architecture, security reasons or callback itself is delayed to save energy
Is there any way to get notified when a peripheral is turned off?
No I dont think so, The event received for any action is broadcasted so its waiting for a signal from the device it self but its not getting one, the only thing that you can do here is to send it via some other broadcast(or HTTP request) from the other end of the device to achieve it