Issue debugging settings

I am developing an app for the Fenix 3 and having some issues with adding some settings/properties to is. I added settings for the colos used within the UI. Within the simulator everything works like it should, changing, resotring etc. To test it on my watch correctly is added the app in the ConnectIQ store becaus that is the only way to test te changing of settings. Tha android app showed the correct settings and selection lists. Settings could be stored and it looked promising. But now when i start the app it it crashing and not working anymore. I cannot reproduce this in the simulator and cannot debug on my watch. What can i do to find out what is wrong?

I use the following resource settings:

<property id="COLOR_Background" type="number">0x000000</property>

<setting propertyKey="@Properties.COLOR_Text" title="@Strings.UI_STR_Text_color">
<settingConfig type="list">
<listEntry value="0xFFFFFF">@Strings.UI_COLOR_White</listEntry>
<listEntry value="0xAAAAAA">@Strings.UI_COLOR_Gray</listEntry>
<listEntry value="0x555555">@Strings.UI_COLOR_Dark_Gray</listEntry>
<listEntry value="0x000000">@Strings.UI_COLOR_Black</listEntry>
<listEntry value="0xFF0000">@Strings.UI_COLOR_Red</listEntry>
<listEntry value="0xAA0000">@Strings.UI_COLOR_Dark_Red</listEntry>
<listEntry value="0x00FF00">@Strings.UI_COLOR_Green</listEntry>
<listEntry value="0x00AA00">@Strings.UI_COLOR_Dark_Green</listEntry>
<listEntry value="0x00AAFF">@Strings.UI_COLOR_Blue</listEntry>
<listEntry value="0x0000FF">@Strings.UI_COLOR_Dark_Blue</listEntry>
<listEntry value="0xFF5500">@Strings.UI_COLOR_Orange</listEntry>
<listEntry value="0xFFAA00">@Strings.UI_COLOR_Yellow</listEntry>
<!--COLOR_PURPLE = 0xAA00FF Purple. Not valid on Fenix 3 or D2 Bravo. Use 0x5500AA instead. -->
<listEntry value="0xFF00FF">@Strings.UI_COLOR_Pink</listEntry>
</settingConfig>
</setting>
  • There have been problems with Garmin Connect Mobile and the settings system. One of the problems is that the setting can come back as the wrong type (you expect a Lang.Number, but the system provides a Lang.String that is convertible to the number, but will throw an exception if you use it in a context where a number is expected). You should be able to combat this problem by checking the type before using the value.

    I've written a wrapper around the object store in an attempt to avoid this problem. I haven't used this in production yet, but it seems that it should work. If the value returned by the object store is the correct type, the value is returned. If the value is a string, a conversion is made. Otherwise, the default value provided is returned.

    module Settings {
    
    using Toybox.Application as App;
    using Toybox.Lang as Lang;
    
    function setProperty(name, val) {
        App.getApp().setProperty(name, val);
    }
    
    function getProperty(name, initial) {
        var val = App.getApp().getProperty(name);
        if (val != null) {
            return val;
        }
    
        return initial;
    }
    
    function deleteProperty(name) {
        App.getApp().deleteProperty(name);
    }
    
    function clearProperties() {
        App.getApp().clearProperties();
    }
    
    function getStringProperty(key, initial) {
        var value = App.getApp().getProperty(key);
        if (value != null) {
    
            if (value instanceof Lang.String) {
                return value;
            }
            else if (value instanceof Lang.Double ||
                value instanceof Lang.Float ||
                value instanceof Lang.Long ||
                value instanceof Lang.Number) {
                return value.toString();
            }
        }
    
        return initial;
    }
    
    function setStringProperty(key, value) {
        assert(value instanceof Lang.String);
        App.getApp().setProperty(key, value);
    }
    
    function getBooleanProperty(key, initial) {
        var value = App.getApp().getProperty(key);
        if (value != null) {
    
            if (value instanceof Lang.Boolean) {
                return value;
            }
            else if (value instanceof Lang.Double ||
                value instanceof Lang.Float ||
                value instanceof Lang.Long ||
                value instanceof Lang.Number ||
                value instanceof Lang.String) {
                return value.toNumber() != 0;
            }
        }
    
        return initial;
    }
    
    function setBooleanProperty(key, value) {
        assert(value instanceof Lang.Boolean);
        App.getApp().setProperty(key, value);
    }
    
    function getNumberProperty(key, initial) {
        var value = App.getApp().getProperty(key);
        if (value != null) {
    
            if (value instanceof Lang.Number) {
                return value;
            }
            else if (value instanceof Lang.Boolean) {
                return value ? 1 : 0;
            }
            else if (value instanceof Lang.Double ||
                value instanceof Lang.Float ||
                value instanceof Lang.Long ||
                value instanceof Lang.String) {
                return value.toNumber();
            }
        }
    
        return initial;
    }
    
    function setNumberProperty(key, value) {
        assert(value instanceof Lang.Number);
        App.getApp().setProperty(key, value);
    }
    
    
    function getFloatProperty(key, initial) {
        var value = App.getApp().getProperty(key);
        if (value != null) {
    
            if (value instanceof Lang.Float) {
                return value;
            }
            else if (value instanceof Lang.String) {
                return value.toFloat();
            }
            else if (value instanceof Lang.Boolean) {
                return value ? 1.0f : 0.0f;
            }
            else if (value instanceof Lang.Double ||
                value instanceof Lang.Long ||
                value instanceof Lang.Number) {
                return value.toFloat();
            }
        }
    
        return initial;
    }
    
        function setFloatProperty(key, value) {
            assert(value instanceof Lang.Float);
            App.getApp().setProperty(key, value);
        }
    }



    Another problem was with the list setting type where the index of the property was coming through instead of the value. I believe that this can only be fixed by changing your resource definition and then using a lookup table in your source. For example.

    <setting propertyKey="@Properties.COLOR_Text" title="@Strings.UI_STR_Text_color">
      <settingConfig type="list">
        <listEntry value="0">@Strings.UI_COLOR_White</listEntry>
        <listEntry value="1">@Strings.UI_COLOR_Gray</listEntry>
        <listEntry value="2">@Strings.UI_COLOR_Dark_Gray</listEntry>
        <listEntry value="3">@Strings.UI_COLOR_Black</listEntry>
        <listEntry value="4">@Strings.UI_COLOR_Red</listEntry>
        <listEntry value="5">@Strings.UI_COLOR_Dark_Red</listEntry>
        <listEntry value="6">@Strings.UI_COLOR_Green</listEntry>
        <listEntry value="7">@Strings.UI_COLOR_Dark_Green</listEntry>
        <listEntry value="8">@Strings.UI_COLOR_Blue</listEntry>
        <listEntry value="9">@Strings.UI_COLOR_Dark_Blue</listEntry>
        <listEntry value="10">@Strings.UI_COLOR_Orange</listEntry>
        <listEntry value="11">@Strings.UI_COLOR_Yellow</listEntry>
        <listEntry value="12">@Strings.UI_COLOR_Purple</listEntry>
        <listEntry value="13">@Strings.UI_COLOR_Pink</listEntry>
      </settingConfig>
    </setting>



    var color_map = {
      0 => Gfx.COLOR_WHITE,
      1 => Gfx.COLOR_LT_GRAY,
      2 => Gfx.COLOR_DK_GRAY,
      3 => Gfx.COLOR_BLACK,
      4 => Gfx.COLOR_RED,
      5 => Gfx.COLOR_DK_RED,
      6 => Gfx.COLOR_GREEN,
      7 => Gfx.COLOR_DK_GREEN,
      8 => Gfx.COLOR_BLUE,
      9 => Gfx.COLOR_DK_BLUE,
      10 => Gfx.COLOR_ORANGE,
      11 => Gfx.COLOR_YELLOW,
      12 => Gfx.COLOR_PURPLE,
      13 => Gfx.COLOR_PINK
    }
    
    function get_color_for_value(val) {
        var color = color_map[val];
        if (color != null) {
          return color;
        }
    
        return Gfx.COLOR_RED;
    }
    


    I believe this issue has been fixed, so it may not be a concern any more.

    As for this issue...

    <!--COLOR_PURPLE = 0xAA00FF Purple. Not valid on Fenix 3 or D2 Bravo. Use 0x5500AA instead. -->



    You can create device-specific resource definitions that will override those used by the default configuration (i.e., you can provide a definition of the setting in resources-fenix3/properties/properties.xml that has one value for purple, and another definition for all other devices in resources/properties/properties.xml. There is a section in the programmers guide about this.

  • There still seem to be problems with Garmin Connect Mobile and app settings. It appears that Garmin Connect Mobile does not necessarily respect the type defined for an app setting property. In particular, it can send floating point values for app setting properties that are defined as integers.

    When I define the property for a setting (paceWindow_prop in this example) in properties.xml, I define it as an integer (number) and not a float:

    <properties>
    <property id="paceWindow_prop" type="number">10</property>
    </properties>


    I also specify the relevant minimum and maximum values:

    <settings>
    <setting propertyKey="@Properties.paceWindow_prop" title="@Strings.paceWindow_title">
    <settingConfig type="numeric" min="1" max="60"/>
    </setting>
    </settings>


    However, I have received reports from users who set an integer value (for instance, 60) in Garmin Connect Mobile for Android and then have the data field run into an error when a float (for instance, 60.0000000) gets passed to it instead. I have got around the issue by having the data field convert the value it receives into an integer:

    paceWindow = Application.getApp().getProperty("paceWindow_prop");
    paceWindow = (paceWindow != null) ? paceWindow.toNumber() : 10;


    It would be helpful if Garmin Connect Mobile set the value for the property as the correct type.

    Absent that, it could be useful to add a sentence in the section on app settings in the programmer’s guide noting that Garmin Connect Mobile may send a value for a setting that is of a different type than what is defined for the corresponding property so that developers are aware of this issue and check and fix property types at the app end. Since the type attribute is required for a property tag, I was expecting this to be taken into account by Garmin Connect Mobile, and only realised this was not the case after getting user feedback and finding this thread with the helpful post by TRAVIS.VITEK.
  • Although it's not in the programmers guide, it is in the "New Developer FAQ2" Sticky at the top of the forum:

    https://forums.garmin.com/showthread.php?359183-New-Developer-FAQ-2
  • I should have seen that, it is prominent enough. Thanks.