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.
Related
I know that similar questions have been posted in the past and the most current solution I have found is to use a JobScheduler + wakelock + Foreground Service as explained for example in this excellent article by Roberto Huertas (https://robertohuertas.com/2019/06/29/android_foreground_services/).
However my doubt is to know if there is a limit for this method. Does it really work that well? What if the App stays in the background for days or even weeks, will it still work?
If the answer to these last questions is no, is it possible to keep a background service on Android > 10 that can keep running for days without stopping?
EDIT 1:
I'm trying to create a real time GPS tracking app (In this case I'm using Firebase). The company and the users who use it, give their consent to be tracked all day long during their activity. This tracking can be stopped if the user disables the option inside the APP.
I have managed to keep the service running in the background using various techniques, but after a few hours Android kills it.
No, it's not. It's actually less possible than ever. Background services are now limited to 2 minutes after you exit the foreground. Foreground services will be kept around for a while, but they won't stick around forever.
The correct answer on Android is to find a way NOT to need a service running at all times. This is almost always possible, but methods differ depending on what you actually need to do, which you haven't given us any info on.
I'm developing a location aware app. This app will start tracking users when they are in their workday. These are the requirements:
The service should run on a regular basis (every 30 or 45 min).
It won't matter if the service does not trigger at the same basis everytime.
The service needs to upload data to our firestore db.
I doesn't need to be triggered on specific conditions (data is on, phone is charging, etc...)
I need this to run even if the user restarts his phone.
We may need to track the distance traveled by the user. (This is not a requirement per se, but it may be a feature someday)
I know there are a lot of ways to achieve this, but I have not decided which is the option that best fits my scenario. This is what I've thought so far:
Foreground service combined with BroadcastReciever in case the phone is rebooted
Background service using the new jetpack's Workmanager.
Which will the best solution? Do you think there is a better solution than those?
Thanks!
Was thinking create a GPS location tracker so when they are in work premise as well as outside it kinda shows.
Then consider adding the number 5 of the above. Like you said there could be mire awesome solutions than these so lets wait for options.
I'm developing a set of complications that I would like have regardless of the other installed apps and watch faces. Yes, at some point I am reinventing the wheel, but at the same time I am using this as a learning project. This will also ensure that I always have all the complications I use, available and that they all have the same format and style, instead of relying on 3rd party apps to provide them separately.
The set will have complications for Heart rate, gps coordinates, hours, minutes, seconds, dd/MM date, dd/MM/yy date, battery, etc.
When I started programing all this I found several problematic pieces (most likely because this is the first time I develop complications, or an app for android wear for that matter) and hence this question.
Note that some of this behavior might be specific to the Huawei Watch 2 LTE.
1) Upgrade interval push / pull.
I understand complications as data providers, whose only responsibility is to provide the data to whatever watch face is calling them. This means that we are not certain (and we rely on the watch face developer) to know about the complication and request updates accordingly. This turns some complications completely useless if not updated in time (for example display the Seconds). Could also leave to complications displaying old data (for example old GPS coordinates, old heart rate bpm).
So ok, I decided to implement ProviderUpdateRequester with the AlarmManager to push data to the watch face. The problem again, is with complications that should happen faster, like seconds, as Android will block pending intents if they are schedule too often. So in order to get around that, I decided to use Android handlers within the same service instance, which turn out to be not a good idea because of the next topic.
2) Complication lifecycle
By debugging, I found out that the instance of the ComplicationProviderService object that is executing onComplicationActivated, onComplicationUpdate, onComplicationDeactivated can be different. This means that this is not a sticky service (single instance) that will be always running, but every update creates a new instance of the service. This is problematic because of heavy initialization complications: for example GPS, or Heart Rate monitor that need to listen for new values and it might take a while to retrieve the first value. And also, for those complications that can't rely on AlarmManager, and/or need to keep some sort of state between updates executions.
3) Display aware service
To get around the previous point , let's say you have static variables on your complication service , which are initialized onComplicationActivated and disabled at onComplicationDeactivated. For example, this could be getting a reference for the LocationProvider and starting listening for location updates. This will ensure that each invocation to onComplicationUpdate will not have to perform the heavy/cold initialization and will have access to the most up-to-date data.
However, this also means that your logic will executed regardless if onComplicationUpdate is called or not.
When in ambient mode (or screen off) the watch face can decide not to update the complication by not calling onComplicationUpdate, but it's not aware of our static logic, nor the ComplicationProviderService has a callback invocation for when the screen goes into ambient mode or turns on/off. This is a problem, because in our example, if the screen is off, we are still going to be listening for GPS coordinates, and most likely draining the battery.
Sure, we can deal with this by using a combination of BroadcastReceiver (Intent.ACTION_SCREEN_ON/OFF) and DisplayManager.DisplayListener, but then again, not sure if i'm taking the correct path here, because this will mean that we are now creating services that need to be statically aware of the state of the display.
4) Detect screen on/off
The BroadcastReceiver for Intent.ACTION_SCREEN_ON/OFF works as expected when ambient mode is disabled, but it doesn't it's enabled. When ambient mode is enabled, Intent.ACTION_SCREEN_OFF is dispatched when going into ambient mode, but Intent.ACTION_SCREEN_ON is not dispatched when coming out of ambient mode. While a bit more complex, this can be accomplished by using DisplayManager.DisplayListener to get updates on the onDisplayChanged callback.
TL;RD
1) How do you ensure watch faces display your complications in a timely manner to always have correct and most up-to-date information?
2) How do you deal heavy/cold initialization of a ComplicationProviderService if everytime onComplicationUpdate is called the service instance is different?
3) Is making a long running service display-aware something crazy to do?
4) Technically the screen is still on when in ambient mode, so why is Intent.ACTION_SCREEN_OFF being broadcasted? Why isn't Intent.ACTION_SCREEN_ON/OFF symetrical when ambient mode is enabled?
5) Maybe complications shouldn't be use for exposing realtime information?
Thanks a lot
A couple of things to unpack:
Complications are not meant to be updated frequently (think minutes, not seconds) - this is to preserve battery.
ProviderUpdateRequester is designed more for (on average infrequent) irregular updates like messages coming through a chat app.
Time dependent complications - there are not an "update" as such but Wear provide ways for developers to count up / down from certain time and for displaying date related field (world clock, day of the month) without the provider sending the system updates all the time. For this last one, please refer to docs for ComplicationText.TimeDifferenceBuilder
and ComplicationText.TimeFormatBuilder.
For your use case, a more appropriate thing maybe to consider an always-on app. User uses it for a certain time period for a specific purpose so they explicitly agree to use to use more battery to track things like GPS or heart rate. For example, a lot of running apps on Wear do this.
I hope this helps.
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.
Just watched the session about new location capabilities:
https://developers.google.com/events/io/sessions/325337477
and think that feature of GEOFENCES will be a good fit for my app.
I also downloaded the demo app which while quite informative is not giving me the functionality I am looking for.
So could someone please explain me or point me to some example on how could I add a geofencing detection to the app that works while the app is off. If you have seen the IO session and noticed the app Zillo that is what I am talking about.
What I know by now is that I don't want to use a constantly running service in the background that detects TRANSITION broadcast but would like to register for them in the manifest file and than handle them inside a broadcast receiver class. Something like you would do when using GCM messaging.
So the questions are:
What broadcast needs to be registered in the manifest?
When should I register my fences so they are registered only once and stay registered when the app is closed?
Are there any pointers on how to optimize battery life in a case like this?
If someone already has experience what radius for a geofence would you suggest to detect entering a large building (3000-5000 sqm ground floor area for example)?
I implemented what you are talking about. (using a broadcast receiver instead of a IntentService). I started with the sample code, then made a few small changes, listed in my response here.
It seems to be working fine when the app is closed.
As far as optimizing battery life, this is all done by the OS. You just register the fences and Android handles the rest. I think they have optimized it well, I haven't seen significant drain after registering almost 100 fences. But I haven't done extensive testing.
As far as the radius size, I suggest building a sample app that has a map in it, and put a pin on the lat lng and play with the radius till it looks right. For a wild guess, I'd suggest something around 150 meter radius?
--update--
More detail on what I've found as far as accuracy. I built a testing app to see track myself and see the accuracy, and been driving around for the last few weeks and checking it frequently. I've only been testing with gps off since thats similar to what most users will encounter when they are out and about. :
Outdoors, not close to any wifi signals: Not very accurate, something like 100-200+ meters
Outdoors, close to wifi signals: Surprisingly accurate. Between 10-30 meters. If I'm sitting outside a restaurant, or at a strip mall where there are wifi signals, it knows very well where I am.
Indoors: even with wifi, many times it seemed less accurate than outdoors. More like 30-50 meters.