Button Press Detect on an EDGE Data Field

There isn't a way to detect the press of one of the buttons on a non-touch screen EDGE device, right? Other than the LAP and START buttons using onTimerLap and onTimerSTOP or START? At least in a data field?

Someone mentioned a CIQ Application is able to sense the other buttons to trigger application actions. But I'm not aware of a technique within a data field to do this.

"Note that on wearable products, input events are not supported for data fields." I think this applies to non-wearable products as well?

  • There isn't a way to do it  Imagine if the data screen was showing more than one data field.  Which one would see the button input?

  • "Note that on wearable products, input events are not supported for data fields." I think this applies to non-wearable products as well?

    As previously discussed, this is a (now-outdated) reference to the fact that onTap() is supported for Edge devices but it was not supported for wearables (watches).

    It’s outdated bc recent watches now support onTap() as well, although this is neither documented nor reflected in the sim

    There isn't a way to detect the press of one of the buttons on a non-touch screen EDGE device, right? Other than the LAP and START buttons using onTimerLap and onTimerSTOP or START? At least in a data field?

    Correct. Data fields can’t directly accept input in the same way that device apps can.

    Every button already has a function within an activity, so there’s no way for a data field to “take over” a button so that it handles that button to the exclusion of its existing action. 

    For example, for five button watches:

    - LIGHT already turns on the light (even device apps can’t handle this button)

    - UP scrolls up

    - DOWN scrolls down

    - START starts or stops the timer

    - LAP/BACK takes a lap

    Clearly Garmin cannot allow a data field to override any of these buttons, as it would cause user confusion and damage the normal user experience of activities. Imagine if you scroll to a 3rd party data field and all of a sudden, pressing UP or DOWN suddenly starts doing things in the data field’s UI instead (like moving a cursor between various “buttons”). How does the user get out of this state (if they even can?) If Garmin wanted to allow this kind of thing for CIQ data fields, they would’ve had to make it like the map page or the music controls page, where you have to explicitly enter a new mode in order to interact with the page (like pan/zoom mode in the map). 

    I mentioned this before, but I have a full-screen data field for watches which supports several display modes (main screen with 6 data fields, and multi-page list of laps). I implemented a hack which detects whether onShow() is called twice within a certain period of time, and flips to the next page when this happens. It’s not great because:

    - the user has to use a very unnatural “gesture” to trigger the hack, such as pressing UP, DOWN, UP (or DOWN, UP, DOWN0 quickly

    - it has to be tuned for very old watches which don’t respond to button presses / swipes very quickly

    - the exact pattern of calling onShow() is different for various watches. (On older watches, the “gesture” is triggered on the way back to the data field — i.e. when the data field is shown for the 2nd time, but on newer watches, the “gesture” is triggered on the way out, when the data field is hidden. This actually doesn’t matter for my purposes, but it might matter for others).

    - it isn’t possible (anymore) to test this in the sim — the trigger onShow / onHide function is now greyed out in the sim for data fields, whereas in the past, it was available for data fields

    I don’t know what you need input for, but if it is for some kind of (display?) mode switching, you might consider using on-device settings for this purpose. Ofc it won’t be the greatest user experience, since it takes many button presses to reach the on-device settings UI for a data fields. And you can’t really implement a fully-fledged secondary UI in on-device settings: last time I checked, a view in this context only updates due to user input (you can’t update it via a timer).

  • Thanks! You also gave me an idea when you mentioned onShow(). I'm thinking that could be the way to do this. I did implement onTimerLap() but then Garmin pops up a big Lap Stats overlay for 10 seconds that obscures the special screen I want to show for 10-15 seconds before going back to the main content. So that isn't a good approach. Also some users like to use laps, and would not also want to activate this feature every time.

    But with onShow() what the user could do is simple flip to another view and then immediately back to this field. If that happens within 2 seconds (or some watchdog time), I interpret that like an onTap(). I'd also have to NOT perform this upon an onShow() if the field was not recently showing... so I need keep a variable set to a timer() in onUpdate(). If that timer isn't recent, then I know NOT to perform the special action in onShow().

  • Like I said it's not user-friendly, and the exact sequence of calls to the relevant functions (onUpdate() and onShow()) differs from device to device.

    The way I actually implement it in one of my data fields is:

    - I store the uptime (System.getTimer()) in ms of the last onUpdate(). (This ensures that the data field was actually recently shown)

    - On every onShow(), I check to see if the last onUpdate() was within 2000 ms of the current uptime. If so, I trigger the gesture

    Couple of problems with this:

    - it can be inadvertently triggered by something like a lap alert (so I have additional code to ignore the gesture within 8 seconds of onTimerLap(), since it takes 8 seconds for a lap alert to time out by itself)

    - it can be triggered by flipping back and forth between the "pause" menu and the data pages (i.e.g by pressing the BACK button on the watch while the activity timer is stopped). This could also be seen as a feature, I guess

    - the exact sequence of calls to onShow() differs from device to device. On my FR935, when the user scrolls away from a data field and back, onShow() isn't called until the data field is shown again (when the user flips back). On my FR955, onShow() is called immediately when the user *scrolls away* from the data field [if I look closely, I can see my data field responding to the "gesture"]. I think this is probably due to the smooth scrolling that's implemented in newer watches (to facilitate a smooth touch UI).

    In my case it doesn't matter, because the view will be toggled either way by the time the user returns to the original data page, and if the user waits too long to return to the original data page, I timeout and return the view to the original state. But if the user returns to the data page quickly enough, the new view is "permanent" [until they perform another gesture or scroll away from the data page long enough for it to time out].

    I don't think it's a great solution. The gesture is an optional feature in my full-screen running data field, and idk how many ppl actually use it except for me. It's ok for my personal use, since I am willing to put up with something that's user-unfriendly in exchange for functionality that can't be accomplished another way (well, now I can use onTap(), but I couldn't before, and I usually have touch disabled for run activities anyway.)

  • Good tips. This is EDGE devices only. I actually just implemented this to test it out and did just like you did with a 3000ms check in onShow(). I didn't know that a lap event has an effect on this sequence! Thanks for catching that scenario and the list of problems I need to handle! In my case this is only for cyclists using an EDGE, so I'll have to see how this works out to quickly flip the screen back/forth on the road.

  • Imo, what would be a lot nicer is if:

    - Garmin had "native" support for full-screen data fields (as a special app type)

    - full-screen data fields were allowed to push their own "full UI view", like the map page or the music controls page

    That way you could have full-screen data fields with an "alternate" mode that has a fully-functional UI.

    I doubt Garmin would ever implement this, though.

  • I didn't know that a lap event has an effect on this sequence!

    It's because of the lap alert. I don't know if the lap alert is full screen on Edge, but it is on watches, so data fields will be hidden when the lap alert is shown. onShow() will be called after the lap alert, when the data field is displayed again.

    The sequence is something like:

    - t = a: onUpdate() (once per second)

    - t = a+1000: onUpdate() (once per second)

    - t= a+1050: lap is triggered. onHide() is called. onTimerLap() is called. Full screen lap alert is shown for up to 8 seconds, no onUpdate() is called during this time

    - t > a+1050 and t <= a+9050: lap alert times out or user dismisses it with back button. onShow() is called.

    So if the user dismisses the lap alert too soon, or if the threshold for the "gesture" is too long, the first onShow() after the lap alert could be misinterpreted as the gesture.

  • The funny thing is Garmin has something very close to a secondary UI for data fields, but it's in the form of on-device settings, and Garmin must really not want devs to use it for anything else, bc as I mentioned, the on-device settings view will not update based on a timer, only in response to user input.

    If you just want to semi-permanently toggle a view, on-device settings would still work, although it would be very clunky.

  • My initial code... still need to handle some of the situations you mentioned. I set a feature timer that decrements to zero, with an option to turn off the feature early by repeating the trigger. I'll probably disable the onTimerLap() method if the onShow() works well. Thanks again!