Glance mode widget: please allow popView() at top level (for parity with non-glance widget UX)

Hi,

I've recently started to adapt a stopwatch widget of mine for glance mode. Currently I don't own a glance-enabled watch, so I can only test this in the sim (CIQ SDK 3.2.3, Windows/Eclipse).


Non-Glance Widget

The non-glance structure of the widget is as follows:

Top-level Initial view (minimal UI):

Displays the stopwatch (minimal UI) and has very limited user-input (as it's the front page of a widget). The user can tap or press enter to transition to "full user interaction mode", at which point another view is pushed (let's call it "full view")

e.g.

Full view (full UI):

Displays the stopwatch (full UI) and has full user input (via onKey() handler). The user can start the timer, stop the timer, take laps, change settings, etc. When the user presses Back (or another key sequence under certain circumstances *), this view is popped and the user is back to the initial view (which can be "exited" by either scrolling to another widget or by pressing Back)

(* I actually have two ways of exiting the full widget UI other than Back: by pressing Up twice, or by using a settings menu item. The use case here is that while the stopwatch is running, Back is reserved for taking laps or resetting the stopwatch.)

e.g.

All of this works perfectly without any crashes.


Glance-Mode Widget

But in glance mode, the glance view is supposed to replace the initial view (minimal UI), and the new initial view is the full UI. So the new architecture of the widget in glance mode is:

Glance View: shows an "extremely minimal UI" (like the minimal UI, but smaller and with slightly less information)

e.g.

Top-level Widget View: shows the "full UI", with full user interaction. (User can start and stop the stopwatch, as well as take laps, access settings, etc.)

e.g.

The problem here is that I can't seem to exit the top-level widget view cleanly.

- If I call popView(), then I get a system error (probably because popView() is not allowed for the top-level view of a widget) and the widget exits

- But if I just return false from onKey(), then nothing happens. Whether I return true or false from onKey() (without calling popView), nothing happens

It seems that the only way to cleanly exit the top-level view of the widget in glance mode is to omit the onKey() handler from the delegate.

(EDIT: As Jim pointed out, the problem here is due to having both an onKey and an onBack handler, but not returning false form both).

Am I doing something wrong or missing something here? I need to have full user interaction in the "full view" (which is top-level view of the glance-mode widget), but I also want to be able to exit that top level view:

- When Back is pressed (under some circumstances - i.e. when the stopwatch is not running)

- When some other key sequence is pressed (under other circumstances - i.e. when the stopwatch is running, as the Back key is now reserved for taking laps)

It seems I could just continue to call popView(), but I don't want the widget to crash every time it exits.

If it's actually the case the top-level view of widget in glance mode cannot be popped, maybe this design decision should be revisited? At the very least, maybe the behavior of onKey() could be changed?

As it stands, it seems that it isn't possible to have the same kind of UX in both the glance and non-glance versions of a widget, where the glance view takes the place of the non-glance widget landing/summary page, and the glance-mode widget initial view takes the place of the non-glance widget "full view" (with an onKey() handler and with the ability to exit this view with ways other than the Back key.). Unless I'm missing something.

It seems that the only way to accomplish what I want to do is to keep the extra widget landing page (minimal UI) in glance mode. But the landing page is redundant when the glance mode view exists....

Thanks!

  • Just some general things

    The problem with popping the top level view is the VM doesn't know what to go back to.  That's why you get the error, and it's valid.  Without glances, it's a watch face, but doesn't know which one.  With glances, it's the widget loop.

    Are you using both onKey and onBack?

    Trying to use onBack/KEY_ESC in a widget does not prevent a widget from timing out - from about 30 seconds on a va/venu to 2 minutes on other watches.  This happens if the widget was started with glance view or not, and doesn't occur in the sim - a widget never times out in the sim.

    When doing a glance view, you don't return a delegate.  So just, 

    	function getGlanceView() {
            return [ new WUWGView() ];
        }	

    In your main view, you can tell if the widget was started from a glance or not

    Sys.getDeviceSettings.isGlanceModeEnabled;

    this impacts what you can do in the delegate for the main view.  For example, if started with a glance, you can use up/down.  Without glance mode, you can't.

    Depending on the device, when displaying a glance, Ui.requestUpdate() may be honored or not.  This you can see in the sim, and is based on "liveUpdates" as set for the device.  It's false on a f6 but true on an f6 pro for example.

  • Thanks for the response. I think I understand how the glance view itself works and that's not what I'm worried about here. I also have a plan for handling "glance view with live update" vs. "glance view without live update".

    I'm not really worried about widget timeouts here (I realize there's nothing that can be done here -- that's just a limitation that my users have to live with.)

    I also understand why popping the top-level view of a widget is not allowed, but I disagree with the rationale, especially in the case of glance mode widgets (see below).

    Are you using both onKey and onBack?

    Actually, yes. Embarassingly, that's the problem in my code. onKey() is returning false but onBack is returning true. When I return false from both, then the widget exits as expected. Thanks!

    However, I still think there's an issue here.

    If the glance view is meant to replace the initial view of a non-glance mode widget, then we should be able to pop the initial view of a glance mode widget, which should return us to glance view.

    My rationale is:

    - Non glance widget: 1st view = "widget landing page", 2nd view = "full widget page"

    ^ in this case popping the 2nd view returns us to the first view

    Now if I want a similar UX for glance mode widgets:

    - Glance widget: Glance View = "mini widget landing page", 1st view = "full widget page"

    ^ in this case, I want to be able to pop the 1st view and return to the glance view (at will)

    If I can't pop the first view of the glance widget, now I have to have an extra landing page for no reason. (Which is similar to the UX that glance-enabled users are seeing right now.)

    IOW they see:

    - Glance widget: Glance View = "mini widget landing page", 1st view = "widget landing page", 2nd view = "full widget page"

    In general, I disagree with the rationale behind not being allowed to pop or exit the initial view of a widget under any circumstances. I've read the threads and I understand the argument, but the simple fact is that the user is allowed to press Back on the initial view and *something* happens. It seems to me that whatever happens in that case should also happen when the initial view is popped.

  • I guess I have a pretty esoteric use case where I selectively block the Back button in a widget, yet I also allow the user to "exit" the (full) widget in a different way (when the Back button is blocked by the widget.). But I don't see anything wrong with it in principle. It works fine in non-glance mode without crashing anything.

    A similar stopwatch widget (which also uses Back to take laps and reset the stopwatch) simply doesn't allow the user to exit the widget without stopping and resetting the stopwatch. (Or letting the widget time out.) To me that's unacceptable, because I consider it a feature that the stopwatch widget can be exited while the stopwatch is running.

  • TL;DR in a non-glance widget we can do "special" things with the Back button (and exit the widget in other ways), but in a glance widget we really can't, unless we add a redundant landing view.

  • The problem with popping the top level view is the VM doesn't know what to go back to.  That's why you get the error, and it's valid.  Without glances, it's a watch face, but doesn't know which one.  With glances, it's the widget loop.

    For a glance-mode widget, popping the top level should take you back to the glance view, since that's how you got to the top level in the first place, right?

    Or it should just do whatever would happen if the user pressed Back. Why can't popView() just do the exact the same thing as a manual press of Back?

  • There was a thread about this a while back where Brian talked about why this was the case.  The problem is "who" handles the press of the back button - the VM or the firmware

  • Too bad there isn't support for synthetic button events at a sufficiently low level, then. Thanks for the explanation.