Feature request: Proper background process

I have been using watchfaces for so-called background processing, but there are more and more limitations in which watchface execution is suspended entirely making this less effective, causing gaps in my data.  Previoiusly watchfaces would only be suspended when a widget or activity was active.  Now with new features like the morning report, watchface during sleep, and always on display off option, there are more cases where watchface "background" code (whether run in the background or on 1 min update) is suspended. 

It would be nice to have a way to specify a proper background process with somewhat "guaranteed" execution (and execution time limit of course).  Ideally the execution period could be customized (every 1 min to 60 min).  Perhaps a totally new type of app needs to be invented for this.

  • In the background if you want to preserve data from when the main app isn't running, you use Background.getBackgroundData()

    Let's say you have a background that runs every 5 minutes for a watch face, but you then start a activity like run, and you use it for 15 minutes.  The background will run about 3 times, but when you go back to the watch face, all it sees in getBackgrondData that was returned the last time Background.exit() is called, so it looks like it only ran once.

    With getBackgroundData, you can see if something is queued for the main app but not seen by the main app, and you can add what's seen in the current background to what's already waiting for the main app to run.

    With the case of the background running 3 times in the run activity, onBackground data only sees the data from the 3rd run of the background, but if you implement getBackgroundData you can pass all three results at one time, and the main app sees all 3.

    So, in onBackgroundData without using getBackgroundData,

    data=result3

    But with proper usage of getBackgroundData

    data=result1 result2 result3

    (your app doesn't miss result1 and result2)

    With watchfaces, a background service only runs for the active watch face.  So if you have two watch faces with background services, only the background for the watch face you see ever runs.

    This is all about the battery.  You don't want the background to run if you aren't actually using that watch face.

    In the case of the "watch face during sleep", your watch face isn't the active one during that time.  It's as if you switched to a different watch face.  You can disable the sleep watchface, and your background will run as you expect, as it remains the active watchface.

  • Did you read the OP? Clearly they understand how it works today, they are asking for something different (hence “feature request”)

    Their use case is implementing watchfaces that collect data regularly (e.g. once per minute), and they’d like to minimize the situations where data collection is interrupted.

  • Did you notice the part where he talked about gaps in his data, and when the watch switched to the sleep watch face?  The gaps can be easily explained and If you don't change the active watch face, you don't lose data there.

    No need for a feature request for the things that can already be handled. And there are some things, that are done for battery life.  A background runs for at most 30 seconds, by design, as you don't want to tie up the watch too long, and impact outer apps' background service.  They only run one at a time (that's also a memory thing - not enough memory for 2 at a time.).  

    How many apps with a background service have you written and used?  Here's my blog post on the subject!  

    https://developer.garmin.com/connect-iq/connect-iq-faq/how-do-i-create-a-connect-iq-background-service/#howdoicreateaconnectiqbackgroundservice

  • I didn't realize that background processes can continue to run during activities.  If that really works that helps as it covers some of my use cases, not all.

  • On some devices, it will only run for native activities, not for CIQ device apps. 

    Consider a CIQ DF with a background service.  The background has to run with a native activity or doing the backrounding in a DF would make no sense..

    But, this is a case where you want to use getBackroundData in your background service for a watch face will see all the data.

    edit:

    While not a watch face, I do have a widget with a background service to return the battery level and a timestamp when it runs, and is configurable to run ever 5,10,15,20,30, or 60 minutes.  With the timestamp, I can catch gaps in the data, like when running a device app on some devices, and reflect that in my graph.

    I use getBackgroundData there so it can actually return a large number of samples, and with a native activity, I can see the graph for the whole time I was running,  Without getBackgroundData, I'd only see a sample from the last time it ran

  • For a widget, I suppose that the widget has to be activated at least once for the background process to start? After that does it run forever ?  Or does it need to be started again after some event? (other than a power off/on cycle)   

    I have used background processes on DFs. I had one that I thought was running all the time even if the DF was not installed on the activity being executed (I had a good use case for it).  But then it seemed to not work after some point.  I suspected a Garmin firmware change.  Any thoughts on this?  

  • Depending on how a widget is written, it does need to run once, but just seeing the glance in the glance loop could be enough.  After that, the background service will run when resources are available to do so.

    For a DF, things are a bit more tricky, as you probably don't want or need the background to run after you finished the activity.

    Something that may be more visible with a DF, is that the background may not run right when an activity with that DF is started, but will run a bit later based on the times of the temporal event.  So lets say you run something, the background runs, you exit and restart the activity, the temporal might not run for a few minutes.  You can't force the background to run right when the DF starts - the "5 minute" rule...

  • This sounds like what I want but I can't follow how to implement this. Is there an example somewhere?

    All I have now is a background   System.ServiceDelegate that contains:

        function onTemporalEvent() {
            Background.exit([1, Time.now().value()]);  
        }
    Then in the AppBase I have this to receive the data
        function onBackgroundData(data) {
            if (data!=null){
                Storage.setValue("updTS", data[1]);
            }
        }
    I can't call Background.getBackgroundData()  from the App class, so how do I get my data back to the non-background process?  Do I call getBackgroundData() from inside onTemporalEvent() to see if there is any data? Seems hokey and it won't give me the exact behaviour I am trying to get to.  Can I call getBackgroundData() from  Background.initialize()  to get queued data?
    What do I need to change?
    I don't suppose there is any way to test this in the simulator?
  • When onTemporalEvent runs, by default, when you do the Background.exit, you only return the result from that run of the background, and if there was something already there waiting for the main app, it gets lost and the main app never sees it.

    For some things, that's fine.  If the background is getting the weather, you may only care about data in the main app that's the most recent.

    But if you want to return data from multiple runs of the background, that's where Background.getBackgroundData comes into play..  I have a widget for example, to watch/graph the battery level.  There I want to provide the main app with multiple data points since it last ran.  Here's my onTemporalEvent.  In this case, maxSize is 144, so that the max number of data points I'll return (there's a limit to how much data can be returned with Background.exit()

        function onTemporalEvent() {
        	var old=Background.getBackgroundData();
        	if(old==null) {old=[];}
        	old.add(Time.now().value());
        	old.add(Sys.getSystemStats().battery);
    		var sz=old.size();
            if(sz>maxSize*2) {
            	old=old.slice(2, sz);
            }
            Background.exit(old);
        }

    If the background runs every 5 minutes, 144 samples is enough for 12 hours of data, every 10 minutes, 24 hours of data, every 30 minutes. 72 hours of data, etc..

    And yes, you can test this in the sim.  Here I started the widget in the sim, closed  the widget (keeping the sim open), waited a while and then started the widget again, while printing what I see in onBackgroundData.  You see the array has two data points:

    onBackgroundData=[1721904378, 91.000000, 1721904678, 91.000000]

  • Thanks a bundle. I'll give it a try.  Certainly could not infer all of this from the Garmin API documentation.