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.
Related
We want Android to automatically connect to our custom made BLE peripheral.
Our peripheral should regularly (but infrequently) advertise and attempt to Indicate some time-sensitive sensor data to the phone. Thus we want the phone to be ready to connect at any time.
Generally, you can pair a smart watch with an Android, and Android will then automatically connect to the smart watch whenever it is in range. So we believe our use case should be feasible.
I read a lot of answers that advise to set the "autoconnect" parameter to true when connecting. I have tried that and the reconnections don't persist through a reboot or even after disabling and re-enabling Bluetooth on Android. This answer by Brian says I should scan in the background, but Android made this unrealistic. If I use a foreground service, my users will hate the app. If I use a background service, I may miss the peripheral's attempts to connect during Android's Doze and the code becomes error prone.
Ideally, I want to do something like what Emil said in his answer here. Please read the follow up question and response.
However, we can't see our app through Android's Bluetooth settings. We can only connect to the peripheral and pair with it using our app (or nrf Connect). In desperation, I tried modifying the peripheral's advertising flags. Then I could see it in Android's Bluetooth settings. But when I try to pair using Android's settings, the attempt fails because the peripheral is not in "pairing mode".
We are building both the app and the peripheral, so we can change both. I want to know if our use case is possible and what we need to do to get it working. We are using the STM32WB for our peripheral.
Use a combination of these techniques:
Bond the device. This might be needed due to the crappy Android Bluetooth LE API design that doesn't take the "address type" as an extra parameter when connecting to a device. When you connect using the Bluetooth device address, it looks up a device with this address in the bonding info, and uses the corresponding address type (random or public).
Use connectGatt with autoConnect set to true. This means no timeout, as well as auto-reconnect if the connection drops. Even if it takes days or weeks until the peripheral starts advertising, it will still work.
Listen to https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#ACTION_STATE_CHANGED and restart your connections when Bluetooth is re-started.
Use a Foreground Service in your application's process to prevent the OS from killing the process. Users can nowadays hide the annoying notification in Android settings if they want to.
Listen to https://developer.android.com/reference/android/content/Intent#ACTION_BOOT_COMPLETED to start your app after boot, including your Foreground Service.
Listen to https://developer.android.com/reference/android/content/Intent#ACTION_PACKAGE_REPLACED to automatically restart your app after an app update. See https://stackoverflow.com/a/2134443/556495 for some instructions.
The best approach is to make sure your peripheral can be bonded. Once you have bonded with it you can ALWAYS use autoconnect because Android stores info about bonded devices and you don't have to scan for it anymore. Hence you avoid the issues with scanning in the background.
Although that resolves the need for scanning, you still need to deal with your app being killed once it is in the background. Using a Foreground Service is still the best solution to my knowledge. I don't think you users will hate your app for it...
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.
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 am no Bluetooth specialist and wondering what possibilities are available to find already paired Bluetooth devices automatically when they are range of each other.
Background:
In our case an Android application needs to connect to a dedicated accessory via Bluetooth (Rfcomm). Both devices are known to each other (they are paired). The Android application registers a broadcast receiver. During the startup of the application, the app initiates a discovery to find the dedicated accessory. If the accessory is in range everything works great.
Problem:
The user starts the application outside the range of the dedicated accessory. The Android application tries to discover the accessory without success. Then the user goes into the range of the Bluetooth accessory. The broadcast receiver won’t get notified about the accessory that is in range now.
Similar Thread / Possible Solutions
Similar questions were already asked on stackoverflow (e.g. autoconnect to bluetooth device when in range).
But continuously trying to discover Bluetooth devices in range isn't what I am looking for because this would cause too much battery drain of the Android device.
Another solution would be to try to connect to the paired device in the onResume method of the Activity. This would work but has the disadvantage that the application can’t run in the background. So the user had to bring the application at least once to the foreground to initiate the connection.
A third idea I thought about is to implement a server socket into the Android application too. When the android application is started and the discovery finished without success, the Android application could create server socket and to listen to incoming notifications of the accessory. This would help in some scenarios (e.g. the user starts his application, approaches the accessory, activates the accessory and the accessory notifies the application on startup that it is in range now). But this is still no 100% solution because both devices can start outside the range of each other. Also it would be mandatory to implement additional functionality (Bluetooth server socket in the Android device…).
So I am wondering if better solutions exist. I am looking for a solution where no additional ServerSockets are required and I always get the notification that the two already paired devices are in range of each other :-)
Thanks for any help!
After connecting the device for the first time, keep the mac address in a local list.
On disconnect, use connectGatt with autoconnect set to true to automatically re-connect when you are in range.
Not a full solution, but maybe it's sufficient for your app to poll the accesory's presence whenever the screen is turned on? In that case, this may be helpful: Start Activity on wake up/sleep in Android
I'm attempting to write an app that involves connecting two android devices via bluetooth.
It is my understanding that one device acts as a server, listening for incoming connections while the other acts as the client, and initializes the connection using the server's MAC address.
Consider the following:
I have my android phone in my pocket, I start working on my android tablet. I want to connect the tablet to the phone (via bluetooth) without taking the phone out of my pocket (I do not want to pull out the phone and manually start listening for incoming connections).
What would be a good way to achieve this? It seems like I would have to make the phone the server, constantly listening for connections 24/7. However, my gut says this will violently drain the battery.
Any suggestions?
You are right, you could make your phone (or your tablet) the server. But it ought not use that much battery; once you set up a server socket and start accepting connections the code simple blocks and waits for an incoming connection. In my experience I haven't found this to be too much of a battery drain (but I have no hard figures to back that up).
If there is a UI involved with the server you'll want to split out the server socket into a separate thread so as to not block UI events.
Typically phones behave this way - i.e wait for incoming connections from paired devices. Waiting / Scanning for incoming connections is less power hungry than trying to find or connect to devices in a poll mode. Many bluetooth chips have low power scan which implements power efficient scanning.