I'm having a problem in a real device I cannot reproduce in the simulator.

In the simulator, I animate a BG layer and draw text over it in a small foreground layer. This works fine in all supported devices in the simulator (Vivoactive 4, Venu, Fenix 6 pro, etc). This is a View that is pushed from the "main one" upon positive check of a confirmation dialog set variable.

But when testing in Venu (the only test device I have), the view blinks the foreground layer (text) and goes to black, the widget doesn't crash as input is still handled correctly and I can navigate away from the black screen.

In the simulator everything works as intended, the animation loops correctly in the background and the text is displayed over it.

Could this be because the real device makes more calls to onUpdate than the simulator? If so, how can I simulate it?

Maybe also related: I was having a problem where a confirmation dialog was being pushed 4 times in the real device (on update called several times), while in the simulator it was only pushed once. I solved this with a control variable, but there is a difference for sure.

I'm developing using SDK 3.1.8.

Can anyone help me make sense of this?

  • I was having a problem where a confirmation dialog was being pushed 4 times in the real device (on update called several times)

    You should not be pushing views from onUpdate() or onPartialUpdate(). The simulator doesn't implement view transitions at this time, so it will only call onUpdate() once during a transition, but on the device onUpdate() may be called multiple times before the view transition is complete. This is likely the difference you're seeing.

    But when testing in Venu (the only test device I have), the view blinks the foreground layer (text) and goes to black, the widget doesn't crash as input is still handled correctly and I can navigate away from the black screen.

    This is possibly a bug. Are you updating the entire screen during the onUpdate() call, or are you just updating parts of the screen? I ask because it is (currently) expected that you are updating the entire screen in onUpdate(). You can get away with this for older devices, but newer devices are clearing the screen to black before calling onUpdate(). This difference in behavior is not shown in the simulator.

    If you haven't already seen this thread, it might be useful to have a look.

  • FYI, I'm not moving this to Bug Reports because we already have WERETECH-7828 and WERETECH-8406 for the issue of clearing the screen to black, and WERETECH-846 covered adding transition support to the simulator.

  • Thanks for the hints,

    I'll try moving the view pushing logic out of the onUpdate. The question is where?

    My idea is to keep the view stack "shallow", since keeping views consumes memory, and I had usability issues with the "back" action when stacking too many pages. I have only a maximum of two views stacked at a time, the main one + another based on an action/context - but in the end, I must prioritise stability, if my approach is not correct from a CIQ widget design stand-point, I can refactor the logic to respect it.

    The problematic page is a "summary" view, this page is loaded from a variable set in a menu action, whose value depends on the existence of data to build the summary (user finishes the session).
    I then load the summary page from the "main" view checking this var, and unset it after pushing the "summary" view. In my mind this should work (works in the simulator), but I might be neglecting something that is handled differently in the device itself.
    In the onUpdate() I call clear and make the draw calls - I'm drawing on a layer that should only take a bit of area in the center of the screen. The animationLayer is running on loop as background, and is called in onShow().

    I made a clip to better show the behavior in the simulator:
    /cfs-file/__key/communityserver-discussions-components-files/12/Screen-Recording-2020_2D00_06_2D00_19-at-17.01.29.mov

    I added some logging in the different parts of the view and reproduced the exact same steps in the device and simulator:

    Simulator:

    0 Summary view onLayout | high mem version!
    0 Summary view onLayout | animation capable!
    0 Summary view onLayout | animation layer added!
    0 Summary view onLayout | text layer added!
    0 Summary view onShow | entered!
    0 Summary view onShow | calling play!
    0 Summary view play | animation play started!
    0 Summary view onUpdate | Stop status = 0| Start date = 1592502360
    1 Summary view onUpdate | using foreground text dc!
    1 Summary view onUpdate | colors set!
    1 Summary view onUpdate | dc clear!
    1 Summary view onUpdate | rendered label!
    1 Summary view onUpdate | rendered elapsed!
    1 Summary view onUpdate | rendered remaining!
    1 Summary view onUpdate | Stop status = 0| Start date = 1592502360
    2 Summary view onUpdate | using foreground text dc!
    2 Summary view onUpdate | colors set!
    2 Summary view onUpdate | dc clear!
    2 Summary view onUpdate | rendered label!
    2 Summary view onUpdate | rendered elapsed!
    2 Summary view onUpdate | rendered remaining!
    2 Summary view play | animation play started!
    2 Summary view animation event | animation complete!
    2 Summary view play | animation play started!
    2 Summary view animation event | animation complete!
    2 Summary view play | animation play started!
    2 Summary view animation event | animation complete!
    2 Summary view play | animation play started!
    2 Summary view animation event | animation complete!
    2 Summary view play | animation play started!
    2 Summary view animation event | animation complete!
    2 Summary view onUpdate | Hiding!
    2 Summary view onUpdate | deleting start date!
    

    Device:

    0 Summary view onLayout | high mem version!
    0 Summary view onLayout | animation capable!
    0 Summary view onLayout | animation layer added!
    0 Summary view onLayout | text layer added!
    0 Summary view onShow | entered!
    0 Summary view onShow | calling play!
    0 Summary view play | animation play started!
    0 Summary view onUpdate | Stop status = 0| Start date = 1592502300
    1 Summary view onUpdate | using foreground text dc!
    1 Summary view onUpdate | colors set!
    1 Summary view onUpdate | dc clear!
    1 Summary view onUpdate | rendered label!
    1 Summary view onUpdate | rendered elapsed!
    1 Summary view onUpdate | rendered remaining!
    1 Summary view onUpdate | Stop status = 0| Start date = 1592502300
    2 Summary view onUpdate | using foreground text dc!
    2 Summary view onUpdate | colors set!
    2 Summary view onUpdate | dc clear!
    2 Summary view onUpdate | rendered label!
    2 Summary view onUpdate | rendered elapsed!
    2 Summary view onUpdate | rendered remaining!
    2 Summary view onUpdate | Stop status = 0| Start date = 1592502300
    3 Summary view onUpdate | using foreground text dc!
    3 Summary view onUpdate | colors set!
    3 Summary view onUpdate | dc clear!
    3 Summary view onUpdate | rendered label!
    3 Summary view onUpdate | rendered elapsed!
    3 Summary view onUpdate | rendered remaining!
    3 Summary view onUpdate | Stop status = 0| Start date = 1592502300
    4 Summary view onUpdate | using foreground text dc!
    4 Summary view onUpdate | colors set!
    4 Summary view onUpdate | dc clear!
    4 Summary view onUpdate | rendered label!
    4 Summary view onUpdate | rendered elapsed!
    4 Summary view onUpdate | rendered remaining!
    4 Summary view onUpdate | Hiding!
    4 Summary view onUpdate | deleting start date!
    

    The number proceeding each log entry is an update counter, which is incremented on every update.

    Update: I botched the counter increment, I set it after the first log inside onUpdate, so the first logged entry in the onUpdate call belongs to the same call (although its one number behind).

    It seems the animation never starts in the device (init/called in onShow).

    Any suggestion on what to try next?

  • Update: I've disable the "high memory" through exclusion annotations on the Venu and made a test built. This build bypasses all layering (including animation logic) to save memory. Like this the summary page works as expected (same as simulator).
    Following this result, I expect there are some shenanigans going on with the layering when running on a real device. Since I cannot reproduce it in the simulator, I'll have to drop this feature for now as there are other updates I want to push.

    There are not many examples of the use of animationLayers outside of watch faces, do you have have any resources I can refer to, specially something that is known to work in Venu?

    I would really like to get it working, as it adds much richness to the summary View in devices that support animationLayer and have enough memory. Its displayed only when the objective is met, so it feels more like an achievement.

    PS: I moved all View pushing out of the onUpdate() into the onShow() - that was pretty dumb of me to put it there in the first place (doesn't make sense).

    Thanks for the guidance and support, its much appreciated.

  • Ideally, you'd be doing view management in the delegate (or code called from the delegate). I'm not saying you can't do view management from the view, just that you shouldn't.

    If you really want to do it, you need to use a flag to indicate that you've pushed the new view and not to do it again. It sounds like you may be doing something like this, but are not clearing the flag early enough. Something like this might work:

    class MainView extends WatchUi.View
    {
        hidden var mSummaryData;
        
        function initialize() {
            View.initialize();
            mSummaryData = null;
        }
        
        function onUpdate(dc) {
            if (mSummaryData != null) {
                WatchUi.pushView(new SummaryView(mSummaryData), new SummaryDelegate(), WatchUi.SLIDE_LEFT);
                mSummaryData = null;
            }
            
            // regular stuff
        }
        
        function setSummaryData(summaryData) {
            mSummaryData = summaryData;
        }
    }

    If you are trying to avoid using normal view management, this sort of implies that you have a lot of memory wrapped up in your views. From the looks of it, the only view that really takes any memory is the one with the animation. If you are loading the animation in onShow and unloading it in onHide then there isn't much you can do to save there. If you have a menu on top of the view stack, you should be able to use switchToView() to pop the menu and push a new view in one operation. Older devices didn't have support for this, so you'd have to do a pop and a push if you didn't want to keep the menu in memory while displaying the resulting view.

    Another option is to just have one main view that has different states. You can encapsulate these states if you want, or you could throw all of the code into the main view.

  • This is how I have it running currently, put pushing the view from onShow() which is called only once to setup the data needed in the view (before bringing it into view), which sounded like a good place for it (deciding to "navigate" to a different view based on existing data). Before, I had it in the delegates, but as I mentioned in my first post, I was having navigation problems relating to the popping and pushing of views, making navigation "clunky". But its likely I was just handling it wrong, as I'm still learning Monkey C and its best practices.

    My current issue is really getting the animation to play in the device, is there any good documentation/post that can help me understand the differences between the simulator and the device and thus point me to the cause?

    As you can see in the log I posted, the onAnimationEvent is not called in the device. Although  I call "play":

    // Animate background layer
    function play() {
        backgroundAnimationLayer.setVisible(true);
        backgroundAnimationLayer.play({:delegate=>new AnimationDelegate(self)});
        System.println(Lang.format("$1$ Summary view play | animation play started!",[debugUpdateCounter]));
        playCount++;
    }

    The update is taking care of:

        drawLayerDc = foregroundTextLayer.getDc();
    	System.println(Lang.format("$1$ Summary view onUpdate | using foreground text dc!",[debugUpdateCounter]));
    
        drawLayerDc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_TRANSPARENT);
        System.println(Lang.format("$1$ Summary view onUpdate | colors set!",[debugUpdateCounter]));
    
        drawLayerDc.clear();
        System.println(Lang.format("$1$ Summary view onUpdate | dc clear!",[debugUpdateCounter]));
            
        // Start rendering
        summary_label.draw(drawLayerDc);
        System.println(Lang.format("$1$ Summary view onUpdate | rendered label!",[debugUpdateCounter]));
    
        elapsed_value.draw(drawLayerDc);
        System.println(Lang.format("$1$ Summary view onUpdate | rendered elapsed!",[debugUpdateCounter]));
        if (remaining_value != null) { // render remaining time only if a mode with time goal is set
            remaining_value.draw(drawLayerDc);
            System.println(Lang.format("$1$ Summary view onUpdate | rendered remaining!",[debugUpdateCounter]));
        }
    

    Is this the right way to go regarding writing the text?
    In the device the text just blinks on a black BG, being barely visible before the screen going fully black. No animation is perceived to be playing in the BG either.

    I posted the expected behavior in a movie (simulator):
    https://drive.google.com/file/d/1kogm-kSrRp1mWq514B7yOiOx2LnSB5Tk/view?usp=sharing

    I based my implementation on the watchface animation sample from the sdk, but also had a look here:
    https://forums.garmin.com/developer/connect-iq/b/news-announcements/posts/bring-your-app-to-life-with-animation

    Since the examples I find are all for watchfaces, I don't know if there are any caveats on using them in a widget, maybe the structure needs to be a bit different.

    Once again, thanks for taking the time to help me out!

  • Hi Travis, I moved on, but created a branch for the animation logic which I would like to go back to when a fix for the issue exists.

    Where can the status of these Bug Reports be consulted?

    I think the problem I'm having is "issue of clearing the screen to black", although I can't be sure and would like to read the detailed description.

  • You can post here if you have questions on the status of the issues.

    As for your issue with the black box being displayed where the animation should be, we had a tester run into this issue recently. It turned out that the animation encoding bug where it was written out using 8bpp color, but it needs to be 16bpp. I believe this fix should be coming with the next release.

  • Ok, thanks for the update. I'm not very proficient with the Monkey Motion tool, but this "appears" like it can be manually set, 

    Or the bug is internal and this setting for "color depth" is disregarded?

    If not, will setting the color override here break compatibility with other "manifest" devices (I can only test in the simulator and Venu at the moment)?

  • For posterity, I never managed to run the animation on a real Venu and ended up dropping it. Maybe I try again in CIQ 4 (could be fixed meanwhile), fingers-crossed.
    If anyone has a working example of a BG animation on a widget (that runs on a real device), I would be very interested.