Android - Why use pending intents for geofences - android

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.

Related

Geofencing in background

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.

Geofences randomly fail to trigger until another GPS app is opened

I have been testing an app for many months which uses the Android Geofencing API to track enter/exit events. It works flawlessly about 99% of the time, but there are random times when the geofences simply do not trigger.
This cannot be an issue caused by my application failing to keep the geofences loaded, because whenever the fences fail to trigger, opening a completely separate GPS application, ie google maps, immediately causes my application to trigger the geofence event that it had failed to.
I am handling the reloading of the fences through a broadcast receiver on BOOT_COMPLETED and location.PROVIDER_CHANGED.
The fence radius is reasonably large, over 1 mile.
The app is not being put to sleep or under power management.
Users and personal testing show this is never due to location services being disabled manually.
There is no dwell and the fences never expire.
As I said, the geofences work flawlessly 99% of the time, and the other 1% simply opening another gps application immediately triggers the fences. I'm trying to figure out what I can do to eliminate the failing 1%, hopefully something short of constantly polling location (which makes the geofencing api pointless anyway).
Update: (Limited testing sample size of 1)On a device running Android Oreo, this issue seems to have become exacerbated to the point of geofences never triggering unless a secondary gps app is launched...
I don't know if this will help anybody but with the Background limitations starting from Android O the geofences work as you described, only opening apps that get the current location of the user will trigger the geofences.
You can create a Foreground service and poll the location from the Fused Location Provider in order to make Geofences to actually work.
I hope someone else found a better solution.

Location tracking like in fitness apps

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.

Can the android geofencing system (Google Play Services) trigger events when the phone is sleeping

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)

how to structure my app to run in background

I am new to Android, and I need some advices for start up.
I want to build an application, which will show up, when the user gets into some hot situation.
By hot situation I mean:
the GPS/cell coordinates are in known zone;
known Bluetooth device detected;
known Wi-Fi network detected;
weather info has change;
I see something running in background and when one of the clauses hit, it will trigger and open the app.
How to get started?
How do I make sure my app won't be shut down?
As I read somewhere that Android OS will terminate apps if memory out occurs or consumes too much, and my app would consume a lot, making repeated measures/checks to see if situation changed.
Regards,
Pentium10
You need to use a Service for the part of your application that runs in the background.
You might find the Application Fundamentals document in the Android Developer Documentation helpful. It says this about Services:
A service doesn't have a visual user interface, but rather runs in the background for an indefinite period of time. For example, a service might play background music as the user attends to other matters, or it might fetch data over the network or calculate something and provide the result to activities that need it.
In you case you might find the LocationManager Service helpful. It is a system Service which will you can use to notify your application based on GPS position.
However, I think you'll have to write your own Services to monitor Wi-fi, Bluetooth and weather.
You can use the AlarmManager Service to get your Service to perform particular tasks at certain intervals.
It depends on how & where you want to deploy your application. In my experience it boils down to
you create an application for a specific use case where battery drain matters less than accurate results (showcase situations, prototyping, ...)
you want to distribute the application to users.
In case 1) just create one service that aggressively polls the sensors / web services. Use the AlarmManager to send a REFRESH intent (AlarmService.setRepeating(...) ).
That REFRESH intent will restart the synchronization service everytime, even if it was killed by the system. onStart() will be called everytime the REFRESH intent is emitted. You can do heavyweight setup logic in onCreate() as this will be called everytime the service is created after it was destroyed. WARNING: This will possibly drain the battery very quickly.
In case 2) I would create several services and let the user configure different polling intervals for each service to limit battery drain. I can see for example that bluetooth should be polled more regulary than GPS as it is more likely that a bluetooth device suddenly appears than a user moving extremely fast.
Weather sounds extremely expensive (network lookup, possibly triggering a network connection!)
Please do not try to be too persistent with your app in case 2). It usually makes a lot of sense for a phone to kill memory / power draining services.

Categories

Resources