diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java index f4ba54ea1..a083c1724 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java @@ -85,6 +85,10 @@ public class DeviceSettingsPreferenceConst { public static final String PREF_HEARTRATE_USE_FOR_SLEEP_DETECTION = "heartrate_sleep_detection"; public static final String PREF_HEARTRATE_MEASUREMENT_INTERVAL = "heartrate_measurement_interval"; + public static final String PREF_HEARTRATE_ACTIVITY_MONITORING = "heartrate_activity_monitoring"; + public static final String PREF_HEARTRATE_ALERT_ENABLED = "heartrate_alert_enabled"; + public static final String PREF_HEARTRATE_ALERT_THRESHOLD = "heartrate_alert_threshold"; + public static final String PREF_HEARTRATE_STRESS_MONITORING = "heartrate_stress_monitoring"; public static final String PREF_AUTOHEARTRATE_SWITCH = "pref_autoheartrate_switch"; public static final String PREF_AUTOHEARTRATE_SLEEP = "pref_autoheartrate_sleep"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java index 31d6290b6..efe23cbca 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java @@ -355,15 +355,43 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp }); } - final Preference heartrateMeasurementInterval = findPreference(PREF_HEARTRATE_MEASUREMENT_INTERVAL); + final ListPreference heartrateMeasurementInterval = findPreference(PREF_HEARTRATE_MEASUREMENT_INTERVAL); if (heartrateMeasurementInterval != null) { + final SwitchPreference activityMonitoring = findPreference(PREF_HEARTRATE_ACTIVITY_MONITORING); + final SwitchPreference heartrateAlertEnabled = findPreference(PREF_HEARTRATE_ALERT_ENABLED); + final SwitchPreference stressMonitoring = findPreference(PREF_HEARTRATE_STRESS_MONITORING); + heartrateMeasurementInterval.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newVal) { + public boolean onPreferenceChange(final Preference preference, final Object newVal) { GBApplication.deviceService().onSetHeartRateMeasurementInterval(Integer.parseInt((String) newVal)); + + final boolean isMeasurementIntervalEnabled = !newVal.equals("0"); + + if (activityMonitoring != null) { + activityMonitoring.setEnabled(isMeasurementIntervalEnabled); + } + if (heartrateAlertEnabled != null) { + heartrateAlertEnabled.setEnabled(isMeasurementIntervalEnabled); + } + if (stressMonitoring != null) { + 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) { + stressMonitoring.setEnabled(isMeasurementIntervalEnabled); + } } addPreferenceHandlerFor(PREF_SWIPE_UNLOCK); @@ -416,6 +444,10 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp addPreferenceHandlerFor(PREF_AUTOHEARTRATE_INTERVAL); addPreferenceHandlerFor(PREF_AUTOHEARTRATE_START); addPreferenceHandlerFor(PREF_AUTOHEARTRATE_END); + addPreferenceHandlerFor(PREF_HEARTRATE_ACTIVITY_MONITORING); + addPreferenceHandlerFor(PREF_HEARTRATE_ALERT_THRESHOLD); + addPreferenceHandlerFor(PREF_HEARTRATE_ALERT_ENABLED); + addPreferenceHandlerFor(PREF_HEARTRATE_STRESS_MONITORING); addPreferenceHandlerFor(PREF_DO_NOT_DISTURB_NOAUTO); addPreferenceHandlerFor(PREF_DO_NOT_DISTURB_NOAUTO_START); addPreferenceHandlerFor(PREF_DO_NOT_DISTURB_NOAUTO_END); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/HuamiCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/HuamiCoordinator.java index 11a4a0d39..42575cf63 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/HuamiCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/HuamiCoordinator.java @@ -273,6 +273,26 @@ public abstract class HuamiCoordinator extends AbstractDeviceCoordinator { return GBApplication.getPrefs().getInt(DeviceSettingsPreferenceConst.PREF_HEARTRATE_MEASUREMENT_INTERVAL, 0) / 60; } + public static boolean getHeartrateActivityMonitoring(String deviceAddress) throws IllegalArgumentException { + Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress)); + return prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_HEARTRATE_ACTIVITY_MONITORING, false); + } + + public static boolean getHeartrateAlert(String deviceAddress) throws IllegalArgumentException { + Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress)); + return prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_HEARTRATE_ALERT_ENABLED, false); + } + + public static int getHeartrateAlertThreshold(String deviceAddress) throws IllegalArgumentException { + Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress)); + return prefs.getInt(DeviceSettingsPreferenceConst.PREF_HEARTRATE_ALERT_THRESHOLD, 150); + } + + public static boolean getHeartrateStressMonitoring(String deviceAddress) throws IllegalArgumentException { + Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress)); + return prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_HEARTRATE_STRESS_MONITORING, false); + } + public static boolean getBtConnectedAdvertising(String deviceAddress) { Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress)); return prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_BT_CONNECTED_ADVERTISEMENT, false); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband5/MiBand5Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband5/MiBand5Coordinator.java index 57d9531af..edf442680 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband5/MiBand5Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband5/MiBand5Coordinator.java @@ -106,7 +106,7 @@ public class MiBand5Coordinator extends HuamiCoordinator { R.xml.devicesettings_miband5, R.xml.devicesettings_vibrationpatterns, R.xml.devicesettings_wearlocation, - R.xml.devicesettings_heartrate_sleep, + R.xml.heartrate_sleep_alert_activity_stress, R.xml.devicesettings_goal_notification, R.xml.devicesettings_custom_emoji_font, R.xml.devicesettings_timeformat, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index 006cf6290..a74f3079d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -171,6 +171,10 @@ import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.Dev import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_START; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_END; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_LIFT_WRIST; +import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_ACTIVITY_MONITORING; +import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_ALERT_ENABLED; +import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_ALERT_THRESHOLD; +import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HEARTRATE_STRESS_MONITORING; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_INACTIVITY_ENABLE; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_INACTIVITY_START; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_INACTIVITY_END; @@ -230,6 +234,7 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService.CO import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService.COMMAND_GPS_VERSION; import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService.COMMAND_WORKOUT_ACTIVITY_TYPES; import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService.DISPLAY_ITEM_BIT_CLOCK; +import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService.ENDPOINT_DISPLAY; import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService.ENDPOINT_DISPLAY_ITEMS; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_VIBRATION_COUNT; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_VIBRATION_PROFILE; @@ -679,6 +684,37 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { return this; } + private HuamiSupport setHeartrateActivityMonitoring(TransactionBuilder builder) { + final boolean enableHrActivityMonitoring = HuamiCoordinator.getHeartrateActivityMonitoring(gbDevice.getAddress()); + final byte[] cmd = {ENDPOINT_DISPLAY, 0x22, 0x00, (byte) (enableHrActivityMonitoring ? 0x01 : 0x00)}; + writeToConfiguration(builder, cmd); + return this; + } + + private HuamiSupport setHeartrateAlert(TransactionBuilder builder) { + final boolean enableHrAlert = HuamiCoordinator.getHeartrateAlert(gbDevice.getAddress()); + final int hrAlertThreshold = HuamiCoordinator.getHeartrateAlertThreshold(gbDevice.getAddress()); + + final byte[] cmd = { + ENDPOINT_DISPLAY, + 0x1a, + 0x00, + (byte) (enableHrAlert ? 0x01 : 0x00), + (byte) hrAlertThreshold + }; + + writeToConfiguration(builder, cmd); + + return this; + } + + private HuamiSupport setHeartrateStressMonitoring(TransactionBuilder builder) { + final boolean enableHrStressMonitoring = HuamiCoordinator.getHeartrateStressMonitoring(gbDevice.getAddress()); + final byte[] cmd = new byte[] {(byte) 0xfe, 0x06, 0x00, (byte) (enableHrStressMonitoring ? 0x01 : 0x00)}; + writeToConfiguration(builder, cmd); + return this; + } + private HuamiSupport setHeartrateMeasurementInterval(TransactionBuilder builder, int minutes) { if (characteristicHRControlPoint != null) { builder.notify(characteristicHRControlPoint, true); @@ -2536,6 +2572,16 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { case PREF_HUAMI_VIBRATION_TRY_FIND_BAND: setVibrationPattern(builder, config); break; + case PREF_HEARTRATE_ACTIVITY_MONITORING: + setHeartrateActivityMonitoring(builder); + break; + case PREF_HEARTRATE_ALERT_ENABLED: + case PREF_HEARTRATE_ALERT_THRESHOLD: + setHeartrateAlert(builder); + break; + case PREF_HEARTRATE_STRESS_MONITORING: + setHeartrateStressMonitoring(builder); + break; } builder.queue(getQueue()); } catch (IOException e) { @@ -3677,6 +3723,9 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { setGoalNotification(builder); setInactivityWarnings(builder); setHeartrateSleepSupport(builder); + setHeartrateActivityMonitoring(builder); + setHeartrateAlert(builder); + setHeartrateStressMonitoring(builder); setDisconnectNotification(builder); setExposeHRThridParty(builder); setHeartrateMeasurementInterval(builder, HuamiCoordinator.getHeartRateMeasurementInterval(getDevice().getAddress())); diff --git a/app/src/main/res/drawable/ic_mood_bad.xml b/app/src/main/res/drawable/ic_mood_bad.xml new file mode 100644 index 000000000..7548a5887 --- /dev/null +++ b/app/src/main/res/drawable/ic_mood_bad.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_warning_gray.xml b/app/src/main/res/drawable/ic_warning_gray.xml new file mode 100644 index 000000000..98ce89163 --- /dev/null +++ b/app/src/main/res/drawable/ic_warning_gray.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index aa3c82889..f9d8d1377 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1581,6 +1581,34 @@ 3600 + + @string/heartrate_bpm_100 + @string/heartrate_bpm_105 + @string/heartrate_bpm_110 + @string/heartrate_bpm_112 + @string/heartrate_bpm_120 + @string/heartrate_bpm_125 + @string/heartrate_bpm_130 + @string/heartrate_bpm_135 + @string/heartrate_bpm_140 + @string/heartrate_bpm_145 + @string/heartrate_bpm_150 + + + + 100 + 105 + 110 + 112 + 120 + 125 + 130 + 135 + 140 + 145 + 150 + + @string/off @string/interval_five_minutes diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bd5c99c3c..895419d9c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -482,6 +482,17 @@ every 15 minutes every 30 minutes every 45 minutes + 100 bpm + 105 bpm + 110 bpm + 112 bpm + 120 bpm + 125 bpm + 130 bpm + 135 bpm + 140 bpm + 145 bpm + 150 bpm once an hour Speed zones Total minutes @@ -538,6 +549,13 @@ Do some activity and synchronize device. About to transfer %1$s of data starting from %2$s Daily step target + Heart rate alert (experimental) + Vibrate the band when the heart rate is over a threshold, without any obvious physical activity in the last 10 minutes. This feature is experimental, and was not extensively tested. + Heart rate alert threshold + Stress monitoring + Monitor stress level while resting + Activity monitoring + Automatically increase the heart rate detection frequency when the band detects physical exercise, to increase heart rate capture accuracy. Error executing \'%1$s\' Your activity (ALPHA) Cannot connect: %1$s @@ -685,6 +703,7 @@ Disable inactivity warnings for a time interval Heart Rate Monitoring Configure heart rate monitoring + Configure heart rate monitoring and alert thresholds Start time End time Activate display upon lift during Do Not Disturb diff --git a/app/src/main/res/xml/heartrate_sleep_alert_activity_stress.xml b/app/src/main/res/xml/heartrate_sleep_alert_activity_stress.xml new file mode 100644 index 000000000..7abecfa16 --- /dev/null +++ b/app/src/main/res/xml/heartrate_sleep_alert_activity_stress.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + +