I have been following https://developer.android.com/guide/topics/connectivity/wifi-scan guide in order to create a Wi-Fi scanner. I am using a foreground service with a handler to call wifiMananger.startScan(); every 30 seconds (I tried with 15 minutes).
Everything works great for about 2 hours then suddenly WifiManager.EXTRA_RESULTS_UPDATED boolean returns false and the wifiManager.getScanResults() are not getting updated. Then as soon as the phone is plugged in it starts sending results again. (No, it is not low on battery)
I have battery optimization turned off. I have all of the required permissions allowed. Locations is turned on with Wi-Fi scanning enabled. The device I'm testing on is a Samsung S7 Edge running Android 8. So I know it's not the new OS. (I also tested with a Nokia 5.1 running Android 10 with pretty much the same results).
Does anyone know why this is happening or has anyone encountered this issue before?
Thanks in advance.
Updated: In case of your problem, since you are using exactly 30 seconds due to some problem there might be more than 4 time in a 2 minutes period, make it like 35 seconds and test the result.
Original Answer: From this WifiManager startScan throttled in P Beta (Developer Preview 2) :
"Call Limitations - Throttling
We are further limiting the number of scans apps can request to improve network performance and improve battery life.
The WifiManager.startScan() usage is limited to:
Each foreground app is restricted to 4 scans every 2 minutes.
All background apps combined are restricted to one scan every 30 minutes."
It is said that this restriction is due to the battery drain, so it is normal to remove the restriction while charging.
Read more about throttling in official documentation.
This is because Android OS enters the infamous "Doze mode". I recommend you to look through the official documentation/explanation.
Unfortunately, there is no way around this. It will also affect any kind of a foreground service and pause it for longer periods. Doze mode will only trigger if the screen is locked and the device is not plugged in.
I encountered the same issue on my project and we implemented a periodic check. If the screen is locked and device not plugged in for a longer period of time, we show a notification asking the user to either plug the device in or open the app so the service could keep working. The implementation is a bit lengthy, but if it is what you decide to go with, I can update the answer with some of the code (using the AlarmManager within a BroadcastReceiver to achieve this).
Related
I have an active-monitoring healthcare application that needs to be synced with different BLE devices every 15min in order to collect vitals and essential data. For this, I am using a ForegroundService with a Notification, Additionally, I have taken the wake-locks, and unrestricted power plan for the app as well with 15 min Periodic WorkManager Job as a safety check which basically triggers the same ForegroundService if somehow service is killed while device goes to idle or doze mode.
Problem
Most devices seem to be working fine, However, most Samsung, Huawei, and Xiaomi devices fail in doze mode. the sync window is increased by 30-120min.
Requirement
I want devices to sync reliably even in doze mode. I want to know possible solutions which may achieve this goal. Since data is important for real-time monitoring and triage a Battery-Tradeoff is acceptable as opposed by DOZE mode. Is there any special permission or mechanism I can use to achieve this?
is there any way to keep a BeaconTransmitter instance sending forever?
The Problem:
I want a RPi detect when I am coming home independent of Wifi running or the RPi even having access to the internet (e.g. it could then turn on all routers etc., when it detects the phone).
I have a minimalistic app on my android phone sending out an iBeacon running and the beacontools Library on the RPi detects it. This is working well, in principle. (Although I know it's supposed to be the other way around, but I again, I want the RPi to be able to do "stuff" without having access to the internet, what the phone cannot do).
However, the power management(?) on the Android phone seems to stop the transmission, the latest after a few hours (even if the App is "not optimized" for battery usage). I am not even sure if this is because of the battery optimization or something else.
Solution so far:
I am using a PeriodicWorkRequest that checks every 30 minutes (I read somewhere this is the minimum time), if the beacon is still running and relaunches it, if it is not.
This also works as expected, but of course, I keep coming home in the time slot when the beacon transmission has stopped and before it is kicked off again by the WorkManager. ;)
A cleaner way would be to "intercept" when the BeaconTransmitter is killed by PowerManagement/BatteryManager(??) or something. Is that possible?
Those covid tracking apps are using something (I hope) that ensures continuous transmission, but I know that Google/Apple had to implement something fundamental to allow those to work, and of course, I cannot use the covid-tracking itself because it is anonymous by design.
A precise answer will vary by phone manufacturer as many OEM's fork Android to kill long-running apps in the background. See here for a summary of challenges by OEM.
For vanilla Android (Pixel phones, many Nokia Android Once devices), Motorola and even most Samsung devices, it is sufficient to keep a foreground service active and have Location always runtime permission. My BeaconScope app uses this foreground service technique, and I typically see a transmitter keep going for weeks on a Pixel or Samsung device. Be sure you grant "Always" location permission to the app for this to work.
You can see the code needed to set up the foreground service in the Kotlin reference app for the Android Beacon Library. The comments indicate that the foreground service is useful for continuous beacon scanning, but it is equally true that it is useful for long-term beacon transmission.
Without the foreground service, the beacon transmission will only last about 10 minutes after the app is put to the background on vanilla Android, at which time the app will be killed.
The problem with a periodic work request or a job service is that they can run at most every 15 +/- 10 minutes on Android. So if the transmitter is killed every 10 minutes you will end up with gaps of up to 15 minutes without transmission. On Android 8+ you have no choice but to use a foreground service.
In my app, I make an internet connection every 10 minutes via the AlarmManager APIs to download data.
I would like the app to make at least 6 attempts to connect, one every 30 seconds if there a problem with the network connectivity.
Is it possible?
It isn't possible to do that on a modern Android device where by modern I mean Android 6 or greater.
6: Doze [Doze that comes on roughly an hour after the screen is turned OFF]
7: Doze++ [Doze that comes on shortly after the screen is turned OFF]
8: Background restrictions [Inability to run services that are not in the foreground]
Google's recommended way of doing syncing like this is to use a JobScheduler or Firebase Cloud Messaging if you have luxury of doing a server implementation.
With out knowing all the requirements, it sounds like the app may need to use the AlarmManager if you're determined to sync more frequently than the JobScheduler allows.
There is only 1 API in the AlarmManager that is guaranteed to be called reliably once every 30 seconds and that is setAlarmClock. However, it cannot be used to start a service. It can only send a user-facing alarm and a PendingIntent that will be executed when the user clicks on the alarm.
The two APis most likely to be useful to you are setAndAllowWhileIdle and setExactAndAllowWhileIdle. Both these APIs can be used to start a service. The alarms will execute frequently when the screen is ON or the device is charging. However, when the device is in the power saving mode called Doze they can only execute during Doze maintenance windows. This means they can still run at least once every 9 minutes during most normal doze windows.
Now apps targeting Android 8 must address another new restriction, they have to call startServiceInForeground. A foreground service sets an on going notification like your media player for example. So it makes the user more aware that the service is running and usually gives them an option to stop it.
Now foreground services are 'exempt' from doze, a few things to be aware of:
When a foreground service is active it prevents the entire device from dozing which greatly increases the battery usage
In Android 6 foreground services will be dozed anyway unless they are in a separate process due to a framework defect
I've heard that some devices will eventually kill a foreground service if you leave it running for an extraordinary amount of time
But the real answer to your question is: "Don't do it". Does the app really need to use that much battery and data? Running every 30 seconds is extraordinary and even if was possible it would make the app a "bad citizen" on the phone...
Currently i reading in official google doc news about Android 7.0
I can not understand a few things.
They wrote Doze improve battery life by turn off network and CPU when user block the screen.
But how this works ?
1.I have Marshmallow in my device, and when my phone is blocked, i still get notifications from app with network (e.g. Messenger).
2.Second thing they wrote Nougat have improved this more by again CPU and network. So what is exacly differet ?
I have Marshmallow in my device, and when my phone is blocked, i still get notifications from app with network (e.g. Messenger).
SMS does not usually go over the Internet, assuming that is what you mean by "Messenger" (many apps use that name). Plus, high-priority FCM push messages work despite Doze mode.
Second thing they wrote Nougat have improved this more by again CPU and network. So what is exacly differet ?
There is a "Doze on the go mode" that kicks in even if the device is moving. This is covered in the documentation and in the documentation.
Push Notifications will still get through, but most services will stop running after a while if you leave your phone sitting on a table with the screen off.
For example Spotify still keeps running smoothly because it has a foreground notification. The battery savings come from when the OS can shut down most systems such as internet and geolocation as well as avoiding running other services for increasingly longer periods of time,for example reaching stretches of hours by the end of a typical user's sleep at night.
Now they're mainly doing what they were saying for a long time: background services have no guarantees of how long they will run. The biggest unintended consequence is that sometimes when they wake up there's no internet or geolocation is not available. And the time they run is less predictable.
There's still ways to wake up and perform tasks with perfect predictability using exact alarms or push notifications, depending on where the event is generated. But for most cases the recommended solution is using job schedulers.
I have an app which updates the location to a web service every 10 seconds. However, on devices with API level 23 or greater, when doze mode kicks in after 15 minutes to inactivity, the network connectivity is lost, and the app becomes unable to send further location updates to my web service.
Other than whitelisting the app by asking for user permission to ignore battery optimizations, which only allows a location update once every 15 minutes, what are my other options to keep getting GPS location updates and be able to send them to my web service?
Though it is highly immoral to overcome doze mode, if the app can explain the issue with the battery to the user then it is better to whitelist the app.
The other option is to keep the screen on to avoid doze mode from getting triggered.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
This piece of code will keep the screen on. Make sure to create a black or empty layout like what battery saver in pokemon go does.
The Official Doze documentation allows whitelisting for your use case. Check it here.
You're running way too often to begin with. There's no phone that even updates location that fast- normal would be once every 30 to 60 seconds. So 2/3 to 5/6 of your updates are pointless. Ignoring that- if you're in a car going 60 mph you aren't going to change by more than 14 feet in 10 seconds. There's absolutely nothing you're doing on the server that needs to be accurate to 14 feet- the typical GPS in a phone is only accurate to 10 meters (over 30 feet). That's one of the reasons why GPS doesn't update more frequently.
But no, there isn't. They implemented Doze for a reason. It saves battery. They set it up so you can't get around it without asking the user if they want to burn that battery. I definitely understand why 15 minutes is too slow, but then you ask the user and let them decide if your app is worth it.