Awesome Maps

I’d like to introduce the results of a project I’ve been working on for some time.  Maps have always been a passion of mine (so much that I went to university to be a cartographer; ended up studying as a geodesist and have worked in related fields ever since).  It was fun to reapply some old theory and build on my understanding of Garmin image management and the infrastructure I put together for my high-resolution Rain Radar app.

The aim was to bring on-demand mapping to *all* devices, not just those Garmin deemed worthy of offline mapping.  To deliver an app with different, zoomable cartography using Open Hiking Map and satellite imagery and unique capabilities with Ordnance Survey (GB) maps on a cached tiled map display.

App Store Link (with YouTube video): https://apps-developer.garmin.com/apps/f0ffb7a3-dc56-4ac2-9428-08250c816474

(as usual, be nice with direct feedback, not critical reviews)

There are plenty of ideas on how to add capabilities to this, but for this forum here are some points that might be interesting to developers were;

Maxing the Storage Cache: this was a real win for tiled maps – delivering decent performance and reducing web requests.  Maintaining the cache and gracefully handling usage limits was work but through my Exception catching web service I'll (hopefully) get to build a pattern of devices and storage size limits.

No-Input Payment Authorisation: I don’t like Garmin’s (or other’s) terrible on-device UI’s for inputting alphanumeric authorisation codes or email addresses for registration and licensing – so I worked out a couple of web services for seamless (no user input on the device) integration and updates with a Merchant of Record handler.

QR Code (ScanCode) Experiment: I quite liked adding the ability to scan a code for my license info / payment, rather than just opening a openWebPage () link via GC.  This allows any third-party devices to open the links.

Annoying Different Exceptions Thrown on Imagery: across 54 devices, the same code is used to handle the same (or similar) images, but 5 devices decide to do different things!  The following x2 exception messages are thrown by a handful of devices;

     "Source must be native color format" - reported by Forerunner165 and EdgeMTB

     “Source must not use a color palette" - reported by InstinctCrossover, Venu4-41 and Forerunner570

Another ongoing issue I still have is that the codebase that runs on the Sim for 54 devices, fails for only (if I tested them all!) the Edge 850.  I can observe via breakpoints and console that my glance view text is being updated in code, however there is just no screen update at all.  I would blame the Sim but in my server logs I have 1000’s of requests and none are from an 850 so I assume it’s a real-world fail as well.  Nothing in Era either, as there is no crash (Sim runs, just no UI update) even with forced requestUpdate().  Anyone with an Edge850 pls let me know...

Finally, my wishlist;

 * better access to info/exceptions on graphics memory pool

 * more standardisation between devices for image handling

 * more storage on devices which could be easily provide more

 * better information on connectivity (vehicles connected to mobile phones know signal strength and battery of the connected device so a watch/head unit should also be able to know in order to allow user to make informed decisions without independently looking at the phone)

 * proper API access to the stack-trace other than println() which then requires extraction off the device (put it in an extended exception)

  • Awesome Maps v2.0

    Update – addition of USGS, IGN France and IGN España (Spain) local mapping data.  And a datafield version in parallel.  And more integrated menus and touch-screen controls. And YouTube videos, phew!

    Notes of interest for the developer community…

    Shared licensing: as per a recent, pertinent discussion started on a sister thread (https://forums.garmin.com/developer/connect-iq/f/discussion/434145/unique) I wanted to have a no-data-entry seamless licence option without the use of Garmin Pay – to support a wide range of devices and have control (because we all want control).  It was only after reading the post above that I fully understood that the uniqueIdentifier property was not device; but device+app and hence unable to use that to generate a common ID from 2 distinct apps.  The discussion give various innovative and clever approaches, but none matching my needs.  Instead I use part of the uniqueIdentifier which, based on research, is still pretty unique in the grand scale of things, and a shared-space hack on the devices (completely valid and exposed on the API) that is readable from 2+ apps to generate and share the same ID/license.

    Datafield optimisation: having started with a glance app/widget, I thought sharing the code to a datafield would be easy. Ha!  Unfortunately, due to a couple of bits of complex maths with lots of variables (coordinate system projections and intersects on rotated overlapping rectangles on every compute()!) I hit the stack limit.  There is a very useful post here https://forums.garmin.com/developer/connect-iq/f/discussion/409273/stack-overflow

    Is it because datafields run compute() and onUpdate() pretty much simultaneously – hence requiring a better approached to managing that stack?  Or just because there are less memory in datafields than apps [that have no compute()] because you can have multiple-simultaneous data fields and therefore need run with smaller stack allocation?  Anyway, combining many member variables into arrays helped and the datafield version came out this week;

    https://apps-developer.garmin.com/apps/7a4f45d8-c126-459a-a81c-1071bf09c33c

    One thing I may ask in the other forum pages – is it better to pass objects around in function calls and reference them as variables - or instead reference global objects without using function parameters and use $ instead?

  • Awesome Maps continues to develop with the addition of dedicated per-country maps from LINZ (New Zealand), Kartverket (Norway), BGDI swisstopo (Switzerland) and NGI (Belgium).

    There are also now touch-screen controls for North-up or heading-based orientation options, multiple zoom levels with pan/drag to move the map for exploring and an optional show "snail trail" menu for the route recently followed.

    For developer interest, I have seen continued odd behaviour with drawBitmap2 and a Transform matrix applied to the images.  With (ONLY) the Forerunner70, Forerunner165 and Instinct3 these three devices thrown an exception “Source must be native color format”.  This is replicable in the Sim, BUT for the Forerunner70, Forerunner165 it looks like this is a false-positive error (maybe from a previous firmware version that did not support the format?).  So for the FR165 and 70 I see my images are actually rotated, but the exception is still thrown – which I then need to handle in the catch with per-device logic to manage the Instinct3 differently with a fallback drawing approach!

    Of course, I can only test this in the Sim and really would like anyone with a FR70 or 165 to confirm they can actually see maps OK.  There is also a new “Safe Mode” switch in the settings/properties (exposed through CIQ and on-device menus) to use the alternative behaviour on handling the exception if required; but requires real-world validation.  Please DM me or use the app contact pages for a test license if interested.

  • Awesome Maps v4+

    Back on the main thread with this update ... if you missed the v3+ update it got out-of-sync but you can see it here: Awesome Maps v3+ 

    TL;DR – with ‘Offline Mode’ and route previews v4.2 of the app now has the core functionality that I wanted it to deliver in the stretch vision I had at the start of the year.

    For a quick YouTube overview, see: https://youtu.be/bH-7-LFEk3A

    As usual, for this more developer-focussed forum here, are technical points and topics for the community that have come up for me recently…

    Monetisation

    Anyone clicking through the app can easily see I use Dodo payments as my MoR (merchant of record) to process payments.  This month they released a couple of new features that I have implemented – it definitely seems more of a hands-on solution than something like KiezelPay which I would probably adopt if I wanted something simpler.  The new payment options that are interesting are “Purchasing Power Parity” which allows a percentage pricing to be applied to different countries (for example the India market has different purchasing power to the US so the payment fee adapts semi-automatically).  And “Charm Pricing” whereby in local currency conversion the price automatically adopts a more attractive price style (for example instead of $9.99 becoming 957.5 rupees it becomes 949.9 rupees).

    Odd Exceptions

    I’ve recently been tracing an odd exception from the waypoint iterator on older Venu2 devices.

        UnexpectedTypeException: Expected String, given null

    Reasonable looking error, however the only place in the named function where I do a string operation is on the result from getName() ... which according to the documents and compiler warnings is only ever a String, not a null.

        var iterWaypoints = PersistedContent.getWaypoints();

        var contentWaypoint = iterWaypoints.next();

        while (null != contentWaypoint) {

          var szWaypointPrefixOrNull = contentWaypoint.getName().substring(X, Y);

         ...

    I wonder if the API changed definition or was never implemented correctly?  Anyway, now to workaround I get a compiler warning (SDK 9.2.0) that I am doing a null check against something that should never be null and so I wonder if this code check will then be optimised-out in the binary.  UPDATE: I now use an (... instanceof String) check which hopefully does the job and won't get optimised out as an invalid null check.

    Terrible Review Process

    It’s been mentioned elsewhere but the permitting of 1* reviews without any comment or indeed any idea what device or version the review was on is intolerable.  This provides zero value to the developer who cannot get further feedback or address any issue without knowing what is it.  It provides zero value to simply negating the overall review score for comparisons.  It also invites abuse of the system by allowing effective anonymity.  IMHO all reviews should require some level of user content and include device/version information… though the hundreds of single-word 5* reviews on some of the ‘trending apps’ demonstrate that this simple check would be almost as invalid as a process.  Is there no pride in your system Garmin?