- add initial / final / min stamina handling for session summary
- add fractional cycle and cadence handling for session summary
- add fallback handling for diving summary
- available in device specific settings for supported gadgets
- supports pasting common text formats (e.g. 27°59′18″N 86°55′31″E)
- supports geo: URIs (e.g. geo:27.988333,86.925278,8848)
Experiment to support setting typical wake / sleep times for devices without realtime settings.
Settings / Developer options / Experimental settings
-> enable
Device specific setting / Experimental settings
-> wake time
-> sleep time
-> send
For Garmin ANT devices the extended ANT device number and the filtered serial number result in the same name.
This link between ANT device number and serial number is not always true for non-Garmin devices.
FIT file for testing:
https://github.com/ThomasKuehne/FIT-test-files/blob/main/Activity/2018/Activity_20180324_005_000_Swimming_Fr935_ae9c05519ca8c802f33a8ffd90b15915.fit
``
Error saving specific samplesjava.lang.IllegalArgumentException: Infinity is not a valid double value as per JSON specification. To override this behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method.
at com.google.gson.Gson.checkValidFloatingPoint(Gson.java:508)
at com.google.gson.Gson$1.write(Gson.java:470)
at com.google.gson.Gson$1.write(Gson.java:453)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:73)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$2.write(ReflectiveTypeAdapterFactory.java:251)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:491)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:73)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:100)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:64)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:73)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$2.write(ReflectiveTypeAdapterFactory.java:251)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:491)
at com.google.gson.TypeAdapter.toJsonTree(TypeAdapter.java:181)
at com.google.gson.typeadapters.RuntimeTypeAdapterFactory$1.write(RuntimeTypeAdapterFactory.java:309)
at com.google.gson.TypeAdapter$NullSafeTypeAdapter.write(TypeAdapter.java:304)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:73)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:225)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:161)
at com.google.gson.Gson.toJson(Gson.java:943)
at com.google.gson.Gson.toJson(Gson.java:898)
at com.google.gson.Gson.toJson(Gson.java:847)
at com.google.gson.Gson.toJson(Gson.java:824)
at nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryData.toJson(ActivitySummaryData.java:189)
at nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryData.toString(ActivitySummaryData.java:185)
at nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminWorkoutParser.updateSummary(GarminWorkoutParser.java:1080)
at nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitImporter.persistWorkout(FitImporter.java:687)
``
Example pace calculation when speed is exactly 0.0 m/s.
``
Error saving specific samplesjava.lang.IllegalArgumentException: Infinity is not a valid double value as per JSON specification. To override this behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method.
at com.google.gson.Gson.checkValidFloatingPoint(Gson.java:508)
at com.google.gson.Gson$1.write(Gson.java:470)
at com.google.gson.Gson$1.write(Gson.java:453)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:73)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$2.write(ReflectiveTypeAdapterFactory.java:251)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:491)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:73)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:100)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:64)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:73)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$2.write(ReflectiveTypeAdapterFactory.java:251)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:491)
at com.google.gson.TypeAdapter.toJsonTree(TypeAdapter.java:181)
at com.google.gson.typeadapters.RuntimeTypeAdapterFactory$1.write(RuntimeTypeAdapterFactory.java:309)
at com.google.gson.TypeAdapter$NullSafeTypeAdapter.write(TypeAdapter.java:304)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:73)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:225)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:161)
at com.google.gson.Gson.toJson(Gson.java:943)
at com.google.gson.Gson.toJson(Gson.java:898)
at com.google.gson.Gson.toJson(Gson.java:847)
at com.google.gson.Gson.toJson(Gson.java:824)
at nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryData.toJson(ActivitySummaryData.java:195)
at nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryData.toString(ActivitySummaryData.java:191)
at nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminWorkoutParser.updateSummary(GarminWorkoutParser.java:1079)
``
- add fallback sources for HR_AVG, TOTAL_ASCENT, TOTAL_DESCENT, AVG_POWER, BODY_ENERGY_AT_START and BODY_ENERGY_AT_END
- fallback to lap average speed if the lap enhanced average speed isn't available
- ensure that paces/speeds are only rounded by WorkoutValueFormatter and not also by GarminWorkoutParser
- add diving lap summary for apnea
- add scuba tank summary
- fix diving summary gaps when CNS, N2 load or O2 toxicity values are 0
- prioritise names: workout name > session sports profile > sport name
- gracefully fallback from Enhanced Respiration to plain Respiration
- gracefully fallback from Enhanced Speed to plain Speed
- add gear info showing last battery reading of connected devices
- add altitude min/max/avg
- add user heart rate (min/max/resting)
- add workout feel (0 - 100%)
- add device battery state (initial / final)
- add ebike battery state (initial / final)
- add more recovery, work, energy statistics
- diving: add SAC (Surface Air Consumption)
- diving: add water density with fallback to water type
- diving: ignore disabled gases
ActivitySummaryData already checks if the value is `null`.
Unless forcing a display or performing calculations, there is no need to also check for `null` values in GarminWorkoutParser.
This extracts the following metrics and stores them in a new GenericMetricSample / GENERIC_METRIC_SAMPLE table:
- endurance score
- functional threshold power
- hill endurance
- hill score
- hill strength
- MET max VO2
- running lactate threshold power
- training readiness
Visualisation and charts aren't part of this PR.
This enhances the general GB code _without_ the device specific adjustments required to actually display values:
- chart elevation even if the activity has no GPS recording (e.g. treadmill and floor climbing)
- added distance chart
- added stride chart
- added step length chart
- added body energy chart - 24/7 energy level
- added stamina chart - activity specific endurance capacity
- added N2 load (Nitrogen) chart for diving
- added CNS toxicity (Central Nervous System) chart for diving
- added oxygen toxicity summary for diving
- added surface interval summary for diving
https://developer.android.com/guide/topics/resources/string-resource#FormattingAndStyling
Escape single quotes (') and double quote (").
Unescaped characters are removed by the Android tool chain.
A string contained completely in quotes
<string>"a b c"</string>
triggers special white space preserving handling (a b c) instead of the normal white space collapse (a b c).