Acknowledged
CIQQA-4127

Add device identifier variable to Monkey Jungle

It would be very helpful if Monkey Jungle provided a built-in variable for the target device identifier (e.g. fr255, fenix7) during the build process. Currently, device-specific handling often requires defining paths per device. Introducing a predefined variable such as $(device) that resolves to the current target device would enable dynamic inclusion of device-specific directories in source and resource paths and remove the need to define paths separately for each device.

For example:

base.sourcePath=somedirectory/$(device)
  • Sorry to be captain semantics, but I don't think the CIQ team meant for this feature to be thought of as an "exclude annotation" where "exclude" is an adjective that modifies "annotation" (in other words, that an "exclude annotation is a kind of annotation with the 'exclude' quality associated with it").

    I understand your point, and your interpretation of the wording makes a lot of sense.

  • For these kinds of “features”, I use exclude annotations

    an exclude annotation in the build file determines which device gets which code

    Sorry to be captain semantics, but I don't think the CIQ team meant for this feature to be thought of as an "exclude annotation" where "exclude" is an adjective that modifies "annotation" (in other words, that an "exclude annotation is a kind of annotation with the 'exclude' quality associated with it").

    I only bring this up because literally everyone else talks about this feature this way, and I've found that it sometimes leads to some misunderstanding about how it works and/or how Garmin intends for it to be used. e.g. in one case, a dev stated that they were using this feature in the opposite way that Garmin had intended, when in fact they were using in exactly the way that Garmin had intended (which could be seen from the example in the Garmin docs which worked exactly the same way that the dev's usage worked.)

    I think the idea is that:

    - code such as classes, functions and variables can be annotated with symbols, in the source code

    - in the monkey.jungle, the excludeAnnotations directive specifies which annotated code should be excluded from the build

    In other words, regarding excludeAnnotations in monkey.jungle, I think:

    - exclude is a verb, not an adjective

    - excludeAnnotations is a directive specifying which annotations should be excluded. i.e. I think it means "exclude the following annotations", not "the following is a list of 'exclude annotations'"

    I think the wording of the official docs and associated comments in the official example backs up my interpretation

    developer.garmin.com/.../

    # Say that all products exclude declarations
    # with the annotation :roundVersion
    base.excludeAnnotations = roundVersion
    # Now say that the round products exclude
    # the regular version
    round.excludeAnnotations = regularVersion

    You're not defining "exclude annotations", you're specifying which annotated code to exclude from the build

    These are annotations (or annotated code) to be excluded, not "exclude annotations".

    i.e. in the above example: 

    base.excludeAnnotations = roundVersion

    This means "I want to exclude code which is annotated with roundVersion", not "I want to define roundVersion as an 'exclude annotation''". Note that the former makes a lot more sense than the latter, grammatically and conceptually.

    Yeah, we all know what you meant, but I like I suggested above, sometimes talking about things imprecisely leads to incorrect conclusions (not in this case, but in other cases).


  • But by default it already looks for source-$device/ , what am I missing?

    Sorry to be that guy (again), but I don't think it does.

    The compiler looks under resources-"$device"/ for a given device build (where $device is the CIQ device ID), in addition to the default resources/ folder, any applicable device-related family paths (e.g. resources-round-260x260), and the applicable resource paths with language modifiers (e.g. resources-round-260x260-eng).

    None of that stuff applies to source files. Actually, by default, all files named *.mc anywhere in the project (not just under source/) will be included in the build.

    You can verify all of that by:

    - reading the docs

    - trying it out

    - looking at default.jungle in the SDK bin/ folder

  • I don't know what your apps look like, but in mine I have "features", and each feature can have a number of variations.

    For these kinds of “features”, I use exclude annotations. Screen shape is a good example. Some visual elements are implemented differently for round and rectangular screens, and an exclude annotation in the build file determines which device gets which code. This is more cumbersome than checking the screen shape at runtime, but it helps conserve memory.

    I didn't understand what you wrote about the properties. Why do you need a class for each device? How is it different from using properties? You can only store user's preferences in properties or storage.

    So that is kind of the point. What I need is not user preferences but device-specific constants.

    To stick with your example: on five-button devices, the select button is on most devices at roughly the 30° position, but on many Forerunner devices it is closer to 27°. If I want to draw an input hint, I need to know that.

    For this, I use a DeviceProperties class that holds default values and can be overridden by a DevicePropertiesOverride class extending it. These overrides live in separate source directories with device identifiers as subfolders and are included via the build configuration.

    DeviceProperties follows a singleton pattern with a twist: when the instance is created, it checks whether a DevicePropertiesOverride exists and, if so, instantiates that instead.

    Compared to using properties: CIQ properties, as you pointed out, are not really intended for this use case. Once the app is installed, they cannot easily be overridden by an update. There are workarounds, such as versioned property names or handling updates in code, but those approaches are not particularly clean.

  • I don't know what your apps look like, but in mine I have "features", and each feature can have a number of variations. Some variations depend on display shape (i.e: round vs rectangle), some on display size, some on number of buttons, some whether the device has some hardware component, etc. I have a python script that generates the monkey.jungle file based on all these. But in terms of source, resource files I don't need to have 200 different files (one for each device), just a few one for each feature. And since I'm generating the monkey.jungle file, I can have whatever directory structure I want (similar to yours).

    I didn't understand what you wrote about the properties. Why do you need a class for each device? How is it different from using properties? You can only store user's preferences in properties or storage. If they saved some value then either you use it or you don't, but you don't really need a class for each device for that. The same code can deal with every device. You can have a few inputs if you want to compare things to the default. But these defaults usually depend on screen size, etc, so again, I just have a file with the constants in each directory (1 directory can be 1 variation of 1 feature), and my getters look like: getConfig(key, defaulValue). If you want to be fancy, then you can even save the default at the time the app was installed, and compare whether the default of the current version is different from the default at the time the app was installed, though I'm not sure what can you do with it if it's different from the original default. Would you override it with the new default, even though the user seemingly wanted something different from the value you thought will be the best choice for most users?