Acknowledged

Media.SyncDelegate JSON parsing bug in CIQ 4.1.5

Given the following JSON payload: {"foo": 42}

If makeWebRequest fetches that payload from outside a Media.SyncDelegate context, 42 is parsed as Lang.Number. However, if the makeWebRequest fetch is made within a Media.SyncDelegate context, it will be parsed as a Lang.Float.

This only occurs in CIQ 4.1.5. Previous versions don't exhibit this behavior.

LOGGING OUTPUT

- CIQ 4.1.5

Making request outside of SyncDelegate
responseCode=200 data={foo=>42}
[OK] saw a number
Making request inside of SyncDelegate.onStartSync()
responseCode=200 data={foo=>42.000000}
[FAIL] saw a float
Making request outside of SyncDelegate
responseCode=200 data={foo=>42}
[OK] saw a number

- CIQ 4.1.4
Making request outside of SyncDelegate
responseCode=200 data={foo=>42}
[OK] saw a number
Making request inside of SyncDelegate.onStartSync()
responseCode=200 data={foo=>42}
[OK] saw a number

- CIQ 4.1.3

Making request outside of SyncDelegate
responseCode=200 data={foo=>42}
[OK] saw a number
Making request inside of SyncDelegate.onStartSync()
responseCode=200 data={foo=>42}
[OK] saw a number

Example Code

// App.mc

import Toybox.Application;

import Toybox.Communications;

import Toybox.Lang;

import Toybox.Media;

import Toybox.System;

import Toybox.WatchUi;



class FloatJSONBugApp extends Application.AudioContentProviderApp {



    var inFlight = false;



    function initialize() {

        AudioContentProviderApp.initialize();

    }



    // onStart() is called on application start up

    function onStart(state as Dictionary?) as Void {

    }



    function makeRequest(msg) {

        if (self.inFlight) {

            return;

        }

        System.println(msg);

        self.inFlight = true;

        var url = "https://garmin-check-tls.s3.amazonaws.com/floatbug.json";

        var parameters = {};

        var options = {};

        var responseCallback = self.method(:onResponse);

        Communications.makeWebRequest(url, parameters, options, responseCallback);

    }



    function onResponse(responseCode, data) {

        self.inFlight = false;

        var msg = "responseCode=" + responseCode + " data=" + data;

        System.println(msg);

        if (responseCode != 200) {

            return;

        }

        switch (data["foo"]) {

        case instanceof Lang.Float:

            System.println("[FAIL] saw a float");

            break;

        case instanceof Lang.Number:

            System.println("[OK] saw a number");

            break;

        default:

            System.println("[FAIL] saw other");

            break;

        }



    }



    // onStop() is called when your application is exiting

    function onStop(state as Dictionary?) as Void {

    }



    // Get a Media.ContentDelegate for use by the system to get and iterate through media on the device

    function getContentDelegate(arg as PersistableType) as ContentDelegate? {

        return new FloatJSONBugContentDelegate();

    }



    // Get a delegate that communicates sync status to the system for syncing media content to the device

    function getSyncDelegate() as SyncDelegate? {

        return new FloatJSONBugSyncDelegate();

    }



    // Get the initial view for configuring playback

    function getPlaybackConfigurationView() as Array<Views or InputDelegates>? {

        self.makeRequest("Making request outside of SyncDelegate");

        return [ new FloatJSONBugConfigurePlaybackView(), new FloatJSONBugConfigurePlaybackDelegate() ] as Array<Views or InputDelegates>;

    }



    // Get the initial view for configuring sync

    function getSyncConfigurationView() as Array<Views or InputDelegates>? {

        return [ new FloatJSONBugConfigureSyncView(), new FloatJSONBugConfigureSyncDelegate() ] as Array<Views or InputDelegates>;

    }



}



function getApp() as FloatJSONBugApp {

    return Application.getApp() as FloatJSONBugApp;

}



// SyncDelegate.mc

import Toybox.Application;

import Toybox.Communications;

import Toybox.Lang;

import Toybox.Media;

import Toybox.System;



class FloatJSONBugSyncDelegate extends Media.SyncDelegate {



    function initialize() {

        SyncDelegate.initialize();

    }



    // Called when the system starts a sync of the app.

    // The app should begin to download songs chosen in the configure

    // sync view .

    function onStartSync() as Void {

        var app = Application.getApp();

        app.makeRequest("Making request inside of SyncDelegate.onStartSync()");

        Media.notifySyncComplete(null);

    }



    // Called by the system to determine if the app needs to be synced.

    function isSyncNeeded() as Boolean {

        return true;

    }



    // Called when the user chooses to cancel an active sync.

    function onStopSync() as Void {

        Communications.cancelAllRequests();

        Media.notifySyncComplete(null);

    }

}

Parents Comment Children
No Data