1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-25 03:16:51 +01:00

Merge pull request #1181 from Dikay900/remove_invalid_hr_data

remove incorrect HR data <10 from the graphs
This commit is contained in:
Carsten Pfeiffer 2018-09-04 21:08:21 +02:00 committed by GitHub
commit 5e4ecd774b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 80 additions and 16 deletions

View File

@ -16,9 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */ along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.activities; package nodomain.freeyourgadget.gadgetbridge.activities;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class HeartRateUtils { public class HeartRateUtils {
public static final int MAX_HEART_RATE_VALUE = 250; public static final int MAX_HEART_RATE_VALUE = 250;
public static final int MIN_HEART_RATE_VALUE = 0; public static final int MIN_HEART_RATE_VALUE = 10;
/** /**
* The maxiumum gap between two hr measurements in which * The maxiumum gap between two hr measurements in which
* we interpolate between the measurements. Otherwise, two * we interpolate between the measurements. Otherwise, two
@ -28,7 +33,37 @@ public class HeartRateUtils {
*/ */
public static final int MAX_HR_MEASUREMENTS_GAP_MINUTES = 10; public static final int MAX_HR_MEASUREMENTS_GAP_MINUTES = 10;
public static boolean isValidHeartRateValue(int value) { private int maxHeartRateValue;
return value > HeartRateUtils.MIN_HEART_RATE_VALUE && value < HeartRateUtils.MAX_HEART_RATE_VALUE; private int minHeartRateValue;
private static final HeartRateUtils instance = new HeartRateUtils();
public static HeartRateUtils getInstance() {
return instance;
}
/**
* Singleton - to access this class use the static #getInstance()
*/
private HeartRateUtils() {
updateCachedHeartRatePreferences();
}
public void updateCachedHeartRatePreferences(){
Prefs prefs = GBApplication.getPrefs();
maxHeartRateValue = prefs.getInt(GBPrefs.CHART_MAX_HEART_RATE, MAX_HEART_RATE_VALUE);
minHeartRateValue = prefs.getInt(GBPrefs.CHART_MIN_HEART_RATE, MIN_HEART_RATE_VALUE);
}
public int getMaxHeartRate(){
return maxHeartRateValue;
}
public int getMinHeartRate(){
return minHeartRateValue;
}
public boolean isValidHeartRateValue(int value) {
return value >= getMinHeartRate() && value <= getMaxHeartRate();
} }
} }

View File

@ -70,8 +70,6 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import static nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils.isValidHeartRateValue;
/** /**
* A base class fragment to be used with ChartsActivity. The fragment can supply * A base class fragment to be used with ChartsActivity. The fragment can supply
* a title to be displayed in the activity by returning non-null in #getTitle() * a title to be displayed in the activity by returning non-null in #getTitle()
@ -443,6 +441,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
List<Entry> heartrateEntries = hr ? new ArrayList<Entry>(numEntries) : null; List<Entry> heartrateEntries = hr ? new ArrayList<Entry>(numEntries) : null;
List<Integer> colors = new ArrayList<>(numEntries); // this is kinda inefficient... List<Integer> colors = new ArrayList<>(numEntries); // this is kinda inefficient...
int lastHrSampleIndex = -1; int lastHrSampleIndex = -1;
HeartRateUtils heartRateUtilsInstance = HeartRateUtils.getInstance();
for (int i = 0; i < numEntries; i++) { for (int i = 0; i < numEntries; i++) {
ActivitySample sample = samples.get(i); ActivitySample sample = samples.get(i);
@ -512,7 +511,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
} }
activityEntries.add(createLineEntry(value, ts)); activityEntries.add(createLineEntry(value, ts));
} }
if (hr && sample.getKind() != ActivityKind.TYPE_NOT_WORN && HeartRateUtils.isValidHeartRateValue(sample.getHeartRate())) { if (hr && sample.getKind() != ActivityKind.TYPE_NOT_WORN && heartRateUtilsInstance.isValidHeartRateValue(sample.getHeartRate())) {
if (lastHrSampleIndex > -1 && ts - lastHrSampleIndex > 1800*HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) { if (lastHrSampleIndex > -1 && ts - lastHrSampleIndex > 1800*HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) {
heartrateEntries.add(createLineEntry(0, lastHrSampleIndex + 1)); heartrateEntries.add(createLineEntry(0, lastHrSampleIndex + 1));
heartrateEntries.add(createLineEntry(0, ts - 1)); heartrateEntries.add(createLineEntry(0, ts - 1));

View File

@ -104,8 +104,8 @@ public class ActivitySleepChartFragment extends AbstractChartFragment {
yAxisRight.setDrawLabels(true); yAxisRight.setDrawLabels(true);
yAxisRight.setDrawTopYLabelEntry(true); yAxisRight.setDrawTopYLabelEntry(true);
yAxisRight.setTextColor(CHART_TEXT_COLOR); yAxisRight.setTextColor(CHART_TEXT_COLOR);
yAxisRight.setAxisMaximum(HeartRateUtils.MAX_HEART_RATE_VALUE); yAxisRight.setAxisMaximum(HeartRateUtils.getInstance().getMaxHeartRate());
yAxisRight.setAxisMinimum(HeartRateUtils.MIN_HEART_RATE_VALUE); yAxisRight.setAxisMinimum(HeartRateUtils.getInstance().getMinHeartRate());
// refresh immediately instead of use refreshIfVisible(), for perceived performance // refresh immediately instead of use refreshIfVisible(), for perceived performance
refresh(); refresh();

View File

@ -168,7 +168,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
private void addSample(ActivitySample sample) { private void addSample(ActivitySample sample) {
int heartRate = sample.getHeartRate(); int heartRate = sample.getHeartRate();
int timestamp = tsTranslation.shorten(sample.getTimestamp()); int timestamp = tsTranslation.shorten(sample.getTimestamp());
if (HeartRateUtils.isValidHeartRateValue(heartRate)) { if (HeartRateUtils.getInstance().isValidHeartRateValue(heartRate)) {
setCurrentHeartRate(heartRate, timestamp); setCurrentHeartRate(heartRate, timestamp);
} }
int steps = sample.getSteps(); int steps = sample.getSteps();
@ -470,8 +470,8 @@ public class LiveActivityFragment extends AbstractChartFragment {
yAxisRight.setDrawLabels(true); yAxisRight.setDrawLabels(true);
yAxisRight.setDrawTopYLabelEntry(false); yAxisRight.setDrawTopYLabelEntry(false);
yAxisRight.setTextColor(CHART_TEXT_COLOR); yAxisRight.setTextColor(CHART_TEXT_COLOR);
yAxisRight.setAxisMaximum(HeartRateUtils.MAX_HEART_RATE_VALUE); yAxisRight.setAxisMaximum(HeartRateUtils.getInstance().getMaxHeartRate());
yAxisRight.setAxisMinimum(HeartRateUtils.MIN_HEART_RATE_VALUE); yAxisRight.setAxisMinimum(HeartRateUtils.getInstance().getMinHeartRate());
mHistorySet = new LineDataSet(new ArrayList<Entry>(), getString(R.string.live_activity_steps_history)); mHistorySet = new LineDataSet(new ArrayList<Entry>(), getString(R.string.live_activity_steps_history));
mHistorySet.setAxisDependency(YAxis.AxisDependency.LEFT); mHistorySet.setAxisDependency(YAxis.AxisDependency.LEFT);

View File

@ -233,8 +233,8 @@ public class SleepChartFragment extends AbstractChartFragment {
yAxisRight.setDrawLabels(true); yAxisRight.setDrawLabels(true);
yAxisRight.setDrawTopYLabelEntry(true); yAxisRight.setDrawTopYLabelEntry(true);
yAxisRight.setTextColor(CHART_TEXT_COLOR); yAxisRight.setTextColor(CHART_TEXT_COLOR);
yAxisRight.setAxisMaxValue(HeartRateUtils.MAX_HEART_RATE_VALUE); yAxisRight.setAxisMaxValue(HeartRateUtils.getInstance().getMaxHeartRate());
yAxisRight.setAxisMinValue(HeartRateUtils.MIN_HEART_RATE_VALUE); yAxisRight.setAxisMinValue(HeartRateUtils.getInstance().getMinHeartRate());
} }
@Override @Override

View File

@ -151,7 +151,7 @@ public class GPXExporter implements ActivityTrackExporter {
} }
int hr = point.getHeartRate(); int hr = point.getHeartRate();
if (!HeartRateUtils.isValidHeartRateValue(hr)) { if (!HeartRateUtils.getInstance().isValidHeartRateValue(hr)) {
if (!includeHeartRateOfNearestSample) { if (!includeHeartRateOfNearestSample) {
return; return;
} }
@ -162,7 +162,7 @@ public class GPXExporter implements ActivityTrackExporter {
} }
hr = closestPointItem.getHeartRate(); hr = closestPointItem.getHeartRate();
if (!HeartRateUtils.isValidHeartRateValue(hr)) { if (!HeartRateUtils.getInstance().isValidHeartRateValue(hr)) {
return; return;
} }
} }
@ -177,11 +177,12 @@ public class GPXExporter implements ActivityTrackExporter {
private @Nullable ActivityPoint findClosestSensibleActivityPoint(Date time, List<ActivityPoint> trackPoints) { private @Nullable ActivityPoint findClosestSensibleActivityPoint(Date time, List<ActivityPoint> trackPoints) {
ActivityPoint closestPointItem = null; ActivityPoint closestPointItem = null;
HeartRateUtils heartRateUtilsInstance = HeartRateUtils.getInstance();
long lowestDifference = 60 * 2 * 1000; // minimum distance is 2min long lowestDifference = 60 * 2 * 1000; // minimum distance is 2min
for (ActivityPoint pointItem : trackPoints) { for (ActivityPoint pointItem : trackPoints) {
int hrItem = pointItem.getHeartRate(); int hrItem = pointItem.getHeartRate();
if (HeartRateUtils.isValidHeartRateValue(hrItem)) { if (heartRateUtilsInstance.isValidHeartRateValue(hrItem)) {
Date timeItem = pointItem.getTime(); Date timeItem = pointItem.getTime();
if (timeItem.after(time) || timeItem.equals(time)) { if (timeItem.after(time) || timeItem.equals(time)) {
break; // we assume that the given trackPoints are sorted in time ascending order (oldest first) break; // we assume that the given trackPoints are sorted in time ascending order (oldest first)

View File

@ -47,6 +47,7 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmClockReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmClockReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmReceiver;
@ -784,6 +785,9 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
mDeviceSupport.setAutoReconnect(autoReconnect); mDeviceSupport.setAutoReconnect(autoReconnect);
} }
} }
if (GBPrefs.CHART_MAX_HEART_RATE.equals(key) || GBPrefs.CHART_MIN_HEART_RATE.equals(key)) {
HeartRateUtils.getInstance().updateCachedHeartRatePreferences();
}
} }
protected boolean hasPrefs() { protected boolean hasPrefs() {

View File

@ -38,6 +38,9 @@ public class GBPrefs {
public static final String USER_NAME_DEFAULT = "gadgetbridge-user"; public static final String USER_NAME_DEFAULT = "gadgetbridge-user";
private static final String USER_BIRTHDAY = ""; private static final String USER_BIRTHDAY = "";
public static final String CHART_MAX_HEART_RATE = "chart_max_heart_rate";
public static final String CHART_MIN_HEART_RATE = "chart_min_heart_rate";
private final Prefs mPrefs; private final Prefs mPrefs;
public GBPrefs(Prefs prefs) { public GBPrefs(Prefs prefs) {

View File

@ -469,6 +469,10 @@
<string name="activity_prefs_height_cm">Height in cm</string> <string name="activity_prefs_height_cm">Height in cm</string>
<string name="activity_prefs_weight_kg">Weight in kg</string> <string name="activity_prefs_weight_kg">Weight in kg</string>
<string name="activity_prefs_charts">Chart settings</string>
<string name="activity_prefs_chart_max_heart_rate">Max heart rate</string>
<string name="activity_prefs_chart_min_heart_rate">Min heart rate</string>
<string name="authenticating">Authenticating</string> <string name="authenticating">Authenticating</string>
<string name="authentication_required">Authentication required</string> <string name="authentication_required">Authentication required</string>

View File

@ -101,6 +101,24 @@
android:maxLength="2" android:maxLength="2"
android:title="@string/activity_prefs_sleep_duration" /> android:title="@string/activity_prefs_sleep_duration" />
</PreferenceScreen> </PreferenceScreen>
<PreferenceScreen
android:key="pref_charts"
android:title="@string/activity_prefs_charts">
<EditTextPreference
android:inputType="number"
android:key="chart_max_heart_rate"
android:maxLength="3"
android:defaultValue="250"
android:title="@string/activity_prefs_chart_max_heart_rate" />
<EditTextPreference
android:inputType="number"
android:key="chart_min_heart_rate"
android:maxLength="3"
android:defaultValue="10"
android:title="@string/activity_prefs_chart_min_heart_rate" />
</PreferenceScreen>
<CheckBoxPreference <CheckBoxPreference
android:layout="@layout/preference_checkbox" android:layout="@layout/preference_checkbox"
android:defaultValue="true" android:defaultValue="true"