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)
Parents
  • 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.

Comment
  • 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.

Children
  • 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).