Three Connect IQ things that each cost me days: swipe handling, request serialization, and simulator-only success

I've just finished a Connect IQ companion for an Android training app, and I want to write down three things I lost days to, because I couldn't find any of them stated plainly while I was searching.

1. BehaviorDelegate's page behaviors also fire for swipes — and they fire first.

If you extend BehaviorDelegate and implement onPreviousPage/onNextPage, a swipe up arrives as onNextPage before your onSwipe ever runs. If you're using up/down to increment a value, the result reads as inverted, and no amount of staring at onSwipe explains it — because onSwipe isn't what handled the gesture.

What worked: don't implement the page behaviors at all. Take raw onKeyPressed for the physical buttons and onSwipe for the gesture, and return true from both.

class PairDelegate extends WatchUi.BehaviorDelegate {
    // Raw key events, not onPreviousPage/onNextPage — page behaviors also
    // fire for swipes (swipe UP = onNextPage) and would invert them.
    function onKeyPressed(evt) {
        var k = evt.getKey();
        if (k == WatchUi.KEY_UP)   { _view.changeDigit(1);  return true; }
        if (k == WatchUi.KEY_DOWN) { _view.changeDigit(-1); return true; }
        return false;
    }

    function onSwipe(evt) {
        var dir = evt.getDirection();
        if (dir == WatchUi.SWIPE_UP)   { _view.changeDigit(1);  return true; }
        if (dir == WatchUi.SWIPE_DOWN) { _view.changeDigit(-1); return true; }
        return false;
    }
}

2. makeWebRequest has to be serialized by you.

Firing a second request before the first one's callback returns works in the simulator and fails on a real device. There's no queue underneath it. I ended up chaining every request through its callback — request N+1 is issued from N's response handler. Unglamorous, and it's the only thing that's been reliable.

3. The simulator is much more forgiving than the watch.

Which is really the general form of (2). Anything touching network, storage, or the activity lifecycle should be believed only after it runs on hardware. Related and still unexplained on my side: on a Fenix 7 I had to flip the swipe direction I got back to make it match what my finger did. I'd welcome an explanation — but if gestures feel backwards on one model and correct on another, that's a real thing, and worth testing per device family rather than assuming.

For context, the app is offline-first, pairs with a phone app as an equal peer rather than a slave display, and builds for 41 devices from one manifest (Fenix 6/7/8, Epix, Enduro, MARQ, Forerunner). Happy to go into any of it in more detail.

  • These are all things that have been the case for years,  Is this your first app?  Handling this stuff will soon be second nature.

    for #2, there is also a difference between IOS and Android.  BLE_QUEUE_FULL.  On iOS you can queue up to 3 requests, while Android, the max is 1

  • You're correct.  This is the first time I've created an app that runs on Garmin watch.  Definitely not the first development I've done but my experience has historically been in the realm of .Net web applications.  

    It has been fun dipping my toes into something new to me.

  • There is a learning curve with CIQ.  I started professionally programing 40 years ago, and started with CIQ in 2015.  Being new, try doing searches in the CIQ forums.  There is a whole bunch of knowledge there

    find the magnifying glass next to garmin and enter something your wondering about - say "behavior delegate".

    And be VERY careful if you try to use AI to find stuff.

  • Thank you for the useful advice Jim.