From 8c91c53bd57fe70adfcb9f7e1f9bdc16785a562a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Sun, 7 Jan 2024 20:55:36 +0000 Subject: [PATCH] wip: refactor charts to get hr from a separate file --- .../ActivitySummariesChartFragment.java | 124 +++++++++++++++++- .../activities/ActivitySummaryDetail.java | 8 +- .../gadgetbridge/util/gpx/GpxParser.java | 36 +++++ .../util/gpx/model/GpxTrackPoint.java | 18 ++- 4 files changed, 178 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesChartFragment.java index e5510f693..11b8efcc3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesChartFragment.java @@ -37,7 +37,11 @@ import com.github.mikephil.charting.data.LineData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.R; @@ -47,8 +51,14 @@ import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsHost; import nodomain.freeyourgadget.gadgetbridge.activities.charts.DefaultChartsData; import nodomain.freeyourgadget.gadgetbridge.database.DBAccess; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; +import nodomain.freeyourgadget.gadgetbridge.util.gpx.GpxParseException; +import nodomain.freeyourgadget.gadgetbridge.util.gpx.GpxParser; +import nodomain.freeyourgadget.gadgetbridge.util.gpx.model.GpxFile; +import nodomain.freeyourgadget.gadgetbridge.util.gpx.model.GpxTrackPoint; public class ActivitySummariesChartFragment extends AbstractActivityChartFragment { @@ -59,18 +69,60 @@ public class ActivitySummariesChartFragment extends AbstractActivityChartFragmen private int endTime; private GBDevice gbDevice; private View view; + private File gpxFile; public void setDateAndGetData(GBDevice gbDevice, long startTime, long endTime) { this.startTime = (int) startTime; this.endTime = (int) endTime; this.gbDevice = gbDevice; + this.gpxFile = null; + if (this.view != null) { + createLocalRefreshTask("Visualizing data", getActivity()).execute(); + } + } + + public void setDateAndGetData(GBDevice gbDevice, File gpxFile) { + this.gbDevice = gbDevice; + this.gpxFile = gpxFile; + this.startTime = 0; + this.endTime = 0; if (this.view != null) { createLocalRefreshTask("Visualizing data", getActivity()).execute(); } } protected RefreshTask createLocalRefreshTask(String task, Context context) { - return new RefreshTask(task, context); + if (gpxFile != null) { + return new RefreshTask(task, context, (dbHandler) -> { + final GpxFile gpx; + + try (FileInputStream inputStream = new FileInputStream(gpxFile)) { + final GpxParser gpxParser = new GpxParser(inputStream); + gpx = gpxParser.getGpxFile(); + } catch (final IOException e) { + LOG.error("Failed to open {}", gpxFile, e); + // fallback to activity samples + return getAllSamples(dbHandler, gbDevice, startTime, endTime); + } catch (final GpxParseException e) { + LOG.error("Failed to parse gpx file", e); + // fallback to activity samples + return getAllSamples(dbHandler, gbDevice, startTime, endTime); + } + + final List ret = new ArrayList<>(gpx.getPoints().size()); + + for (final GpxTrackPoint point : gpx.getPoints()) { + ret.add(new GpxActivitySample( + (int) (point.getTime().getTime() / 1000L), + point.getHeartRate() + )); + } + + return ret; + }); + } else { + return new RefreshTask(task, context, (dbHandler) -> getAllSamples(dbHandler, gbDevice, startTime, endTime)); + } } @Override @@ -135,6 +187,8 @@ public class ActivitySummariesChartFragment extends AbstractActivityChartFragmen @Override protected List getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) { + LOG.warn("This should not need to be called..."); + // FIXME: This fragment should be refactored, this is not even used return getAllSamples(db, device, tsFrom, tsTo); } @@ -178,16 +232,18 @@ public class ActivitySummariesChartFragment extends AbstractActivityChartFragmen } public class RefreshTask extends DBAccess { + private final ActivitySampleGetter getter; - public RefreshTask(String task, Context context) { + public RefreshTask(final String task, final Context context, final ActivitySampleGetter getter) { super(task, context); + this.getter = getter; } @Override protected void doInBackground(DBHandler handler) { - List samples = getAllSamples(handler, gbDevice, startTime, endTime); + List samples = getter.getSamples(handler); - DefaultChartsData dcd = null; + DefaultChartsData dcd = null; try { dcd = refresh(gbDevice, samples); } catch (Exception e) { @@ -205,4 +261,64 @@ public class ActivitySummariesChartFragment extends AbstractActivityChartFragmen mChart.invalidate(); } } + + public interface ActivitySampleGetter { + List getSamples(DBHandler handler); + } + + private static class GpxActivitySample implements ActivitySample { + + private final int timestamp; + private final int hr; + + public GpxActivitySample(final int timestamp, final int hr) { + this.timestamp = timestamp; + this.hr = hr; + } + + @Override + public SampleProvider getProvider() { + return null; + } + + @Override + public int getRawKind() { + return ActivityKind.TYPE_ACTIVITY; + } + + @Override + public int getKind() { + return ActivityKind.TYPE_ACTIVITY; + } + + @Override + public int getRawIntensity() { + return 0; + } + + @Override + public float getIntensity() { + return 0; + } + + @Override + public int getSteps() { + return 0; + } + + @Override + public int getHeartRate() { + return hr; + } + + @Override + public void setHeartRate(final int value) { + + } + + @Override + public int getTimestamp() { + return timestamp; + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummaryDetail.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummaryDetail.java index eb3e2c95d..50645a195 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummaryDetail.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummaryDetail.java @@ -182,11 +182,13 @@ public class ActivitySummaryDetail extends AbstractGBActivity { currentItem = newItem; makeSummaryHeader(newItem); makeSummaryContent(newItem); - activitySummariesChartFragment.setDateAndGetData(getGBDevice(currentItem.getDevice()), currentItem.getStartTime().getTime() / 1000, currentItem.getEndTime().getTime() / 1000); - if (get_gpx_file() != null) { + final File gpxFile = get_gpx_file(); + if (gpxFile != null) { + activitySummariesChartFragment.setDateAndGetData(getGBDevice(currentItem.getDevice()), gpxFile); showCanvas(); - activitySummariesGpsFragment.set_data(get_gpx_file()); + activitySummariesGpsFragment.set_data(gpxFile); } else { + activitySummariesChartFragment.setDateAndGetData(getGBDevice(currentItem.getDevice()), currentItem.getStartTime().getTime() / 1000, currentItem.getEndTime().getTime() / 1000); hideCanvas(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/gpx/GpxParser.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/gpx/GpxParser.java index 8a29d2779..bac55b521 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/gpx/GpxParser.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/gpx/GpxParser.java @@ -168,6 +168,12 @@ public class GpxParser { case "time": trackPointBuilder.withTime(parseTime()); continue; + case "extensions": + final int hr = parseExtensions(); + if (hr >= 0) { + trackPointBuilder.withHeartRate(hr); + } + continue; } } @@ -177,6 +183,36 @@ public class GpxParser { return trackPointBuilder.build(); } + private int parseExtensions() throws Exception { + while (eventType != XmlPullParser.END_TAG || !parser.getName().equals("extensions")) { + if (parser.getEventType() == XmlPullParser.START_TAG) { + switch (parser.getName()) { + case "gpxtpx:TrackPointExtension": + return parseTrackPointExtension(); + } + } + + eventType = parser.next(); + } + + return -1; + } + + private int parseTrackPointExtension() throws Exception { + while (eventType != XmlPullParser.END_TAG || !parser.getName().equals("gpxtpx:TrackPointExtension")) { + if (parser.getEventType() == XmlPullParser.START_TAG) { + switch (parser.getName()) { + case "gpxtpx:hr": + return Integer.parseInt(parseStringContent("gpxtpx:hr")); + } + } + + eventType = parser.next(); + } + + return -1; + } + private GpxWaypoint parseWaypoint() throws Exception { final GpxWaypoint.Builder waypointBuilder = new GpxWaypoint.Builder(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/gpx/model/GpxTrackPoint.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/gpx/model/GpxTrackPoint.java index 1867ffc35..930a2726b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/gpx/model/GpxTrackPoint.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/gpx/model/GpxTrackPoint.java @@ -23,16 +23,26 @@ import nodomain.freeyourgadget.gadgetbridge.model.GPSCoordinate; public class GpxTrackPoint extends GPSCoordinate { private final Date time; + private final int heartRate; - public GpxTrackPoint(final double longitude, final double latitude, final double altitude, final Date time) { + public GpxTrackPoint(final double longitude, final double latitude, final double altitude, final Date time, final int heartRate) { super(longitude, latitude, altitude); this.time = time; + this.heartRate = heartRate; + } + + public GpxTrackPoint(final double longitude, final double latitude, final double altitude, final Date time) { + this(longitude, latitude, altitude, time, -1); } public Date getTime() { return time; } + public int getHeartRate() { + return heartRate; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -52,6 +62,7 @@ public class GpxTrackPoint extends GPSCoordinate { private double latitude; private double altitude; private Date time; + private int heartRate; public Builder withLongitude(final double longitude) { this.longitude = longitude; @@ -73,6 +84,11 @@ public class GpxTrackPoint extends GPSCoordinate { return this; } + public Builder withHeartRate(final int heartRate) { + this.heartRate = heartRate; + return this; + } + public GpxTrackPoint build() { return new GpxTrackPoint(longitude, latitude, altitude, time); }