Question on start: how I can add/remove geofences without app opening?
When user switch off location all geofences are removed. When geofencing was introduced I was testing it and I was able to add/remove geofences in background by handling "android.location.PROVIDERS_CHANGED" broadcast, still have this code on branch.
Currently since API26 this broadcast isn't firing when put in manifest, we need to register (and un-) for this action e.g. during runtime of Activity or Service. And this isn't solution for my case, I want to add geofences again when location turned on or just prevent removing already added.
I do see two solutions for this case, but both have some flaws...
Foreground service - sticky service which add/remove geofences when location goes on/off, Service can receive PROVIDERS_CHANGED. But I don't like sticky Notification present always just for this trivial purpose...
Job/work - checking location state and basing on result add/remove geofences, at the end re-schedule own instance for e.g. 1h, and again. Short-living services (5 sec max) don't need to have "visual representation" - Activity on foreground or sticky Notification - but few secs is sufficient for checking location state and work with geofences (just logic, so pretty fast)
I didn't tested second approach, but it seems to be a kind of workaround, very unefficient for sure. I want to be fair, I'm informing users about purpose of location "listening" in background when asking for permission (also ACCESS_BACKGROUND_LOCATION on API29). So what can I do for keeping these fences alive when app is in background/killed?
ForegroundService is better option you have, as of today, there are many Custom ROMs which kills application which is in the background.
I have used foregroundService for the same purpose and it is working perfectly.
Related
I have implemented a foreground service to get GPS updates for longer runs, like 3 hours, when the app is in background. It is our business requirement. But the app stops getting updates after a few minutes. I see the "location icon" on top bar go disappear, even though my foreground service notification is still there.
I have also excluded my app from Battery Optimization list from the settings, so that Android doesn't kill my app. It helps to keep gps updates alive for about half an hour only, then again the location icon goes away and i stop getting gps updates.
What can I do to keep it always ON?
I am posting this answer based on my short comment and OP request
You can start that service by separate process by adding android:process=":FusedLocationService" in your Service component in manifest.xml.
I had done this and work in most of the device except some of the manufactures like Honor and other because they customized Android AOSP for better user experience
https://developer.android.com/about/versions/oreo/background-location-limits.html
Apart form this you can use JobScheduler to fetch location data after a particular interval (approx 15 mins)
You can build logic a/c to OS version as well.
And while fetching the location use FLP (FusedLocationProvider)
Hope this will help, But after all this depend on Mobile brand(like ONE PLUS) you will face the issues. You need to handle these scenario as well.
i used the google simple code to "Creating and Monitoring Geofences" and every thing works fine but i have one problem that when the device lost gps signal for second the trigger event will count this as exit , and when signal back will count as enter
even it's still inside Geofence ,i guess i can't avoid this situation
so did any one know if this behavior can be suppressed?
also An additional questions, i read alot in stackoverflow geofence problems that using a BroadcastReceiver better than Service to receive the transitions
right now i use service to receive and it's work fine , Is it necessary change it to BroadcastReceiver ?
This is an issue with Google Geofence relying on bad network location points at times. I have a potential solution for this here. It's not 100%, but it does help suppress the geofence jumps.
As for the second part of your question, I don't know if you mean the IntentService or just a Service. If it is a Service, I would recommend using an IntentService or BroadcastReceiver. IntentServices are mostly used for performing tasks on a background thread, where BroadcastReceivers are meant to restart the process (if it wasn't force killed by the user), and perform a quick task to handle the intent. Both of those are self contained, and destroy themselves right after the task is done. But to answer your question, no, you don't have to use a BroadcastReceiver, but it is better practice to do so.
My goal
Get user location updates for quite long time (e.g. 8 hours) with quite high frequency (e.g. every 30 seconds) even when the application is not running in foreground (meaning the activity where the location tracking was started might be destroyed).
Issue
I've found many articles regarding location tracking in Android apps.
The newer ones usually explain how to use Google Play Services' location APIs.
The problem is that in most cases, they demonstrate getting location updates in co-operation with Activity and LocationListener. For example in Google's tutorial. It's obvious this is not what I need. The only approach for long-running background location updates was based on periodical starting (via AlarmManager) of a service that run until it got accurate enough location update. However, this approach doesn't seem right for the frequency I need.
So, I ended up with custom idea how to solve the topic, but your critique would be welcomed. Here it is:
Idea of a possible solution
MainActivity - used just for starting/stopping the tracking by starting/stopping the MonitoringService
MonitoringService - a foreground service, where the whole connecting to LocationServices from Google Play services happens. Also, once connected a requestLocationUpdates method is called, but its variant with PendingIntent object. The pending intent contains intent invoking MyWakefulBroadcastReceiver class. Also, the service holds a partial wake_lock to prevent the device going to sleep and interrupting receiving of the location updates. Here, I'm not sure if holding the wake lock really helps.
MyWakefulBroadcastReceiver - extends WakefulBroadcastReceiver, just starts LocationProcessingIntentService via the startWakefulService
LocationProcessingIntentService - processes the location update passed via intent to it. Network communication performed here. Therefore, it is done in separate service and not directly in the MonitoringService
Currently, I have the solution described above implemented without acquiring the partial wake lock in the MonitoringService. When connected to debugger in Android Studio, I see the processing of the location updates work. However, I'm not sure what it will do after e.g. 4 hours of running without being connected to laptop (like it is for the debugging purposes)
Questions
Is this approach OK from architecture/performance/battery life point of view?
Should I use the wake lock for being sure the device won't go to sleep?
If answer to 2. is yes, do I still need to use WakefulBroadcastReceiver for starting the IntentService processing the location updates?
Any other recommendations?
What you have is mostly fine. You don't need the MonitoringService. The PendingIntent will wake your BroadcastReceiver, regardless of the state of your app. You don't need a permanent wake-lock. Just use the PendingIntent in your setup Activity to requestLocationUpdates.
Remember that the location services are already running in the background (as long as the user has enabled location services), so you don't need to run your permanent wake-lock service also (you can wake-lock after BroadcastReceiver#onReceive(), but don't forget to release the wake-lock after processing).
The only time you might have to worry about the PendingIntent not waking your BroadcastReceiver is if the user force-stops your app. In that case, you could choose to respect the user's decision. You can also explore using intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); which should wake your BroadcastReceiver from the stopped state, but I haven't tested this flag in this scenario.
I'm trying to find out if the Google Play Services geofencing and location system can be practically used for background location monitoring.
An example scenario is that I have the phone in my pocket, and enter a geofenced area - will the event handler in my app be triggered so I can deal with the event as appropriate, or is the system only intended to be used whilst the phone is awake and the app in the foreground?
I've been banging away at the example code, and so far haven't managed to make it work in this way - or find docs fully addressing this - it seems to be too new for people to be using it much.
Obviously the phone doesn't use GPS continually whilst sleeping, or the battery would run down quickly, but I'm wondering if the broad network location is monitored and used for this purpose (or to discover if the device is within short distance of a geofence, to know that it's worth polling the GPS periodically to find if it has been crossed.)
This answer (by Commonsware) to another question seems to answer the general thrust of the question, though more testing is required to answer some of the more detailed aspects about background location availability, accuracy and geofence reliability.
Commonsware
Geofence if implemented properly will work even when your app is in background and it can be handled from ReceiveTransitionsIntentService In the Service you can create notification and alert the Users to bring back to your APP.
But As per the Documentation, If the Location Services is Disabled by the User on the Device your Registered Geofences will be removed and you have to Re-add all the Geofences. (NOT SURE HOW CAN WE ADD THE GEOFENCES BACK in BACKGROUND DID NOT FIGURE OUT THE SOLUTION YET FOR THIS)
Also in other cases like when the Device is Switched Off / Battery is Drained / Restarted Most probably the Geofences are Removed and we have to reset the Geofences back (However i cannot confirm this as have not found this anywhere in documentation but while testing i have figured out this issue)
I just finished the tutorial for geofencing on Android (http://developer.android.com/training/location/geofencing.html) and I wonder why the 'callback' for geofences are done via pending intents and not a simple callback interface.
If implemented in an activity, one would usually disconnect the location client in onPause() anyway, so previously added geofences would not be tracked either after the application paused/was destroyed, so why a pending intent? Or am I mistaken here?
I wonder why the 'callback' for geofences are done via pending intents and not a simple callback interface.
Mostly because geofences are designed to work even without your application running.
If implemented in an activity, one would usually disconnect the location client in onPause() anyway, so previously added geofences would not be tracked either after the application paused/was destroyed, so why a pending intent? Or am I mistaken here?
I believe that you are mistaken here. In fact, geofences specifically are not designed for directly triggering UI, as is discussed in the documentation:
The Intent sent from Location Services can trigger various actions in your app, but you should not have it start an activity or fragment, because components should only become visible in response to a user action.
Now, you might elect to say that you want to only use geofences while you have your activity in the foreground. However, you would have to remove those geofences in onPause(). A geofence will remain registered until its expiration time or manually removed, AFAICT.
This answer can be outdated - accuracy and realiability of google play services has changed a lot from it's initial release.
Some of my experiences with geofencing below.
First of all - the main advantage of this technology is VERY low battery usage. In the fact, I can't notice any changes in battery life. It's really impressive.
Service seems to use only Wi-Fi and network location. I didn't notice GPS running at all. I can't say if it's only hidden location icon or really not using GPS.
Accuracy - it's terrible. 20 circle areas are not detected at all, except range of my home ap. It looks like whole position circle, including error must be inside of fenced area. 1000m areas are detected sometimes and with huge latency. Those experiments where made in open area with very low number of Wi-Fi ap around. I'm still trying to find really reliable settings foot this service. After getting intents I want to turn on GPS location and make final approach in my own code.