Watchface - selective refresh & notifications

Hi all, first post, be gentle :) .
I've developed a watch face that looks like the old Amiga 500 clock app for Workbench 1.3. Yes, I'm getting old!

The watch face is dynamically generated by drawing 2 circles, then rotating and drawing 12 polygons for the hour marks, rotating and drawing 48 lines for the minute marks, and finally drawing the hands.

I've tried to reduce the amount of calc and drawing in OnUpdate, by simply clearing the centre of the watch face and drawing hands, meaning I don't redraw all the ornamentation. OnLayout still draws everything.

Problem: when I get a notification appearing (eg phone disconnected, meeting notification) then the watchface does not draw over the bits that need refreshing. When I switch to another screen and back, it works fine as onLayout gets called.

I had a brainflash to test a pixel colour at the top of the screen to see if it was not the colour I set it to, but there's no way of testing pixel colour...

Any recommendations here, as I don't really want to push drawing all the clockface back into OnUpdate()...
  • And as an example...


    I've added a boolean to show full paint required which I check in onUpdate, then selectively paint the centre or the whole screen. I'm setting the boolean in OnShow and OnHide, but that doesn't seem to help.

    Is there any way of knowing that something else has painted on the screen and that the dc region has been invalidated?
  • I don´t know if I understand your question.

    Maybe that will help you.

    Create an function one level above the update function.
    After you only have to draw the hand, marks,...

    Here is an code example from the Analog Watch sample from the SDK

    function drawHand(dc, angle, length, width)
    {
    // Map out the coordinates of the watch hand
    var coords = [ [-(width/2),0], [-(width/2), -length], [width/2, -length], [width/2, 0] ];

    var result = new [4];
    var centerX = dc.getWidth() / 2;
    var centerY = dc.getHeight() / 2;
    var cos = Math.cos(angle);
    var sin = Math.sin(angle);

    // Transform the coordinates
    for (var i = 0; i < 4; i += 1)
    {
    var x = (coords[0] * cos) - (coords[1] * sin);
    var y = (coords[0] * sin) + (coords[1] * cos);
    result= [ centerX+x, centerY+y];
    }

    // Draw the polygon
    dc.fillPolygon(result);
    }

    //! Handle the update event
    function onUpdate(dc)
    {
    // Draw the hour. Convert it to minutes and
    // compute the angle.
    var n;
    hour = ( ( ( clockTime.hour % 12 ) * 60 ) + clockTime.min);
    hour = hour / (12 * 60.0);
    hour = hour * Math.PI * 2;
    dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_TRANSPARENT);

    drawHand(dc, hour, 90, 8);
    }
    [/CODE]
  • Former Member
    Former Member over 9 years ago
    And as an example...


    I've added a boolean to show full paint required which I check in onUpdate, then selectively paint the centre or the whole screen. I'm setting the boolean in OnShow and OnHide, but that doesn't seem to help.

    Is there any way of knowing that something else has painted on the screen and that the dc region has been invalidated?


    Instead of onShow and onHide, have you tried onEnterSleep and onExitSleep?
  • Thanks for the replies

    The basic questions is whether there's a way to know when any of the DC has been invalidated by a notification pop-up.

    My watchface was originally drawing the whole screen, starting with a clear, in onUpdate. This seems inelegant as the most battery and computationally expensive bit is rendering the static stuff on the display - the hour marks, the tick marks, all of which are drawn with polygons or lines, and all of which require calls to cosine and sine functions...

    So I changed the code to just clear the centre of the clock face - leaving the decoration alone, and bars in OnUpdate. OnLayout still calls for a full paint. The problem is that when a notification appears, I don't get a call to onLayout. If I switch screens to another widget, etc, then when focus returns to the watch I get an OnLayout, which calls for a full screen clear and paint.

    It seems if focus returns from a notification, I don't get a OnShow... Is that correct behaviour?

    I thought onEnterSleep and onExitSleep were called when switching between low power and high power? I'll try that to see if it makes a difference and will report back.
  • Thanks, yes I've just tried to add to onEnterSleep and onExitSleep - it means that the user can force a full repaint by bringing the watch up, entering full power mode, but notifications do not seem to give any change of focus... or trigger any type of event other than another "onUpdate".
  • Former Member
    Former Member over 9 years ago
    It seems if focus returns from a notification, I don't get a OnShow... Is that correct behaviour?


    I believe you should receive an onShow() call when the view is brought back into the foreground. Based on your description it sounds like what you're doing conceptually is correct. There may be an integration bug with the vivoactive where the onShow() call isn't being made after a notification is displayed by the system. If you send your project to [email][email protected][/email] I will file a bug report and we'll look into it further.

    I thought onEnterSleep and onExitSleep were called when switching between low power and high power?


    You're correct here. These are not the triggers that you'd want to use in this case.

    Edit: Please include a link to this thread in your email so we know where the issue originated.
  • Thanks Ken, will do. I'm using SDK 1.2.6, and firmware is v 3.40 for completeness.

    Should I have to call requestUpdate from OnShow? The point is kind of moot anyhow as I'm setting a global to indicate a full repaint is needed, and then checking in onUpdate to determine whether to do a full paint or the hands only, and only the full paint routine clears the global...
  • Former Member
    Former Member over 9 years ago
    Should I have to call requestUpdate from OnShow?


    I can't recall off the top of my head how this works with a watchface. I would think that if onShow() is called then onUpdate() would also get called. However, with watchfaces onUpdate() is periodically called by the system (each minute) where other app types it's only called when the view is first drawn. Because of this it might be that onUpdate() is not automatically getting called after onShow(). It's also possible that in should be getting called and isn't which would be an integration bug.

    It couldn't hurt to to add a Ui.requestUpdate() call to onShow() and see if that solves your problem. This is probably the first thing we'd try in triage.
  • Yep, tried that, and it didn't refresh... Plus when it did refresh, only a partial refresh was done as the global - which gets set in OnShow() - wasn't flagged for the next run through OnRefresh().

    I couldn't see an option on the simulator to have a notification show on the simulation screen - I'm not missing something there, am I?
  • Former Member
    Former Member over 9 years ago
    I couldn't see an option on the simulator to have a notification show on the simulation screen - I'm not missing something there, am I?


    You are not.