Infer capabilities from the incoming FitData message (as test/workaround, we're not sure if the field we're using is the correct one).
Use the CapabilitiesDeviceEvent instead of the hardcoded ConfigurationMessage instanceof check to call completeInitialization() in GarminSupport.
Also centralize the generation of the capabilities-related DeviceEvent in GarminCapability as they are used both in ConfigurationMessage as in FitLocalMessageHandler now.
This commit does not override the default fetching of activity data, which is still phone-initiated, but adds support for watch-initiated sync as well (typically upon connecting).
Also change the order of the messages exchanged upon connection to mimic logs of official app.
Also remove some status messages where the outgoing message is already a status.
Also send the status "app in foreground" so that the watch can initiate the synchronization.
Refactor Ear1Support to extend AbstractHeadphoneBTBRDeviceSupport instead of AbstractHeadphoneSerialDeviceSupport.
Encapsulate NothingProtocol as inner class to Ear1Support and remove NothingIOThread.
Rename one preference to allow the usage of Enum for audio mode. Beside of this change most of NothingProtocol remained unchanged.
Also remove (unused) import in PixooIOThread.
Add the code to generate outgoing FitDefinition- and FitDataStatusMessage.
Add support for incoming FitDefinitionMessage and register handler via deviceEvent (commented for now to avoid leaking).
Refactor FitLocalMessageHandler to support both outgoing and incoming handling of FitDefinition/FitData.
Most of the changes were not tested for the lack of hardware, but at least they show no regressions.
Refactor FitDataMessage to support a two-step message parsing: at first hold a copy of the incoming bytestream and later parse it according to a list of RecordDefinitions.
This allows to remove PredefinedLocalMessage which was already made obsolete by previous changes.
This should also allow to support incoming FitDefinition/FitData exchanges.
Use a temporary MessageHandler to send Definitions and Data in sequence instead of in parallel.
Add functionality to populate FitLocalMessageBuilder record by record instead of with a List, also add helper to get an unused localMessageType.
Don't use hardcoded localMessageTypes for weather message as they are not required.
Add equals() and hashCode() to all classes needed to properly compare RecordDefinition class instances.
Add FitLocalMessageBuilder class to deduplicate the Definitions also recreating the RecordData in case they differ just from previous ones with the same localMessageType (e.g. if they were built specifying the fields in a different order).
Restore a different order in GarminSupport when building weather messages, to test the deduplication.
Add FieldDefinitionWeatherReport as proper enum with explicit Types. Also adapt the code generator and run it (without adding all unrelated changes to generated Messages, only FitWeather).
Also migrate from FragmentStatePagerAdapter to FragmentStateAdapter, preserving the getPageTitle method for compatibility.
Layouts needs adjustments since the TabLayout cannot be a child of ViewPager2.
Further no subclassing is possible hence NonSwipeableViewPager has to be deleted, but the functionality is retained.
Custom classes to handle FragmentAdapters are also removed, and lifecycle of activities (using fragments) has been streamlined.
Add a new NotificationType for received text.
Add device specific settings to the printer coordinator, also add setting to print received text (defaults to on).
Cache Handling and static mapping methods are extracted to new classes
Also adds test for weather mapping and moves legacy Weather class there to ensure the conversion to kotlin did not introduce errors
Don't start the foreground NotificationCollectorMonitorService unless enabled in the deprecated settings.
The notification service seems to be reliably kept alive by the OS without this workaround, and having a second foreground service is causing a second persistent notification for some users.
Show the picture on a canvas and allow to swipe it to align left, middle or right.
Also simplify the activity layout by removing the incoming picture and only showing the preview.
Use a cache file in the cache directory to hold the bitmap, this way we can avoid passing huge byte arrays around for printing.
Also:
allow to open files from the SendToPrinterActivity if it's launched from the device card
fix the encoding of rows when RLE is not in use
show the previews in full width in the activity
The reverted change sent the updated descriptor value to the watch, breaking the connection.
It is unclear why the descriptor is set to an unknown value and never sent to the watch, but this restores the previous working behavior.
Add OS Battery Level detection to BluetoothStateChangeReceiver, pass the event to devices only if their coordinator class declares support for it.
Add supportsOSBatteryLevel() to DeviceCoordinator and AbstractDeviceCoordinator defaulting to false.
Change coordinator of GenericHeadphones to return true for supportsOSBatteryLevel() and remove specific BroadcastReceiver from the support class.
Add a listener to get the current battery level of the audio device.
Also prevent the spurious notification about missing firmware and hardware version.
Also adds a local cache for pictures which is handled by the NotificationListener itself.
If the picture is hosted in a third party content provider it gets queried.
If the Bitmap is embedded in the notification, the local cache is used.
In any case the NotificationSpec just holds a String to the absolute file path
The NPE was triggered by recent changes in the HearthRate Charts (503cd31d91)
Since getModel was also affected by the same NPE, the function is now changed as well.
In order to add an emulated device it is sufficient to use the "Add test device" functionality choosing pebble as device and entering IP:PORT in the mac address field.
The pebble setting to force BLE is moved to discovery_pairing_preferences.xml
Also delete the pebble_preferences file and update general preferences.
Numeric BaseTypes now return fractional part if a scale is set, the return type for numeric values is unboxed from Number class so that existing comparisons and checks keep working, but values are not truncated at nearest integer value.
The codegen class has been updated and some of the messages are re-generated with the new code, with the exception of Hrv* messages, since updating those needs updating the related sample types.
Test cases expected values have been adjusted to keep into account the fractional part of some fields.
Garmin: Fix HRV value and summary types
The previous attempt to send all zeroes (in 7fa5cd1be5) didn't yield actionable progress, hence we try sending back what the watch sent to us.
Blindly implemented based on the legacy vivomoveHR code, not tested against real devices.
Add a Field definition for GPS coordinates and remove the corresponding method from GarminUtils.
Add a new message COURSE and some fields to other known messages.
Also centralize some utility methods in GpxParser and GpxTrack, adapting ZeppOsGpxRouteFile.
Be aware that the capability used to identify the supported watches might be the wrong one.
Our implementation of scale and offset was backwards: we were adding offset and then dividing by scale when decoding fields, but the publicly available protocol description dictates otherwise ( http://web.archive.org/web/20240519102659/https://developer.garmin.com/fit/protocol/#scaleoffset ): "the binary quantity is divided by the scale factor and then the offset is subtracted".
For this reason the sign of GARMIN_TIME_EPOCH in Timestamp field definition must be flipped as well.
Add status message parsing and change the reply logic for watch-initiated Auth (in attempt to fix#3986): before this changeset the phone would reply with a generic ACK and then send a request to the watch for setting the auth (with all zeroes);
after this changeset the phone replies with a specific auth ack/status message but it ignores what the watch requested and acknowledges back all zeroes.
Blindly implemented based on the legacy vivomoveHR code, not tested against real devices.
Prevents it being stale for too long if the user forgets to fetch an updated file.
If the file has to be updated on the watch the response (http status 200) is sent and cached for 14400 seconds, for this period the watch will not request the file again.
Subsequent requests (http status 304) are very small and should not impact battery life negatively, hence they are sent without adding caching directives.
remove message placeholders referring to legacy code,
remove try-catch from the weather data message building method
lower the frequency of music control messages
remove chunk from the map once it is complete if it is incoming, fix the removal of outgoing chunks
also return a warn log message if the protobuf status is not OK.
Also replaces support for device through the new garmin code path.
The Entities are preserved to enable on-demand database migration in case some user had previously synchronized data.
Add Aqi Field Definition and field to today weather and daily forecast, as both are available in WeatherSpec.
Add Feels like temperature to hourly forecast but populate with the forecasted temperature as the field is not available in Weatherspec for hourly.
Use temperature Field Definition for dew point and add it to today's weather.
Fields dew point and air quality could have been removed from the hourly weather definition but are kept in to test compatibility of these changes with watches.
Also adds temporary method to move the fetched files from the legacy path to the new one which does not include the device name.
Also moves the FileIndex to the end of the cached files to allow for easier sorting.
Cherry-picked from 525b395c01ce57449ee9a8f74af663595223279e and adapted
This seems to be widely supported by garmin devices, hence enable it in the base coordinator. Specific devices not supporting Unicode Emojis can override this method and return false.
Add a fictitious action to the notification to enable reply/hangup/reject from the watch.
Also fixes the behavior on sms reply, which should also reject the incoming call.
Change the log level in case some of the canned messages types are left as default to info, as this is a supported scenario.
It looks like (some) watches really don't like having an empty list of actions, hence enable the legacy "refuse" action in every case, leaving it empty and inactive.
Further display the SMS sender in the notification and enable the correct code path for the reply action to work.
Make use of the previously added preference to toggle file archival (deletion) on the watch.
Default is true (keep data on device) until we are sure of the consequences.
PredefinedLocalMessage are only useful for FIT messages and should not interfere with FIT files. The only impact of using the local message in fit files was in the textual output, but it was confusing.
Add an explicit constructor to RecordHeader if PredefinedLocalMessage should be taken into account, and use this only in fit messages leaving the default constructor for fit files.
Also adjusts the test case as textual output comparison needs to be fixed.
To enable custom replies an override must be defined in the devices coordinator that actually support custom replies.
The custom preferences allow to:
- enable / disable the default message suffix (Instinct 2 appends "sent from my $vendor device" to each reply by default)
- define custom messages to reply to calls and incoming messages (leaving those lists empty will enable the default messages to be used)
Also adds a new protobuf definition file of mostly unknown values that enable toggling the message suffix on Instinct 2.
This uses the (assumed) new method of passing multiple actions, instead of the (assumed) legacy accept/decline approach.
At the moment the preset messages stored on the watch firmware are used for replying, the code supports using custom messages already but those have to be updated to the watch somehow (probably by protobuf) and this is not supported yet. Using custom messages if they are not set will just do nothing.
The NotificationActionIconPosition values have been determined on a vívomove Style and might not work properly on other watches.
The evaluation of GBDeviceEvent have been moved in GarminSupport since the notification actions handling uses device events.
Also adds a method to read null terminated strings to GarminByteBufferReader.
Also adds a warning in NotificationListener if the wrong handle is used for replying to a notification.
adds synchronization of supported files from watch to external directory
adds support for Activity and Monitoring files (workouts and activity samples), but those are not integrated yet
adds upload functionality (not used ATM and not tested)
adds notification support without actions
introduces centralized processing of "messageHandlers" (protobuf, file transfer, notifications)
also properly dispose of the music timer when disconnecting