onSleep getting missed by WatchFace

I have a epix (gen 2) with the AMOLED display, not using the wrist gesture option, and I'm having issues getting my watch face code to properly determine the sleep status in certain situations.

I'm using a variable that is set / cleared on the onEnterSleep() and onExitSleep() functions.  Based on the forums that seems to be the usual method.  This is then used to manage the display between the standard and low power faces.

On this watch, I've noticed a scenario where the the watch face app exits the sleep mode (and calls the onExitSleep() properly) and re-enters the sleep mode without calling noEnterSleep();

It seems to happen when the watch face loses focus.  For example... watch face is in sleep mode as normal.  The watch receives a notification from a phone via BTE, which "wakes' the watch.  onExitSleep() is called, but the display moves to the notification focus.  The low power timeout is only 8 seconds, and while the notification message is still on display, the backlight reduces AS IF the watch is going to sleep mode.  After the 30 sec timeout for the notification, the display changes back to the watch face but the watch face app never received a call to the onEnterSleep() so it displays the standard face with the lower backlight.  It will stay in this indefinitely or until something else happens.

I've seen this on multiple watch face apps, including the one I'm writing myself.  Since the isSleepMode property was phased out, there doesn't seem to be a way in the APIs to verify whether the watch is in sleep mode through code.  So the app can't verify it's in the right mode.

Has anyone else seen this?  Or possibly have any ideas on what could be causing this?  I'm not extremely good at debugging directly on the watch (I'm still very new to Garmin and MonkeyC) and the CIQ simulator doesn't seem to simulate these activities that take focus on the screen.

I would be very interested in anyone else's opinion...

  • One other note... I've noticed you can simulate this in the simulator.

    If you run the simulator and check the Low Power Mode option... then rerun the simulator without closing it.  When the watch face renders for the first time, the onEnterSleep() has not run so the code doesn't know it's in sleep mode.  If you uncheck the Low Power Mode, nothing happens.  Then checking it again will properly run the OnEnterSleep().

    The watch face app is being initialized while the watch is in Low Power Mode.  Is there any way to check a property for this?  There needs to be some way for the app to check the mode when it's initialized.

  • yes, I can see strange behaviour of epix,

    but first, do you use onShow()?

  • Currently onShow is emply, and the onLayout is very basic just to get the time and put it on the screen.  I'm only switching fonts depending on whether it's in low power mode or not.

    What seems to be happening in the watch face is initiated while the watch is in low power mode.  Since there's no call to check if the watch is in low power mode or not, I can't recognize that in the watch face software.

    The idea of using onEnterSleep and onExitSleep to track the power mode only works if you know what mode you're starting in.  Without being able to check, you have to "guess: or assume you're in regular power mode.

    So there are two questions...

    1, Is there a clever way to tell if a class is initiated while in low power mode?

    2. Is there a software command or call that would force the watch out of low power mode?  If there was, this could be called on initialize or onShow to ensure the watch was in regular power mode, then using onEnterSleep and onExitSleep would work again.

  • onUpdate() is where you should get the time for display.  onLayout is used to load a layout, or possibly to define the x/y for displaying the time but it's not called regularly.  onUpdate in a WF is called either once a second or once a minute.

  • Jim - you're correct, and that is my mistake.  I double checked the code, and the time algorithm is in onUpdate.  onLayout is just setting the layout.  That was an error on my part.

    I'm still at the original issue though... class initiation while in low power mode has no ability to tell it's in low power mode.  This defeats the purpose of allowing a class to make decision based on being in low power mode.

    I need some way to either poll the system to tell if it's in low power mode, or force the system into low or high power mode so I know we're there.  I haven't been able to find any API calls or commands that would trigger changing from low to regular power mode (or vice versa).

  • In your view class have a variable like

    var inLowPower=false;

    Then onEnterSleep and onExitSleep like this:

    function onExitSleep() {
    inLowPower=false;
    WatchUi.requestUpdate();
    }

    function onEnterSleep() {
    inLowPower=true;
    WatchUi.requestUpdate();
    }

    in onUpdate(), check inLowPower to see what to do.  With an AMOLED display you may need to also check if burnin protection is needed.

    The sim works fine for me and the epix2, with one small exception.  If the sim is running and you restart your WF, the sim may say it's in low power but really isn't  Toggle the setting in the sim a couple times

  • Understand in a WF, your main view only is created one in the WF life cycle.  That happens in getInitialView in your AppBase.  Put a println in the view's initialize() (and maybe some other functions in the view) so you can see what's happening

  • Jim - I already had that functionality in my code, except for the WatchUi.requestUpdate().  But those function calls don't address the problem, the issue is the onEnterSleep is NOT being called when the watch enters sleep mode and the watch face is not active on the screen.

    You mentioned you have to toggle the Low Power setting in the simulator to get it working.  I would say it's working exactly as expected... when you restart your WF and the simulator is running, you're actually duplicating the issue that happening in the physical watch when a notification occurs and your WF is closed.  The WF then starts new and the watch itself is already in low power mode.  So onEnterSleep does NOT get called.  When you uncheck the Low Power Mode, the onExitSleep is called but the WF code already thought it wasn't sleeping.  Now when you check the Low Power Mode it does call the onEnterSleep and everything looks to be working fine.  In reality, it was always working.  But since you cannot tell Low Power Mode until the first onEnterSleep, it looks like it's not working properly at first.

  • This issue with low power in the sim has been around for a long time.  I did a bug report on it maybe 3 years back

    Here's a watch face with it unchecked and checked: (I dim the time in low power mode and reduce what I display)

    Now if I just run the same WF again without restarting the sim (low power was checked) and still is after the app starts


    but you can see the setting doesn't reflect it's not in low power. The WF is in high power mode (seconds update every second).  This is where you want to toggle it if you don't restart the sim.

    This is simulating an Epix2, and it's working as expected.  Notice how the data displayed changes between low and high power (except for the minor glitch in the low power setting)

    onEnterSleep() and onExitSleep() are working correctly for me, with the Epix2, and has so from when the epix2 was introduced. 

    Look at your code, and add println calls, to see what's happening

  • Jim - I really do appreciate the help!

    The problem I'm having can't be simulated, as I believe the simulator doesn't allow for things like message notifications.

    I just setup the watch to provide some feedback and recreated the issue.  I put print statements in to the main functions of the watch face.  Here is the log file from the watch (with a few comments):

    12:38:50 - Watch face initializing.
    12:38:50 - Laying out the watch face.
    12:39:31 - Entering sleep.

    Received a text notification
    12:44:56 - Leaving sleep.
    12:44:57 - Hiding the face.
    12:44:57 - Hiding the face.

    Received a calendar notification
    12:45:01 - Hiding the face.

    8 seconds after the notification, the backlight dims and the watch goes into low power mode

    30 seconds after the notication, the text message notication disappears and the watch face comes back

    12:45:32 - Entering sleep.
    12:45:32 - Leaving sleep.
    12:45:32 - Hiding the face

    At this time, the watch is in low power (lower backlight) but the watch face is in the regular mode.

    After a few minutes, I pressed the backlight button

    12:48:11 - Entering sleep.
    12:48:20 - Leaving sleep.
    12:48:20 - Hiding the face.

    Back to normal

    What's interesting is when the text message display leaves, the first call to the watch face is to entre sleep.  It then immediately calls the onExiitSleep even though the watch doesn't seem to wake up (the backlight does NOT increase).  There should also should be an "Entering sleep" 8 seconds later after the timeout, but that doesn't happen (probably because the watch thinks it's already in low power mode).

    The result is the "leaving sleep" when the watch face comes back and no corresponding "entering sleep' call to onEnterSleep, so the watch face code doesn't know it's in low power mode.

    I'm very interested in any thoughts or ideas...