Here are a few Complication samples

Hey folks, the Complication examples in the Core Topics documentation doesn't really help you build an end-to-end demo.

So, with the help of others here, I've prepped two Complication samples for System 6 devices that;

  1. Subscribe to Complication callbacks, and display their data in a watchface, and
  2. Pressing them within a bounding box (onPress) to launch the Complication widget.

This code deals with square press bounds;
https://github.com/sunpazed/garmin-complicate

While this one deals with round press bounds;
https://github.com/sunpazed/garmin-complicate-circle

Pick whichever works for your design or approach.

Here's a video of what the "onPress" does with one of my watchfaces;
https://www.youtube.com/watch?v=Gp-m-2xvfM0

The "onPress" doesn't do anything yet, but hopefully we'll see this change with a new SDK or firmware update in the future.

Happy to hear any feedback, and please contribute / improve these code samples for everyone.

  • Perfectly clear, thanks. "returns true on some devices even if they don't support solar - solarIntensity is available." is the part I didn't get before.

  • Hi I found this message in a thread while searching for another topic in the forum:

    Not really a work-around.  The way to do things if you are using a background service.  In AppBase, some things are only called for the main app, some, only when the background service runs, and some for both. onStart() is one that's called in both cases.

    Do you know where I can find more information about this? What functions are called for the main process vs the background serice? Today I'm using a lot of "if (in_background) but If I knew more about how background services execute in AppBase I could probably move around the code that I need to run only in fg or only in bg. TIA.

  • Not sure if it's anywhere in the doc, but here's a basic list.  You can also see if you add a println to a function to see.

    I posted a sample a few years back that already has a bunch of println calls: https://forums.garmin.com/developer/connect-iq/f/discussion/5287/very-simple-sample-of-a-watch-face-with-a-background-process

    Both:

    ininialize(), onStart().onStop()

    Main App only:

    onSettingsChanged, onBackgroundData(),getInitalView(),getGlanceView(),getSettingsView()

    Background only:

    getServiceDelegate(),onAppInstall(), onAppUpdate()

    I probably missed a few, but they are things I really don't use.

  • so helpful! Thanks Jim

  • In this sample, I am curious how this function passes compiler.  I can find no place in the code where a "var WatchView" appears.  I am confused as to why this doesn't through a compiler error.  Does the compiler just assume something because it is the class name?  How does it know which instance of WatchView is being referenced?

  • In this sample, I am curious how this function passes compiler.  I can find no place in the code where a "var WatchView" appears.  I am confused as to why this doesn't through a compiler error.  Does the compiler just assume something because it is the class name?  How does it know which instance of WatchView is being referenced?

    I assume you're referring to the first example on the OP (https://github.com/sunpazed/garmin-complicate/) although the principle is the same for both.

    - WatchView is actually instantiated and returned by WatchApp's getInitialView() function:

    https://github.com/sunpazed/garmin-complicate/blob/41e29c3b2cd42353de643a0ec2a6a7ca083c9f51/src/WatchApp.mc#L43-L45

        function getInitialView() {
            return [ new WatchView(), new WatchDelegate()  ];
        }
    

    We could ask the same question about WatchApp itself? How does the Garmin device firmware know what to do with the "WatchApp" class. The answer that manifest.xml specifies the application entry point, which happens to be WatchApp.

    https://github.com/sunpazed/garmin-complicate/blob/41e29c3b2cd42353de643a0ec2a6a7ca083c9f51/manifest.xml#L4

    <?xml version="1.0"?>
    <!-- This is a generated file. It is highly recommended that you DO NOT edit this file. -->
    <iq:manifest xmlns:iq="http://www.garmin.com/xml/connectiq" version="3">
        <iq:application entry="WatchApp" id="dbf6f10dbb931c1505dd1ee3b892ef98" launcherIcon="@Drawables.LauncherIcon" name="@Strings.AppName" type="watchface" minSdkVersion="1.3.1">

    To reiterate all of that in chronological order:

    - The name of the app class is specified in manifest.xml, in the entry property of the iq:application tag. In this case, it's WatchApp (but it could be called something else.)

    - This is a watchface, and just like most other app types, its app class needs to provide the system with an initial view via the getInitialView() function. In this specific example, an instance of the WatchView class is created and returned from getInitialView(). WatchView could also be called something else - the name isn't significant

  • Thank you.  I saw the code in getInitialView().  I was assuming that would return an unnamed WatchView in the container.  It seems a little different to me than what I remember from Java/C# ... and the Monkey C documentation specifically says all you must use var to declare a variable.  That documentation isn't exactly the greatest so I just wasn't sure if it was an omission.  I also understand the manifest and how that works but thank you for confirming.

  • I was assuming that would return an unnamed WatchView in the container. 

    It will.

    It seems a little different to me than what I remember from Java/C#

    Java, C# and all the major programming languages will allow you to pass an unnamed value to a function or return it from a function.

    Variables are used to store values, but just because you have a value, it doesn't mean you need a variable.

    You don't need a variable unless you want to refer to its value more than once, or change its value.

    and the Monkey C documentation specifically says all you must use var to declare a variable

    Yes that's true. What they mean is that you can't just use a variable without declaring it. As a counter example, old javascript allows global variables to be used without prior declaration. e.g.

    function f() {
      x = 42; // assume x is not declared anywhere in the code
      return x;
    }
    
    f();

    This code will implicitly create a global variable named x when "x = 42" is executed. Most programming languages, including modern javascript, forbid this behavior for obvious reasons.

    Going back to getInitialView(), nothing like that is happening:

        function getInitialView() {
            return [ new WatchView(), new WatchDelegate()  ];
        }

    You can think of this code as:

    1. Creating a new instance of the WatchView class

    2. Creating a new instance of the WatchDelegate class

    3. Creating an array with two elements: the values from 1. and 2.

    4. Returning the array from 3.

    There's no variables involved here.

    But we could easily rewrite getInitialView() to use variables, although it would make no difference.

        function getInitialView() {
            var view = new WatchView();
            var delegate = new WatchDelegate();
            return [view, delegate];
        }

    As you can see, it's pointless to create the view and delegate variables in this case, as they're only used once, and the code which initializes their values is very short.

    In some cases, you may wish to create a variable even if it's only used once, if it avoids having to write a very long or complicated line of code which would be hard to read, understand or maintain.

    In another case, we may have designed our app so that the view takes the delegate as a constructor argument or vice versa. In that case a variable would be necessary.

    e.g. Suppose WatchDelegate's constructor requires the WatchView instance to be passed in, for some reason. (Maybe the delegate handles a button click which triggers an action in the view, so the delegate needs to be able to call a function in the view class.) Now we need to assign the WatchView instance to a variable, since its value is used twice.

        function getInitialView() {
            var view = new WatchView();
            return [ view, new WatchDelegate(view)  ];
        }

  • Very helpful.  Thank you.  Another question, I noticed in the sample that the type checking was set to 0. Without that in the jungle file, the sample throws a compile error.  I noticed in the API docs there is a ComplicationChangedCallback typedef.  I could not immediately find however a good example of how to use this typedef with a callback function.  How do you do that?  Given the unfamiliar to me syntax for referencing the callback I'm not even sure how one would do something simple like say just cast it to the right type?

  • See https://forums.garmin.com/developer/connect-iq/f/discussion/349473/simple-example-wf-that-shows-a-bunch-of-things

    The zip in the first post is a watch face that subscribes to COMPLICATION_TYPE_HEART_RATE and it build clean with the type check at the default level.  No typedef added or changed for the callback. (6.3.1 and 6.4.0 SDK)..