package nodomain.freeyourgadget.gadgetbridge.devices.garmin; import android.content.Context; import android.net.Uri; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import de.greenrobot.dao.AbstractDao; import de.greenrobot.dao.Property; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen; import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.WorkoutVo2MaxSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.Vo2MaxSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.vivomovehr.GarminCapability; import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.entities.GarminActivitySampleDao; import nodomain.freeyourgadget.gadgetbridge.entities.GarminBodyEnergySampleDao; import nodomain.freeyourgadget.gadgetbridge.entities.GarminEventSampleDao; import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvSummarySampleDao; import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvValueSampleDao; import nodomain.freeyourgadget.gadgetbridge.entities.GarminSleepStageSampleDao; import nodomain.freeyourgadget.gadgetbridge.entities.GarminSpo2SampleDao; import nodomain.freeyourgadget.gadgetbridge.entities.GarminStressSampleDao; import nodomain.freeyourgadget.gadgetbridge.entities.PendingFileDao; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser; import nodomain.freeyourgadget.gadgetbridge.model.BodyEnergySample; import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample; import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample; import nodomain.freeyourgadget.gadgetbridge.model.PaiSample; import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample; import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample; import nodomain.freeyourgadget.gadgetbridge.model.SleepScoreSample; import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample; import nodomain.freeyourgadget.gadgetbridge.model.StressSample; import nodomain.freeyourgadget.gadgetbridge.model.Vo2MaxSample; import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.GarminSupport; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator { @Override public boolean suggestUnbindBeforePair() { return false; } @Override protected void deleteDevice(@NonNull final GBDevice gbDevice, @NonNull final Device device, @NonNull final DaoSession session) throws GBException { deleteAllActivityData(device, session); } public void deleteAllActivityData(@NonNull final Device device, @NonNull final DaoSession session) throws GBException { final Long deviceId = device.getId(); final Map, Property> daoMap = new HashMap, Property>() {{ put(session.getGarminActivitySampleDao(), GarminActivitySampleDao.Properties.DeviceId); put(session.getGarminStressSampleDao(), GarminStressSampleDao.Properties.DeviceId); put(session.getGarminBodyEnergySampleDao(), GarminBodyEnergySampleDao.Properties.DeviceId); put(session.getGarminSpo2SampleDao(), GarminSpo2SampleDao.Properties.DeviceId); put(session.getGarminSleepStageSampleDao(), GarminSleepStageSampleDao.Properties.DeviceId); put(session.getGarminEventSampleDao(), GarminEventSampleDao.Properties.DeviceId); put(session.getGarminHrvSummarySampleDao(), GarminHrvSummarySampleDao.Properties.DeviceId); put(session.getGarminHrvValueSampleDao(), GarminHrvValueSampleDao.Properties.DeviceId); put(session.getBaseActivitySummaryDao(), BaseActivitySummaryDao.Properties.DeviceId); put(session.getPendingFileDao(), PendingFileDao.Properties.DeviceId); }}; for (final Map.Entry, Property> e : daoMap.entrySet()) { e.getKey().queryBuilder() .where(e.getValue().eq(deviceId)) .buildDelete().executeDeleteWithoutDetachingEntities(); } } @Override public String getManufacturer() { return "Garmin"; } @Override public int getDefaultIconResource() { return R.drawable.ic_device_zetime; } @Override public int getDisabledIconResource() { return R.drawable.ic_device_zetime_disabled; } @NonNull @Override public Class getDeviceSupportClass() { return GarminSupport.class; } @Nullable @Override public ActivitySummaryParser getActivitySummaryParser(final GBDevice device, final Context context) { return new GarminWorkoutParser(context); } @Override public SampleProvider getSampleProvider(final GBDevice device, DaoSession session) { return new GarminActivitySampleProvider(device, session); } @Override public TimeSampleProvider getStressSampleProvider(final GBDevice device, final DaoSession session) { return new GarminStressSampleProvider(device, session); } @Override public TimeSampleProvider getBodyEnergySampleProvider(final GBDevice device, final DaoSession session) { return new GarminBodyEnergySampleProvider(device, session); } @Override public TimeSampleProvider getHrvSummarySampleProvider(final GBDevice device, final DaoSession session) { return new GarminHrvSummarySampleProvider(device, session); } @Override public TimeSampleProvider getHrvValueSampleProvider(final GBDevice device, final DaoSession session) { return new GarminHrvValueSampleProvider(device, session); } @Override public Vo2MaxSampleProvider getVo2MaxSampleProvider(final GBDevice device, final DaoSession session) { return new WorkoutVo2MaxSampleProvider(device, session); } @Override public TimeSampleProvider getSpo2SampleProvider(final GBDevice device, final DaoSession session) { return new GarminSpo2SampleProvider(device, session); } @Override public TimeSampleProvider getPaiSampleProvider(final GBDevice device, final DaoSession session) { return new GarminPaiSampleProvider(device, session); } @Override public TimeSampleProvider getRespiratoryRateSampleProvider(final GBDevice device, final DaoSession session) { return new GarminRespiratoryRateSampleProvider(device, session); } @Override public TimeSampleProvider getRestingMetabolicRateProvider(final GBDevice device, final DaoSession session) { return new GarminRestingMetabolicRateSampleProvider(device, session); } @Override public TimeSampleProvider getSleepScoreProvider(final GBDevice device, final DaoSession session) { return new GarminSleepStatsSampleProvider(device, session); } @Override public GarminHeartRateRestingSampleProvider getHeartRateRestingSampleProvider(final GBDevice device, final DaoSession session) { return new GarminHeartRateRestingSampleProvider(device, session); } @Override public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) { final DeviceSpecificSettings deviceSpecificSettings = new DeviceSpecificSettings(); if (supports(device, GarminCapability.REALTIME_SETTINGS)) { deviceSpecificSettings.addRootScreen(R.xml.devicesettings_garmin_realtime_settings); } final List notifications = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.CALLS_AND_NOTIFICATIONS); notifications.add(R.xml.devicesettings_send_app_notifications); if (getCannedRepliesSlotCount(device) > 0) { notifications.add(R.xml.devicesettings_canned_reply_16); notifications.add(R.xml.devicesettings_canned_dismisscall_16); } if (getContactsSlotCount(device) > 0) { notifications.add(R.xml.devicesettings_contacts); } final List location = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.LOCATION); location.add(R.xml.devicesettings_workout_send_gps_to_band); if (supportsAgpsUpdates(device)) { location.add(R.xml.devicesettings_garmin_agps); } final List connection = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.CONNECTION); connection.add(R.xml.devicesettings_high_mtu); final List developer = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.DEVELOPER); developer.add(R.xml.devicesettings_keep_activity_data_on_device); developer.add(R.xml.devicesettings_fetch_unknown_files); return deviceSpecificSettings; } @Override public DeviceSpecificSettingsCustomizer getDeviceSpecificSettingsCustomizer(GBDevice device) { return new GarminSettingsCustomizer(); } @Override public boolean supportsActivityDataFetching() { return true; } @Override public boolean supportsActivityTracking() { return true; } @Override public boolean supportsActivityTracks() { return true; } @Override public boolean supportsStressMeasurement() { return true; } @Override public boolean supportsBodyEnergy() { return true; } @Override public boolean supportsHrvMeasurement() { return true; } @Override public boolean supportsVO2Max() { return true; } @Override public boolean supportsVO2MaxCycling() { return true; } @Override public boolean supportsVO2MaxRunning() { return true; } @Override public boolean supportsActiveCalories() { return true; } @Override public int[] getStressRanges() { // 1-25 = relaxed // 26-50 = low // 51-80 = moderate // 76-100 = high return new int[]{1, 26, 51, 76}; } @Override public boolean supportsHeartRateMeasurement(final GBDevice device) { return true; } @Override public boolean supportsHeartRateRestingMeasurement(final GBDevice device) { return true; } @Override public boolean supportsRealtimeData() { return true; } @Override public boolean supportsSpo2(GBDevice device) { return true; } @Override public boolean supportsRemSleep() { return true; } @Override public boolean supportsAwakeSleep() { return true; } @Override public boolean supportsSleepScore() { return true; } @Override public boolean supportsRespiratoryRate() { return true; } @Override public boolean supportsDayRespiratoryRate() { return true; } @Override public boolean supportsPai() { // Intensity Minutes return true; } @Override public int getPaiName() { return R.string.garmin_intensity_minutes; } @Override public boolean supportsPaiTime() { return true; } @Override public boolean supportsPaiLow() { return false; } @Override public int getPaiTarget() { return 150; } @Override public boolean supportsFindDevice() { return true; } @Override public boolean supportsWeather() { return true; } @Override public int getCannedRepliesSlotCount(final GBDevice device) { if (getPrefs(device).getBoolean(GarminPreferences.PREF_FEAT_CANNED_MESSAGES, false)) { return 16; } return 0; } @Override public int getContactsSlotCount(final GBDevice device) { if (getPrefs(device).getBoolean(GarminPreferences.PREF_FEAT_CONTACTS, false)) { return 50; } return 0; } protected static Prefs getPrefs(final GBDevice device) { return new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress())); } @Override public boolean supportsUnicodeEmojis() { return true; } public boolean supportsAgpsUpdates(final GBDevice device) { return !getPrefs(device).getString(GarminPreferences.PREF_AGPS_KNOWN_URLS, "").isEmpty(); } public boolean supports(final GBDevice device, final GarminCapability capability) { return getPrefs(device).getStringSet(GarminPreferences.PREF_GARMIN_CAPABILITIES, Collections.emptySet()) .contains(capability.name()); } @Override public boolean supportsFlashing() { return true; } @Nullable @Override public InstallHandler findInstallHandler(Uri uri, Context context) { final GarminFitFileInstallHandler fitFileInstallHandler = new GarminFitFileInstallHandler(uri, context); if (fitFileInstallHandler.isValid()) return fitFileInstallHandler; final GarminGpxRouteInstallHandler garminGpxRouteInstallHandler = new GarminGpxRouteInstallHandler(uri, context); if (garminGpxRouteInstallHandler.isValid()) return garminGpxRouteInstallHandler; return null; } }