Periodic foreground location tracking on Android - android

I am in the process of creating a custom Phonegap plugin for Android that monitors location both when the app is in the foreground and when it is backgrounded. Google documentation on using the FusedLocationProviderAPI is remarkably clear. The process I have worked out thus far is as follows
Ensure that the API is available
GoogleApiAvailability api = GoogleApiAvailability.getInstance();
int code = api.isGooglePlayServicesAvailable(ctxt);
return (code == ConnectionResult.SUCCESS);
Define a LocationListener with assigned callbacks to handle the results retured by the requestLocationUpdates method.
Create a LocationRequest
Here is where things become slightly unclear
setInterval - the interval at which the app wants location updates
setFastestInterval - the interval at which it will consume updates if available.
setSmallestDistance & setPriorty - clear enough
setNumUpdates - how this works is not clear to me. Reading between the lines I am assuming that if I use setInterval(60000) and setNumUpdates(1000) the system will keep sending back location updates for the next 6000 minutes or until such time as the app is backgrounded/shutdown or I/the user cancels location updates.
But then this begs the question - what does the app need to do to be a good citizen. I am assuming that would have to be something like this
Record the PendingResult being returned by the requestLocationUpdates call.
Detect when the onPause event occurs
call PendingResultt.cancel() prior to letting the app go to the background
I'd be much obliged if someone could comment on the correctness of this workflow.
A related issue - The documentation for PendingResult states
It is the responsibility of the caller or callback receiver to release any resources associated with the returned result.
It is not clear to me what resources they are talking about here. The LocationListener.onLocationChanged event returns a Location object which I assume will be garbage collected when it goes out of scope. Presumably the PendingResult being returned by requestLocationUpdates should be canceled and then set to null when the app goes to the background. Is there anything else one needs to do by way of releasing resources?
A few hours later
I created two versions of my test app
App 1:Sets up the LocationRequest with setNumUpdates(10000). Pops up toasts on location change in the form App 1:Location is...
App 2:Sets up the LocationRequest with setNumUpdates(1). Pops up toasts on location change in the form App 2`:Location is...
I had the two apps running simultaneously and simulated position changes with the help of a really neat little app called FakeGPS. Both App1 and App2 provided me with an update when I did my first fake location change. However, all subsequent location changes were reported only by App 1.
By inference then setNumUpdates provides a mechanism for polling for updates periodically. What is slightly confusing is that the updates continue even after the app is backgrounded - though I assume that this is largely because it is at the mercy of the OS which will kill it when it deems fit.
However, all of the above is based on empirical testing. I find surprisingly little on the setNumUpdates setting.

To your question, Is update continue even if app is in background:
Ans: What ever be the case setNumUpdates is 1 or x, when your app is in background and is still registered to update, you will get the updates, unless the OS has killed your app, for memory.
The only difference that setNumUpdates does is, as you said correctly, if its set to 1, it will give only one update, unless you has reregistered again.
Link has sufficient definition for setNumUpdates
https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#public-methods

Related

FusedLocationProviderClient.getCurrentLocation(): Background apps calling this method will be throttled under background location limits

In the docs for FusedLocationProviderClient.getCurrentLocation() it says as follows:
This method may return locations that are a few seconds old, but never returns much older locations. This is suitable for foreground applications that need a single fresh current location.
Background apps calling this method will be throttled under background location limits, so background apps may find the method returns null locations more often.
What are the implications of "will be throttled"?
In my situation, I have a widget which updates at most every 30 mins. With appropriate location permissions granted (foreground and background), I can already access the last known location using FusedLocationProviderClient.getLastLocation() and this has been working fine.
But I'd like to explore a more active approach, using getCurrentLocation() instead of getLastLocation(). For a widget, with no app in the foreground, even passing LocationRequest.PRIORITY_HIGH_ACCURACY to getCurrentLocation(), I never see the little "location" icon (map pin icon) appearing in the status bar, like I'd expect to if the device were actively requesting a new location fix. Yes, ACCESS_FINE_LOCATION permission is requested and granted. Using this same method call in the app (in the foreground) and I do see the "location" icon.
So, for a widget is there any real benefit in using getCurrentLocation() instead of getLastLocation() in the background if it is going to be hampered significantly in some way? Sometimes it seems to take around 30 seconds to complete (with no visible sign in the status bar of any location access) and then return with a null location anyway, so what is it actually doing?
I could start a foreground service (with notification) but it seems overkill if the user is anyway going to have visibility (via the "location" icon in the status bar) that location is being actively accessed.
So what exactly is "throttling"? Just putting a limit on frequency (widget updates at most every 30 mins so it's hardly "frequent")? Or putting a limit on accuracy (e.g. no GPS)?
I think that it probably relates to these background location limits:
In an effort to reduce power consumption, Android 8.0 (API level 26) limits how frequently an app can retrieve the user's current location while the app is running in the background. Under these conditions, apps can receive location updates only a few times each hour.

Android Location GPS Track

I have a small test App that with an Android GPS API map fragment. I use FusedLocationProvider. TarketSDK=29. Using Java.
As long as the app is active it works beautifully. On locationUpdates, I add a new point to the track and everything looks great and stays accurate. The goal is to track my hike, total distance and track and show it on the map. Works great.
As soon I lock my phone or loses focus, then the updates stop and I no longer get location updates.
Solution seems to be:
Background Service (discouraged)
Foreground Service
PendingIntent
I have poured over the docs, StackOverflow, all examples/tutorials I can find, developer.android.com, etc. I have downloaded examples of the latter 2 from GitHub; they seem incredibly obtuse (probably just me).
What are the dis/advantages of ForegroundService vs PendingIntent?
How about a bare-bones example illustrating the min features of each to implement location updates while your phone is locked in your pocket or some other app is active? Just the template minimum.
I need to save the locationUpdates that occur while my app is not active or phone is locked; in order to fill in Track when activity is restored to the app.
Some simple end-to-end guidance from my working app to something that will maintain locationUpdates and save the data would be great.
Ok - I have answered my question in a roundabout way.
I had been Searching on "retrieving location updates when app is not active". This lead to the various solutions of background service, foreground service, pendingIntents, etc.
I eventually found that if you just start a Foreground Service with a Notification, even if your phone is locked or you switch active apps, your App continues to receive LocationUpdates; as the Foreground Service runs in the same thread and therefore activates your app code (if I understand the reasons why correctly).
So, I started searching on just how to start a Foreground Service. As anyone knows that has tried to figure this out lately, this has changed more than a couple times over recent versions. The online docs at developer.android.com are not up to date. You will spend a lot of time wondering why things do not work following these docs.
Eventually, with just searching on how to start a foreground service, I came across this simple and straightforward (non-youtube-video - don't you just hate those things) tutorial. https://androidwave.com/foreground-service-android-example/
I just added this code to my existing Mapping code that works when the app is active, and tested with locking the phone and putting it in my pocket and switching apps and doing the same. It appears to solve the problem.
Update: Added code to count number of location updates and average accuracy of each update holding the phone in hand, screen on and app active as the baseline. Phone locked, or App not active no difference in number of updates nor accuracy. Phone locked and in pocket, no difference in number of updates, but accuracy suffered by from an average of 10m to an average of 13m; to be expected I assume whilst in the pocket.

What are good strategies for dealing with background location limits for apps running on O devices?

Given the limits placed on location gathering on Android apps running in the background on O devices, what are good options for developers who want more frequent location updates?
I realize that O is still in developer preview, but there are significant changes to how location can be gathered in the background, and I want to project ahead to changes that might be needed in my apps.
Apps requesting location updates that are not in the foreground are subject to some limits when running on O devices. Location updates are still available in the background, but they may be happen less frequently than the interval specified in LocationRequest#setInterval. Developers have the following options for getting more frequent location updates:
Request updates in the foreground. This means requesting and removing updates as part of the activity lifecycle (request in onResume() and remove in onPause(), for example). Apps running in the foreground are not subject to any location limits on O devices .
Request updates using a foreground service. This involves displaying a persistent notification to users.
Use geofencing to trigger notifications based on the device’s location. If your use case relies on the device entering, dwelling, or exiting a particular area of interest, this API provides a performant way to get these notifications. See the GeofencingEvent#getTriggeringLocation[, which gets the location that triggered the geofence transition.
Use batched location updates using LocationRequest#setMaxWaitTime. With this API, locations may be provided more frequently than the non-batched API however, will be delivered in a batch after the interval specified in setMaxWaitTime (also limited to a few times an hour)
Use passive location updates: While your app is in the background, it may continue to receive location updates passively if another app in the foreground requests location updates. You can receive some of these updates by using LocationRequest#setFastestInterval with a small interval, such as 5 min.
Given that this is a large-scoped question on how to handle Android O background location restrictions, this may be relevant:
If your app needs to receive locations in the background primarily to use as a dependent input, Awareness API may be useful for you.
Geofence is one example where you want to be notified when device moves by X miles (and you do not really care about the actual location coordinates). Similarly, if you need location for things like fetching location-dependent data on server, or triggering location-dependent notifications, Awareness has a bunch of useful APIs.
For example, the weather snapshot API lets you get the weather at device location without you having to request locations. TimeFence has APIs for waking-up apps at instants based on timezone or sunrise/set etc at device location.

Android - GPS after a while no longer receives coordinates

I have a big problem with an Android application that I developed.
The purpose of the application (for business) is to track the position of the device continuously (24 hours on 24) detecting a GPS track on a regular interval, which will then be synchronized to the server to the unleashing of certain events.
Of course, over time the device in and out of buildings, acquiring and losing the GPS signal continuously.
Often the device is not used and remains in office for several hours inside the company headquarters without GPS signal. During the course of time the Android system continues to provide me constantly getLastKnowLocation
My problem is that after some time that the system is running, sometimes two or three days, sometimes more days, my app starts to receive from the system always the same coordinates, regardless of who is in the open or at closed. From what I understand the Android operating system no longer seems able to update his coordinates and It will always return the same getLastKnowLocation indefinitely.
My App therefore becomes useless.
You know how I can fix this?
Is there any process that Android can restart in order for the system to wake up. In My App I will acquire any permission, except for root permissions.
For now the only control that I put, and that if the system always gives me the same identity for a number of seconds I call the method requestLocationUpdates of the location manager again.
But I need something more robust, to give me a better guarantee of operation. I'd like to be sure as possible that the systems try really to get updated coordinates.
The only thing I can think of is that maybe I can ask the system to restart some process so that the Location Manager, is fully reset. Can I do this? What is the process to be killed?
Can you think of any other solution or you found yourselves in this issue?
Thank you.

What are the best practices for Location-based Android app's architecture?

I want to know what are the best practices for Location-based Android app's architecture/workflow?
My current code uses several Activity and one backing Service, and several AsyncTask.
I start my Service as soon as my app is launched, I do all the HTTP callings and parsings in my Service. And I also wrote a subclass of AsyncTask to obtain user's location. I run the AsyncTask everytime I need to update user's location. The AyncTask calls LocationManager.requestLocationUpdates() and asks to get locations as fast as possible. My strategy for this is:
1. At first, I getLastKnownLocation for both GPS and network, and compare them using the method on http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestEstimate.
2. When 3 GPS locations and 5 network locations is obtained, or one or both of GPS and network didn't respond in 1 minute, I stop the task.
3. I return the best estimate I have.
the Locating AsyncTask is run in the Service, and I set an AlarmService for 5 minutes to send my service an Intent to check whether I need to update user's location. My min interval between two AsyncTask is 10 minutes. User is able to request Location updates manually by simply pressing a button.
Above is how I implement the Location service into my app.
I need to know whether my practice is appropriate. If not what is wrong? If yes, is there anything that can be improved?
I think youy pretty much got it. I have very similar solution where I want "in and out" as soon as I can.
I implemented check for "accuracy" into my algoritm. I give service 1 minute from start to get BEST possible location or I will exit even earlier if I get 25m or better accuracy fix.
Also, I don't use AsyncTask for location itself - Service doesn't block thread, it get's and processes callbacks from LocationManager so I don't see why you want to do AsyncTask.
When I'm done with obtaining location and about to exit - then I call async task to process Http post to the server.
As far as interval - I give user options of 5/15/30/1hr and 1/2day. I use inexact alarm for this - supposedly better on battery.
This is not an answer per say , but here are some additional points. Reto Meier , in his Pro Android tips in Google IO suggested not using wi-fi if the battery was low.
This can also be extended to location. Let the user know his battery is too weak & the app wont be using GPS & network provider , instead it will be using the last known location which may be inaccurate.
You have not mentioned it, so I am going on the worst case scenario that you can not checking if the location providers are enabled. You need to check for the same and have an alert asking the user to enable location service if all are providers are disabled.

Categories

Resources