/* Copyright (C) 2022-2024 Arjan Schrijver, José Rebelo This file is part of Gadgetbridge. Gadgetbridge is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gadgetbridge is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.capabilities; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_ACTIVITY_MONITORING; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_ALERT_ACTIVE_HIGH_THRESHOLD; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_ALERT_ENABLED; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_ALERT_HIGH_THRESHOLD; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_ALERT_LOW_THRESHOLD; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_MEASUREMENT_INTERVAL; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_STRESS_MONITORING; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_USE_FOR_SLEEP_DETECTION; import android.content.Context; import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.SwitchPreferenceCompat; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler; public class HeartRateCapability { public enum MeasurementInterval { OFF(0, R.string.off), SMART(-1, R.string.smart), MINUTES_1(60, R.string.interval_one_minute), MINUTES_5(300, R.string.interval_five_minutes), MINUTES_10(600, R.string.interval_ten_minutes), MINUTES_15(900, R.string.interval_fifteen_minutes), MINUTES_30(1800, R.string.interval_thirty_minutes), MINUTES_45(2700, R.string.interval_forty_five_minutes), HOUR_1(3600, R.string.interval_one_hour), ; private final int intervalSeconds; private final int label; MeasurementInterval(final int intervalSeconds, final int label) { this.intervalSeconds = intervalSeconds; this.label = label; } public int getIntervalSeconds() { return intervalSeconds; } public int getLabel() { return label; } public String getLabel(final Context context) { return context.getString(label); } } public void registerPreferences(final Context context, final List intervals, final DeviceSpecificSettingsHandler handler) { final Preference enableHeartrateSleepSupport = handler.findPreference(PREF_HEARTRATE_USE_FOR_SLEEP_DETECTION); if (enableHeartrateSleepSupport != null) { enableHeartrateSleepSupport.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newVal) { GBApplication.deviceService(handler.getDevice()).onEnableHeartRateSleepSupport(Boolean.TRUE.equals(newVal)); return true; } }); } handler.addPreferenceHandlerFor(PREF_HEARTRATE_ALERT_ACTIVE_HIGH_THRESHOLD); handler.addPreferenceHandlerFor(PREF_HEARTRATE_ALERT_HIGH_THRESHOLD); handler.addPreferenceHandlerFor(PREF_HEARTRATE_ALERT_LOW_THRESHOLD); final ListPreference heartrateMeasurementInterval = handler.findPreference(PREF_HEARTRATE_MEASUREMENT_INTERVAL); final ListPreference heartrateAlertActiveHigh = handler.findPreference(PREF_HEARTRATE_ALERT_ACTIVE_HIGH_THRESHOLD); final ListPreference heartrateAlertHigh = handler.findPreference(PREF_HEARTRATE_ALERT_HIGH_THRESHOLD); final ListPreference heartrateAlertLow = handler.findPreference(PREF_HEARTRATE_ALERT_LOW_THRESHOLD); // Newer devices that have low alert threshold can only use it if measurement interval is smart (-1) or 1 minute final boolean hrAlertsNeedSmartOrOne = heartrateAlertActiveHigh != null && heartrateAlertHigh != null && heartrateAlertLow != null && heartrateMeasurementInterval != null; if (hrAlertsNeedSmartOrOne) { final boolean hrMonitoringIsSmartOrOne = heartrateMeasurementInterval.getValue().equals("60") || heartrateMeasurementInterval.getValue().equals("-1"); heartrateAlertHigh.setEnabled(hrMonitoringIsSmartOrOne); heartrateAlertLow.setEnabled(hrMonitoringIsSmartOrOne); heartrateAlertActiveHigh.setEnabled(hrMonitoringIsSmartOrOne); } if (heartrateMeasurementInterval != null) { // Set the measurement intervals dynamically, as per the device's capability final CharSequence[] entries = new CharSequence[intervals.size()]; final CharSequence[] values = new CharSequence[intervals.size()]; for (int i = 0; i < intervals.size(); i++) { entries[i] = intervals.get(i).getLabel(context); values[i] = String.valueOf(intervals.get(i).getIntervalSeconds()); } heartrateMeasurementInterval.setEntries(entries); heartrateMeasurementInterval.setEntryValues(values); final SwitchPreferenceCompat activityMonitoring = handler.findPreference(PREF_HEARTRATE_ACTIVITY_MONITORING); final SwitchPreferenceCompat heartrateAlertEnabled = handler.findPreference(PREF_HEARTRATE_ALERT_ENABLED); final SwitchPreferenceCompat stressMonitoring = handler.findPreference(PREF_HEARTRATE_STRESS_MONITORING); heartrateMeasurementInterval.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { public boolean onPreferenceChange(final Preference preference, final Object newVal) { GBApplication.deviceService(handler.getDevice()).onSetHeartRateMeasurementInterval(Integer.parseInt((String) newVal)); final boolean isMeasurementIntervalEnabled = !newVal.equals("0"); if (activityMonitoring != null) { activityMonitoring.setEnabled(isMeasurementIntervalEnabled); } if (heartrateAlertEnabled != null) { heartrateAlertEnabled.setEnabled(isMeasurementIntervalEnabled); } if (hrAlertsNeedSmartOrOne) { // Same as above, check if smart or 1 minute final boolean hrMonitoringIsSmartOrOne = newVal.equals("60") || newVal.equals("-1"); heartrateAlertActiveHigh.setEnabled(hrMonitoringIsSmartOrOne); heartrateAlertHigh.setEnabled(hrMonitoringIsSmartOrOne); heartrateAlertLow.setEnabled(hrMonitoringIsSmartOrOne); } if (stressMonitoring != null && !hrAlertsNeedSmartOrOne) { // Newer devices (that have hrAlertsNeedSmartOrOne) also don't need HR monitoring for stress monitoring stressMonitoring.setEnabled(isMeasurementIntervalEnabled); } return true; } }); final boolean isMeasurementIntervalEnabled = !heartrateMeasurementInterval.getValue().equals("0"); if (activityMonitoring != null) { activityMonitoring.setEnabled(isMeasurementIntervalEnabled); } if (heartrateAlertEnabled != null) { heartrateAlertEnabled.setEnabled(isMeasurementIntervalEnabled); } if (stressMonitoring != null && !hrAlertsNeedSmartOrOne) { // Newer devices (that have hrAlertsNeedSmartOrOne) also don't need HR monitoring for stress monitoring stressMonitoring.setEnabled(isMeasurementIntervalEnabled); } } } }