diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/XiaomiActivityFileId.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/XiaomiActivityFileId.java index c13cb20a7..1b797fcc4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/XiaomiActivityFileId.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/XiaomiActivityFileId.java @@ -198,7 +198,7 @@ public class XiaomiActivityFileId implements Comparable { SPORTS_OUTDOOR_RUNNING(Type.SPORTS, 0x01), SPORTS_OUTDOOR_WALKING_V1(Type.SPORTS, 0x02), SPORTS_TREADMILL(Type.SPORTS, 0x03), - SPORTS_OUTDOOR_CYCLING_V2(Type.SPORTS, 0x06), // TODO + SPORTS_OUTDOOR_CYCLING_V2(Type.SPORTS, 0x06), SPORTS_INDOOR_CYCLING(Type.SPORTS, 0x07), SPORTS_FREESTYLE(Type.SPORTS, 0x08), SPORTS_POOL_SWIMMING(Type.SPORTS, 0x09), diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/impl/WorkoutGpsParser.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/impl/WorkoutGpsParser.java index 08162b2e9..705799c20 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/impl/WorkoutGpsParser.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/impl/WorkoutGpsParser.java @@ -58,6 +58,9 @@ public class WorkoutGpsParser extends XiaomiActivityParser { final int sampleSize; switch (version) { case 1: + headerSize = 1; + sampleSize = 12; + break; case 2: headerSize = 1; sampleSize = 18; @@ -85,21 +88,34 @@ public class WorkoutGpsParser extends XiaomiActivityParser { final ActivityTrack activityTrack = new ActivityTrack(); - while (buf.position() < buf.limit()) { - final int ts = buf.getInt(); - final float longitude = buf.getFloat(); - final float latitude = buf.getFloat(); - final int unk1 = buf.getInt(); // 0 - final float speed = (buf.getShort() >> 2) / 10.0f; + // GPS V1 contains no speed data, therefore second while loop to avoid too many ifs within the loop + if (version == 1) { + while (buf.position() < buf.limit()) { + final int ts = buf.getInt(); + final float longitude = buf.getFloat(); + final float latitude = buf.getFloat(); - final ActivityPoint ap = new ActivityPoint(new Date(ts * 1000L)); - ap.setLocation(new GPSCoordinate(longitude, latitude, 0)); - activityTrack.addTrackPoint(ap); + final ActivityPoint ap = new ActivityPoint(new Date(ts * 1000L)); + ap.setLocation(new GPSCoordinate(longitude, latitude, 0)); + activityTrack.addTrackPoint(ap); + LOG.trace("ActivityPoint V1: ts={} lon={} lat={}", ts, longitude, latitude); + } + } else { + while (buf.position() < buf.limit()) { + final int ts = buf.getInt(); + final float longitude = buf.getFloat(); + final float latitude = buf.getFloat(); + final int unk1 = buf.getInt(); // 0 + final float speed = (buf.getShort() >> 2) / 10.0f; - LOG.trace("ActivityPoint: ts={} lon={} lat={} unk1={} speed={}", ts, longitude, latitude, unk1, speed); + final ActivityPoint ap = new ActivityPoint(new Date(ts * 1000L)); + ap.setLocation(new GPSCoordinate(longitude, latitude, 0)); + activityTrack.addTrackPoint(ap); + LOG.trace("ActivityPoint: ts={} lon={} lat={} unk1={} speed={}", ts, longitude, latitude, unk1, speed); + } } - try (DBHandler dbHandler = GBApplication.acquireDB()) { + try (DBHandler dbHandler = GBApplication.acquireDB()) { final DaoSession session = dbHandler.getDaoSession(); final Device device = DBHelper.getDevice(support.getDevice(), session); final User user = DBHelper.getUser(session); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/impl/WorkoutSummaryParser.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/impl/WorkoutSummaryParser.java index f398f4503..2a13cd6b8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/impl/WorkoutSummaryParser.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/impl/WorkoutSummaryParser.java @@ -210,6 +210,10 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi case SPORTS_OUTDOOR_WALKING_V2: parser = getOutdoorWalkingV2Parser(fileId); break; + case SPORTS_OUTDOOR_CYCLING_V2: + summary.setActivityKind(ActivityKind.OUTDOOR_CYCLING.getCode()); + parser = getOutdoorCyclingV2Parser(fileId); + break; case SPORTS_OUTDOOR_CYCLING: parser = getOutdoorCyclingParser(fileId); break; @@ -277,7 +281,10 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi if (version == 5) { builder.addUnknown(10); builder.addShort(XIAOMI_WORKOUT_TYPE, UNIT_NONE); - builder.addUnknown(8); + builder.addUnknown(2); + builder.addUnknown(2); // configuredTimeGoal, UNIT_SECONDS + builder.addUnknown(2); + builder.addUnknown(2); // configuredCaloriesGoal, UNIT_KCAL } else { builder.addUnknown(2); builder.addUnknown(4); @@ -749,4 +756,42 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi return builder.build(); } + + @Nullable + private XiaomiSimpleActivityParser getOutdoorCyclingV2Parser(final XiaomiActivityFileId fileId) { + final int version = fileId.getVersion(); + final int headerSize; + switch (version) { + case 4: + headerSize = 5; + break; + default: + LOG.warn("Unable to parse workout summary version {}", fileId.getVersion()); + return null; + } + + final XiaomiSimpleActivityParser.Builder builder = new XiaomiSimpleActivityParser.Builder(); + builder.setHeaderSize(headerSize); + builder.addInt(TIME_START, UNIT_UNIX_EPOCH_SECONDS); + builder.addInt(TIME_END, UNIT_UNIX_EPOCH_SECONDS); + builder.addInt(ACTIVE_SECONDS, UNIT_SECONDS); + builder.addInt(DISTANCE_METERS, UNIT_METERS); + builder.addShort(CALORIES_BURNT, UNIT_KCAL); + builder.addUnknown(8); + builder.addFloat(SPEED_MAX, UNIT_KMPH); + builder.addByte(HR_AVG, UNIT_BPM); + builder.addByte(HR_MAX, UNIT_BPM); + builder.addByte(HR_MIN, UNIT_BPM); + builder.addUnknown(28); + builder.addInt(HR_ZONE_EXTREME, UNIT_SECONDS); + builder.addInt(HR_ZONE_ANAEROBIC, UNIT_SECONDS); + builder.addInt(HR_ZONE_AEROBIC, UNIT_SECONDS); + builder.addInt(HR_ZONE_FAT_BURN, UNIT_SECONDS); + builder.addInt(HR_ZONE_WARM_UP, UNIT_SECONDS); + builder.addUnknown(18); + builder.addUnknown(2); // configuredTimeGoal, UNIT_SECONDS + builder.addUnknown(6); + + return builder.build(); + } }