Acknowledged

Add onTimerLapUndo() event to signify that the previous onTimerLap() event was undone

Background:

- newer watches give the user the ability to undo a manual lap by pressing the Down button while the lap banner is displayed (for 8 seconds)

Issue:

- any CIQ data field that tracks lap data will be negatively affected if and when a user undoes a lap, because apps aren't notified of this event

- this will cause CIQ data fields to calculate, display and write incorrect lap data following an undone lap

Request for CIQ changes:

- add onTimerLapUndo() event to the CIQ API, signifying that the previous lap event was undone

- add onTimerLapFinalized() event (for convenience) to the CIQ API, signifying that it's no longer possible to undo the previous lap event

- document what devs needs to do to handle lap undo properly (see next section)

What I think devs of CIQ data field apps would need to do (please correct me if I'm missing something):

- constantly maintain *two* sets of lap data at the same time: S_current_lap (the current lap data as if the current lap will not be undone), and S_previous_lap (the previous lap data, as if the current lap will be undone)

- when calculating and displaying lap data, or calling FitContributor.Field.setData() on a field of MESG_TYPE_LAP, continue to use values based on the apps *current conception* of the correct lap values. i.e. as long as the current lap is not undone, use S_current_lap. If and when the current lap is undone, copy/assign S_previous_lap to S_current_lap

(note that CIQ data fields need to be constantly calling setData() for fields of MESG_TYPE_LAP, as in the MoxyField SDK sample, since it's too late to call setData() in onTimerLap()).

- if onTimerLapFinalized() is implemented, this frees the dev from the burden of constantly maintaining two sets of lap data (they would only have to do so for up to the first 8 seconds of every lap). This would save battery life / CPU cycles, and possibly allow additional functionality due to having additional memory to spare (depends on whether that functionality can be restricted while a lap can be undone)

For example, assuming that the first activity lap is Lap 1, when onTimerLap() is triggered for the first time, the app now has to track/calculate data for both Lap 2 (the new lap) and Lap 1 (as if Lap 2 never existed). As long as Lap 2 is not undone, the data for Lap 2 should be displayed where applicable, and passed to FitContributor.Field.setData() for applicable MESG_TYPE_LAP fields. During this time, data for Lap 1 should still be tracked/calculated. If and when Lap 2 is undone, the app should start using the data for Lap 1 again (as if Lap 2 never existed).

Related discussion:

https://forums.garmin.com/developer/connect-iq/f/discussion/403749/what-event-is-triggered-when-a-lap-is-discarded/1899120#1899120

  • I wrote:

    Basically Situation 1) (delaying onTimerLap) breaks both use cases (lap is not undone, which is by far the most common use case, and lap is undone), and it forces to the dev to do a lot of work to fix the common use case.

    Correction: delaying onTimerLap only breaks the use case where the lap is not undone. It does fix the case where the lap is undone (since in this case, onTimerLap will never be called), but as I argued previously, I don’t think this is worth the cost of breaking the most common use case (lap is not undone), and breaking all existing CIQ data fields in the store which handle lap data (some of which will never be updated).

  • Also, if these changes ever make it to the CIQ API, in addition to documenting what devs need to do to properly support lap undo, it would be nice if the MoxyField sample were updated with a working example of supporting lap undo.

  • An alternative solution would be to have the api return what the current lap number is (in that case firing ontimerlap on undo would be sufficient)

    That’s an interesting solution, but personally I would prefer an explicit onTimerLapUndo() event.

    It would also be nice for the API to make the current lap number available, regardless. (Although ofc this information would be redundant given an undo event).

    Either way, it wouldn’t change the work a dev would have to do to support lap undo properly (keep two concurrent sets of lap data).

  • An alternative solution would be to have the api return what the current lap number is (in that case firing ontimerlap on undo would be sufficient)

  • Furthermore, consider how often users actually undo manual laps, compared to the total number of manual laps that are triggered.

    I think it's safe to say that users will choose not to undo a lap the vast majority of time, meaning that not undoing a lap is the rule, and undoing a lap is the exception to the rule.

    Yes, if onTimerLap() was delayed, that would fix the (rare) case when a user undoes a lap. But it would come at the cost of either breaking all existing lap data in CIQ data fields, or necessitating a very awkward and convoluted API change to allow the dev to fix laps which are not undone (which is the most common case imo).

    If onTimerLap() is not delayed (as is the case now), then the very common case where laps are not undone still works fine, and it's the only the rare case where a lap is undone which is broken.

    Either proposal (delaying onTimerLap or not delaying onTimerLap) would require code changes to handle both cases properly (lap undone / lap not undone).

    But only the proposal of delaying onTimerLap() would break the most common case where laps are not undone, meaning literally every CIQ DF in the store would need to be updated.

    With the alternate proposal (not delaying onTimerLap()) the situation with existing data fields would be exactly the same as it is today: without code changes, they would not be able to handle undoing a lap. This proposal would simply allow devs to handle undoing lap if they chose to do so, without breaking the most common case (user does not undo a lap).