After using Google Fast Pair the buds will have their bluetooth name suffixed
with some identification text, thus the exact match won't work anymore and they
get detected as generic headphones instead.
- 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
When the In-Ear detection state changes on the device (via a 2nd
connected phone) handle the change indicated by the buds and update the
value accordingly.
When the buds change their audio / ANC mode (via buds touch, or a 2nd
connected phone) they send the current state using a different command.
Handle that so the state is updated properly.
Newer buds send 6 bytes for ANC status instead of 3. Since the relevant
information is in the first 3 bytes and identical allow extra trailing
bytes when parsing.
Confirmed on the Buds 2 Plus. Likely also applies to Ear(a) (see #3994),
possibly other models as well.
Some Buds support additional ANC modes "medium" and "adaptive".
Add them to the available modes.
- Buds 2 Plus
- Ear(a) (see #3994)
Likely also applies to other models.
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