I bought myself a smartwatch that has Android KitKat running.
I have connected it to my HTC m9 smartphone using Bluetooth.
I have created an application that is running on both smartwatch(client mode) and smartphone(server mode).
The applications are talking each other over a Bluetooth Socket connection.
When I get a phone call on my phone, I am sending a Bluetooth notification over the Bluetooth socket to the watch and make it vibrate.
All is good as long as the watch's CPU is up and running.
When the watch goes to sleep, and I get a phone call on the smartphone, the notification is not processed by the watch because watch's CPU is sleeping.
Using a partial lock on the watch does the thing but it consumes the battery to fast.
I don't need a partial lock on the phone, because when the phone receives a call, the phone is "magically" awaken, so my application's service is able to send the notification.
I also can't use AlarmManager on the watch, because I need the watch to wake up when I get a bluetooth socket notification, not on regular intervals.
A WakefullRecevier is also not solving the problem because my watch needs to wake up first so that the WakefullReceiver puts the power lock (or have I got this wrong ?!) and runs its code.
So the question is: How does the phone wake up on incoming call? Or on SMS received? It is a hardware thing..an interrupt?
Is there any way of waking up the watch when a bluetooth message is received?
Thank you
For the past few days I've been playing around with the watch making different tests.
I am not answering the original question but since nobody else answered the question I will just write down my own conclusions which are good enough for my application and maybe help others with similar problems.
1. When the paired watch is in Bluetooth range of the phone, a power lock is not needed on the watch.
Any messages sent by the phone are received by the watch.
If the watch stays idle for some time, the 1st Bluetooth message sent by the phone is received with about 1 second delay. Probably Android watch goes into some kind of low power mode but is able run my code when Bluetooth message is received. Of course Bluetooth messages are received almost immediately by the watch while the watch is not idle.
2. Best way to find out if a Bluetooth socket is still connected, is to write into it.
Socket read is a blocking call but it does not throw IOException when watch goes out of Bluetooth range. I wasn't able to find a read timeout property I can change.
So I am just writing a byte into the socket every 60 seconds to detect if socket is not connected anymore. Battery impact is minimum while socket down detection timing is acceptable.
3. When the paired watch is NOT in Bluetooth range of the phone anymore, Bluetooth socket re-connect strategy is required.
Using a partial lock in this case does not seem like a good approach since it keeps the CPU awake. Also trying to re-connect to often to the phone kills the battery.
The re-connect strategy is based on application needs.
I ended up using WakefulBroadcastReceiver and AlarmManager to make a socket connect attempt with a given period.
4. Every now and then, when the watch goes out of Bluetooth range, then comes back into range, then again and again the Bluetooth socket seems to go in some kind of 'zombie' state. Sometimes the socket.connect call just blocks without succeeding or throwing error, some other times the socket.connectcall does not throw error given the impression that connection has been established, but a subsequent write always throws IOException.
Whenever I encounter these kinds of situations I just stop/start Bluetooth adapter which seems to solve the problem.
5. Pay attention to stop/start the Bluetooth adapter. During Bluetooth restart attempt Android can put the CPU to sleep. I wasn't expecting this behavior but it really happens. So if you want to do this as fast as possible without any delay, make sure the application acquires a PARTIAL_WAKE_LOCK during the re-start attempt. Of course don't forget to release the lock as soon as possible.
Related
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 have a permanently running service app on the handset, one of the things it does is detect when there is an incoming phone call and send a message and some data to a companion app on a wearable device.
I'm wondering whether the app should establish the API to communicate with the wearable when it launches, or only when there is an incoming call and then disconnect afterwards.
Has anybody with wear development experience got any pros or cons of these approaches?
The service automatically starts at device start-up, and I've noticed if an attempt is made to create the GoogleApiClient/Wearable.API and get the wearable device node soon after rebooting there's a high chance of failure, therefore a disadvantage of establishing the wearable connection at app launch is its probably fail and will need to re-try or wait etc.
In general, to save on battery life, you want to minimize usage of any network connection on a mobile device. The general rule of thumb is: establish a connection only when needed, if you expect to use it again "soon" (e.g. within a minute or so), then keep it around, and close the connection when you are not going to use it for a longer while.
So in your case, since you are responding to phone calls (which should not happen every couple of minutes!), you should re-establish the connection every time. I am not sure though about the delay incurred in this case.
I'm looking for a way to detect the disconnection of a Bluetooth device immediately after it has happened (2 second max), typically in a "device too far" scenario or Device battery is dead. Currently I can detect it with a BroadcastReceiver by getting a BluetoothDevice.ACTION_ACL_DISCONNECTED, but it takes about 16 to 20 seconds to fire.
Is there any way to get notified in 2 seconds Max.
I used BroadcatReceiver but it is not fast enough to get alert in 2 seconds Max, so is there any other kind of approach available to get notification quickly that bluetooth is disconnected.
I use this createRfcommSocketToServiceRecord(UUID); to connect a paired device and i am bound to use it using UUID.
I have visited a lot of links regarding this issue, but no one matches with my needs.that's why any help would be appreciated.
thanks.
I think the only way you can reliably sense loss of connection quickly (within two seconds) is via your own application protocol that you use over the Bluetooth connection. For example, your application protocol might implement a heartbeat that occurs every 500ms. If you don't see a heartbeat within two seconds then you could trigger your own event.
Bluetooth is a socket-based stream protocol that is designed to work over an unreliable medium (i.e. radio), and as such has to tolerate errors in (or loss of) packets. For this reason it will take significantly more than 2 seconds before your Bluetooth stack declares it has given up and disconnected the device, as you have found.
I have an application on Play which is designed to talk with an automotive ECU via Bluetooth and my strategy for sensing disconnection is exactly as I suggested in my first paragraph.
Update 20th June 14
I see in your bounty comment and also your comment below that you're asking for a code example, but it's kind of difficult for me to provide one without knowing anything about the application protocol that you're running over the socket connection. Or to put it another way, what exactly is it about my first paragraph (i.e. the heartbeat suggestion) that you do not understand or cannot create code for yourself? The concept of using a heartbeat really is quite simple. You would define a certain message type in your application protocol that represents a heartbeat message. One end of the connection sends this heartbeat message periodically, say every one second. The other end of the connection checks that this heartbeat message is received every second or so and drops the connection after a two-second time-out. It is impossible to be any more specific than that, because I can't see your existing code and I don't know what kind of messages you are currently exchanging over the socket.
After nothing work around!
I got two things to get my work done.
I need to check that is my Bluetooth socket is not in use(Sending Receiving) till 2 to 5 sec I disconnect that and when user wants to send data to the receiver device I connect that again.
Or I'll try to connect the socket after 2 to 5 sec so that if it is not ready to connect means it is already connected, else it will be connected and I refresh the previous socket references.
but first option is more valuable to work perfectly in my problem.
This is a problem with old bluetooth and more hardware than software.
If you want to notice that the connection is broken you need to do polling (a heartbeat), something like "are you alive? are you alive?"... This is bad for battery so... the users will finally uninstall your app.
I recommend you to change to BTLE (bluetooth low energy), devices like Nexus 5 has this.
With BTLE you have a proximity profile which can tell you the quality of the signal, so, you can guess the distance (near, far, out of range) and therefore you can also tell if the devices are disconnected.
Another nice point is that if the devices are out of range but one is again in range you could get noticed as well, so this is really nice for apps to open doors by proximity for example.
Check this:
https://developer.bluetooth.org/TechnologyOverview/Pages/PXP.aspx
In the other hand Apple has invented the concept of iBeacons, devices that are distance aware, and the good thing is that there is also an implementation of iBeacons for Android:
http://developer.radiusnetworks.com/ibeacon/android/
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
I'm working on an Android application that runs in the background and enables support for a Bluetooth accessory. I would like to be constantly listening in the background for the Bluetooth device to try and open a socket to the phone. My question is whether it is possible to achieve this without constantly keeping a partial wakelock, since that would obviously have severe battery consequences. So what I'm wondering is what effect Bluetooth has on the phone falling asleep. Does the phone stay awake when there is an open Bluetooth socket? Does the Bluetooth chip wake up Android automatically if a device tries to connect? I've attempted to do some testing to answer these questions, but it's difficult to isolate what is happening with wake locks; in addition, I don't know if I can rely on the behavior I observe or if it subject to change on other devices.
Yes, if your application is running and a thread is in serverSocket.accept() method, incoming connection wake up phone, so there is no need to use wakelocks. However, make sure that your service is in foreground and is not killed by system.
If you are developing it for devices target to marshmallow based or above, there is DOZE mode to treat such conditions. You then need not to worry about these thing. It can handle the WAKE_LOCK with appropriate mechanism.
The phone does not stay awake if there is an open Bluetooth socket, and neither does the Bluetooth chip wake up Android if a device tries to connect. Usually there is a background thread running to accept connections on the open port and as soon as a device tries to connect, it is this thread which reads the connection, gets some sort of authentication from the incoming device(I am assuming that there is a security protocol in place to accept any new incoming connections) and once the incoming connection is authenticated, an independent thread is created/notified to handle subsequent information exchange with this thread.
So the background process would consume some power and battery drain and it is also responsible for keeping Android partially awake(partially as its a background process and you can always control how frequently it checks for incoming connections). Usually this background process is not run always, its run only when Bluetooth is turned on in Android. So you can also create a thread which should run only when Bluetooth is switched on in Android, else it should sleep.