Simulator Won't Allow Watchface to Set Up Timer

As of SDK 1.1.2, the simulator will abort with a "Permission Required" error with the following code. Similar code still seems fine running on hardware.

class SandboxView extends Ui.WatchFace {
var myTimer;

function onLayout(dc) {
myTimer = new Timer.Timer();
myTimer.start(method(:myUpdate), 500, true);
}

function onUpdate() {
}

function myUpdate() {
Sys.println("Hello");
}

}
  • I'm not able to test my theory, but I'm guessing that the problem is that you are trying to start a timer while the simulator is in low power mode.

    You should start timers in onExitSleep and stop them in onEnterSleep.
  • Former Member
    Former Member over 10 years ago
    I just updated the SDK to 1.1.2 and now I also get the Permission Required error. I made no other changes to a formerly working watch face.

    It looks like the watch simulator now starts in low power mode, which generates a permission error when a timer is started in onShow. The Physical Watch does not work this way as it starts up a watch face in High power mode.

    This is a major blunder in the New simulator and needs to be addressed immediately. It makes my startup splash screen not work in the simulator. The splash screen was a necessary fix to a slow widget scroll through due to a complex watch face. It also enables me to create my Moon face animation intro, which I can no longer test in the simulator.

    Thanks
  • Can you just start the timer in "onExitSleep()" and stop it on "onEnterSleep()" (if needed). That way it starts in the simulator when you leave low power mode.

    What you see in the simulator may start showing up on real devices when the CIQ 1.1.2 VM starts getting built into device firmware, and it seems there are new timer restrictions for watchfaces (the permissions thing..)
  • Former Member
    Former Member over 10 years ago
    In fact, after some testing, it seems the simulator calls onEnterSleep() before calling onShow()
  • Former Member
    Former Member over 10 years ago
    Can you just start the timer in "onExitSleep()" and stop it on "onEnterSleep()" (if needed). That way it starts in the simulator when you leave low power mode.


    Yes,

    By creating some extra flags to let the watch face know when it is the first time though onEnterSleep so the splash screen only plays once.

    Basically making the code more robust to handle these calls (onEnterSleep / onExitSleep / onShow / onHide) coming in any order at the same time as making sure no timers are started in low power mode fixes the issue.
  • Thanks for your replies. Is it unreasonable for a programmer to rely on onLayout being called while not in low power mode? While it seems possible to code around this so as not to rely on such an assumption, it seems like the API would be better if a programmer could rely on this.
  • I think the thing you should be relying on is that the device is starting low-power mode when onEnterSleep() is called, and is stopping low-power mode when onExitSleep() is called. That is what the functions are there for. If you want to rely on the other Ui.View methods (onLayout(), onShow(), onHide()) being called at specific times, then your code is depending on an assumption and is likely to break.

    If you have a test case that demonstrates why you can't use onEnterSleep() and onExitSleep() to safely manage your timers, then I think it is reasonable to ask for the Garmin development staff to commit to a call order.

    Travis
  • What is the proper way to start a timer at init time? If the watch face starts in high power mode, then there should be no power mode state transition (and therefore no call to onExitSleep) until the watch face enters low power mode when it would finally call onEnterSleep(), seconds later. If the watch face starts in low power mode (it doesn't on actual hardware), then I'm not sure how it would be possible to start a timer at init.
  • What is the proper way to start a timer at init time?


    There is no proper way to start a timer at initialization time. You can only safely start a timer after onExitSleep() has been called and before onEnterSleep() has been called. You will have to make an assumption about the power state of the device when your watch face becomes active; it is safest to assume that the device is in low power mode. This may mean that your watch face doesn't update for the first few seconds after you return to the watch face. I can't say for certain because I'm not playing with watch faces.

    Is there something wrong with just doing this the simple and safe way?

    class MyWatchFace extends Ui.WatchFace
    {
    hidden var _timer;

    function onShow() {
    _timer = new Timer.Timer();
    }

    function onHide() {
    _timer = null;
    }

    hidden var _lowpower = true;

    function onEnterSleep() {
    _timer.stop();

    _lowpower = true;
    }

    function onExitSleep() {
    _lowpower = false;

    _timer.start(self.method(:onTimer), 100, true);
    }

    function onTimer() {
    Ui.requestUpdate();
    }

    function onUpdate(dc) {
    // draw whatever, use _lowpower to determine what to draw
    }
    }
  • Former Member
    Former Member over 10 years ago
    The API guarantees only that the watch is not in sleep mode from the point when onExitSleep is called until the point when onEnterSleep is called.

    I don't have any way of knowing if the current behavior (out of sleep when started) will change on any existing or future devices, but there is not an explicit design that requires it to be that way. I know at least one device team is in the process of auditing the power consumption of ConnectIQ faces, which could impact this behavior.