mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-10-31 06:32:54 +01:00
Huawei: more details for swim workout
This commit is contained in:
parent
3294e20242
commit
a46e970f84
@ -54,7 +54,7 @@ public class GBDaoGenerator {
|
|||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
final Schema schema = new Schema(84, MAIN_PACKAGE + ".entities");
|
final Schema schema = new Schema(85, MAIN_PACKAGE + ".entities");
|
||||||
|
|
||||||
Entity userAttributes = addUserAttributes(schema);
|
Entity userAttributes = addUserAttributes(schema);
|
||||||
Entity user = addUserInfo(schema, userAttributes);
|
Entity user = addUserInfo(schema, userAttributes);
|
||||||
@ -151,6 +151,7 @@ public class GBDaoGenerator {
|
|||||||
Entity huaweiWorkoutSummary = addHuaweiWorkoutSummarySample(schema, user, device);
|
Entity huaweiWorkoutSummary = addHuaweiWorkoutSummarySample(schema, user, device);
|
||||||
addHuaweiWorkoutDataSample(schema, huaweiWorkoutSummary);
|
addHuaweiWorkoutDataSample(schema, huaweiWorkoutSummary);
|
||||||
addHuaweiWorkoutPaceSample(schema, huaweiWorkoutSummary);
|
addHuaweiWorkoutPaceSample(schema, huaweiWorkoutSummary);
|
||||||
|
addHuaweiWorkoutSwimSegmentsSample(schema, huaweiWorkoutSummary);
|
||||||
|
|
||||||
addCalendarSyncState(schema, device);
|
addCalendarSyncState(schema, device);
|
||||||
addAlarms(schema, user, device);
|
addAlarms(schema, user, device);
|
||||||
@ -1387,6 +1388,8 @@ public class GBDaoGenerator {
|
|||||||
|
|
||||||
workoutSummary.addByteArrayProperty("recoveryHeartRates");
|
workoutSummary.addByteArrayProperty("recoveryHeartRates");
|
||||||
|
|
||||||
|
workoutSummary.addByteProperty("swimType").notNull();
|
||||||
|
|
||||||
return workoutSummary;
|
return workoutSummary;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1443,6 +1446,28 @@ public class GBDaoGenerator {
|
|||||||
return workoutPaceSample;
|
return workoutPaceSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Entity addHuaweiWorkoutSwimSegmentsSample(Schema schema, Entity summaryEntity) {
|
||||||
|
Entity workoutSwimSegmentsSample = addEntity(schema, "HuaweiWorkoutSwimSegmentsSample");
|
||||||
|
|
||||||
|
workoutSwimSegmentsSample.setJavaDoc("Contains Huawei Workout swim segments data samples");
|
||||||
|
|
||||||
|
Property id = workoutSwimSegmentsSample.addLongProperty("workoutId").primaryKey().notNull().getProperty();
|
||||||
|
workoutSwimSegmentsSample.addToOne(summaryEntity, id);
|
||||||
|
|
||||||
|
workoutSwimSegmentsSample.addIntProperty("segmentIndex").notNull().primaryKey();
|
||||||
|
workoutSwimSegmentsSample.addIntProperty("distance").notNull().primaryKey();
|
||||||
|
workoutSwimSegmentsSample.addByteProperty("type").notNull().primaryKey();
|
||||||
|
workoutSwimSegmentsSample.addIntProperty("pace").notNull();
|
||||||
|
workoutSwimSegmentsSample.addIntProperty("pointIndex").notNull();
|
||||||
|
workoutSwimSegmentsSample.addIntProperty("segment").notNull();
|
||||||
|
workoutSwimSegmentsSample.addByteProperty("swimType").notNull();
|
||||||
|
workoutSwimSegmentsSample.addIntProperty("strokes").notNull();
|
||||||
|
workoutSwimSegmentsSample.addIntProperty("avgSwolf").notNull();
|
||||||
|
workoutSwimSegmentsSample.addIntProperty("time").notNull();
|
||||||
|
|
||||||
|
return workoutSwimSegmentsSample;
|
||||||
|
}
|
||||||
|
|
||||||
private static void addTemperatureProperties(Entity activitySample) {
|
private static void addTemperatureProperties(Entity activitySample) {
|
||||||
activitySample.addFloatProperty(SAMPLE_TEMPERATURE).notNull().codeBeforeGetter(OVERRIDE);
|
activitySample.addFloatProperty(SAMPLE_TEMPERATURE).notNull().codeBeforeGetter(OVERRIDE);
|
||||||
activitySample.addIntProperty(SAMPLE_TEMPERATURE_TYPE).notNull().codeBeforeGetter(OVERRIDE);
|
activitySample.addIntProperty(SAMPLE_TEMPERATURE_TYPE).notNull().codeBeforeGetter(OVERRIDE);
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.database.schema;
|
||||||
|
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
||||||
|
|
||||||
|
public class GadgetbridgeUpdate_85 implements DBUpdateScript {
|
||||||
|
@Override
|
||||||
|
public void upgradeSchema(final SQLiteDatabase db) {
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.SwimType.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutSummarySampleDao.Properties.SwimType.columnName + "\" INTEGER NOT NULL DEFAULT -1;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void downgradeSchema(final SQLiteDatabase db) {
|
||||||
|
}
|
||||||
|
}
|
@ -50,6 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSampleDao;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSwimSegmentsSampleDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
@ -124,6 +125,10 @@ public class HuaweiCoordinator {
|
|||||||
session.getHuaweiWorkoutPaceSampleDao().queryBuilder().where(
|
session.getHuaweiWorkoutPaceSampleDao().queryBuilder().where(
|
||||||
HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.eq(sample.getWorkoutId())
|
HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.eq(sample.getWorkoutId())
|
||||||
).buildDelete().executeDeleteWithoutDetachingEntities();
|
).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||||
|
|
||||||
|
session.getHuaweiWorkoutSwimSegmentsSampleDao().queryBuilder().where(
|
||||||
|
HuaweiWorkoutSwimSegmentsSampleDao.Properties.WorkoutId.eq(sample.getWorkoutId())
|
||||||
|
).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
session.getHuaweiWorkoutSummarySampleDao().queryBuilder().where(HuaweiWorkoutSummarySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
session.getHuaweiWorkoutSummarySampleDao().queryBuilder().where(HuaweiWorkoutSummarySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||||
|
@ -570,6 +570,8 @@ public class HuaweiPacket {
|
|||||||
return new Workout.WorkoutData.Response(paramsProvider).fromPacket(this);
|
return new Workout.WorkoutData.Response(paramsProvider).fromPacket(this);
|
||||||
case Workout.WorkoutPace.id:
|
case Workout.WorkoutPace.id:
|
||||||
return new Workout.WorkoutPace.Response(paramsProvider).fromPacket(this);
|
return new Workout.WorkoutPace.Response(paramsProvider).fromPacket(this);
|
||||||
|
case Workout.WorkoutSwimSegments.id:
|
||||||
|
return new Workout.WorkoutSwimSegments.Response(paramsProvider).fromPacket(this);
|
||||||
default:
|
default:
|
||||||
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
||||||
return this;
|
return this;
|
||||||
|
@ -58,6 +58,8 @@ public class Workout {
|
|||||||
public short workoutNumber;
|
public short workoutNumber;
|
||||||
public short dataCount;
|
public short dataCount;
|
||||||
public short paceCount;
|
public short paceCount;
|
||||||
|
public short segmentsCount = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public short count;
|
public short count;
|
||||||
@ -84,6 +86,9 @@ public class Workout {
|
|||||||
workoutNumber.workoutNumber = subContainerTlv.getShort(0x06);
|
workoutNumber.workoutNumber = subContainerTlv.getShort(0x06);
|
||||||
workoutNumber.dataCount = subContainerTlv.getShort(0x07);
|
workoutNumber.dataCount = subContainerTlv.getShort(0x07);
|
||||||
workoutNumber.paceCount = subContainerTlv.getShort(0x08);
|
workoutNumber.paceCount = subContainerTlv.getShort(0x08);
|
||||||
|
if(subContainerTlv.contains(0x09)) {
|
||||||
|
workoutNumber.segmentsCount = subContainerTlv.getShort(0x09);
|
||||||
|
}
|
||||||
this.workoutNumbers.add(workoutNumber);
|
this.workoutNumbers.add(workoutNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,6 +148,8 @@ public class Workout {
|
|||||||
|
|
||||||
public byte[] recoveryHeartRates = null;
|
public byte[] recoveryHeartRates = null;
|
||||||
|
|
||||||
|
public byte swimType = -1;
|
||||||
|
|
||||||
|
|
||||||
public Response(ParamsProvider paramsProvider) {
|
public Response(ParamsProvider paramsProvider) {
|
||||||
super(paramsProvider);
|
super(paramsProvider);
|
||||||
@ -184,7 +191,8 @@ public class Workout {
|
|||||||
this.duration = container.getInteger(0x12);
|
this.duration = container.getInteger(0x12);
|
||||||
if (container.contains(0x14))
|
if (container.contains(0x14))
|
||||||
this.type = container.getByte(0x14);
|
this.type = container.getByte(0x14);
|
||||||
// TODO: I'm guessing 0x15 is Main style for swimming, but cannot confirm.
|
if (container.contains(0x15))
|
||||||
|
this.swimType = container.getByte(0x15);
|
||||||
if (container.contains(0x16))
|
if (container.contains(0x16))
|
||||||
this.strokes = container.getShort(0x16);
|
this.strokes = container.getShort(0x16);
|
||||||
if (container.contains(0x17))
|
if (container.contains(0x17))
|
||||||
@ -565,6 +573,100 @@ public class Workout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class WorkoutSwimSegments {
|
||||||
|
public static final int id = 0x0e;
|
||||||
|
|
||||||
|
public static class Request extends HuaweiPacket {
|
||||||
|
|
||||||
|
public Request(
|
||||||
|
ParamsProvider paramsProvider,
|
||||||
|
short workoutNumber,
|
||||||
|
short segmentNumber
|
||||||
|
) {
|
||||||
|
super(paramsProvider);
|
||||||
|
|
||||||
|
this.serviceId = Workout.id;
|
||||||
|
this.commandId = id;
|
||||||
|
|
||||||
|
this.tlv = new HuaweiTLV().put(0x81, new HuaweiTLV()
|
||||||
|
.put(0x02, workoutNumber)
|
||||||
|
.put(0x08, segmentNumber)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends HuaweiPacket {
|
||||||
|
public static class Block {
|
||||||
|
public short distance = -1;
|
||||||
|
public byte type = -1;
|
||||||
|
public int pace = -1;
|
||||||
|
public short pointIndex = 0;
|
||||||
|
public short segment = -1;
|
||||||
|
public byte swimType= -1;
|
||||||
|
public short strokes = -1;
|
||||||
|
public short avgSwolf = -1;
|
||||||
|
public int time= -1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuffer sb = new StringBuffer("Block{");
|
||||||
|
sb.append("distance=").append(distance);
|
||||||
|
sb.append(", type=").append(type);
|
||||||
|
sb.append(", pace=").append(pace);
|
||||||
|
sb.append(", pointIndex=").append(pointIndex);
|
||||||
|
sb.append(", segment=").append(segment);
|
||||||
|
sb.append(", swimType=").append(swimType);
|
||||||
|
sb.append(", strokes=").append(strokes);
|
||||||
|
sb.append(", awgSwolf=").append(avgSwolf);
|
||||||
|
sb.append(", time=").append(time);
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public short workoutNumber;
|
||||||
|
public short segmentNumber;
|
||||||
|
public List<Block> blocks;
|
||||||
|
|
||||||
|
public Response(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws ParseException {
|
||||||
|
HuaweiTLV container = this.tlv.getObject(0x81);
|
||||||
|
|
||||||
|
this.workoutNumber = container.getShort(0x02);
|
||||||
|
this.segmentNumber = container.getShort(0x08);
|
||||||
|
|
||||||
|
this.blocks = new ArrayList<>();
|
||||||
|
for (HuaweiTLV blockTlv : container.getObjects(0x83)) {
|
||||||
|
Block block = new Block();
|
||||||
|
|
||||||
|
block.distance = blockTlv.getShort(0x04);
|
||||||
|
block.type = blockTlv.getByte(0x05);
|
||||||
|
block.pace = blockTlv.getInteger(0x06);
|
||||||
|
if (blockTlv.contains(0x07))
|
||||||
|
block.pointIndex = blockTlv.getShort(0x07);
|
||||||
|
if (blockTlv.contains(0x09))
|
||||||
|
block.segment = blockTlv.getShort(0x09);
|
||||||
|
if (blockTlv.contains(0x0a))
|
||||||
|
block.swimType= blockTlv.getByte(0x0a);
|
||||||
|
if (blockTlv.contains(0x0b))
|
||||||
|
block.strokes = blockTlv.getShort(0x0b);
|
||||||
|
if (blockTlv.contains(0x0c))
|
||||||
|
block.avgSwolf = blockTlv.getShort(0x0c);
|
||||||
|
if (blockTlv.contains(0x0d))
|
||||||
|
block.time= blockTlv.getInteger(0x0d);
|
||||||
|
|
||||||
|
blocks.add(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class NotifyHeartRate {
|
public static class NotifyHeartRate {
|
||||||
public static final int id = 0x17;
|
public static final int id = 0x17;
|
||||||
|
|
||||||
|
@ -74,6 +74,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSample;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSwimSegmentsSample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSwimSegmentsSampleDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.export.ActivityTrackExporter;
|
import nodomain.freeyourgadget.gadgetbridge.export.ActivityTrackExporter;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.export.GPXExporter;
|
import nodomain.freeyourgadget.gadgetbridge.export.GPXExporter;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProviderType;
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProviderType;
|
||||||
@ -1646,7 +1648,8 @@ public class HuaweiSupportProvider {
|
|||||||
packet.recoveryTime,
|
packet.recoveryTime,
|
||||||
packet.minHeartRatePeak,
|
packet.minHeartRatePeak,
|
||||||
packet.maxHeartRatePeak,
|
packet.maxHeartRatePeak,
|
||||||
recoveryHeartRates
|
recoveryHeartRates,
|
||||||
|
packet.swimType
|
||||||
);
|
);
|
||||||
db.getDaoSession().getHuaweiWorkoutSummarySampleDao().insertOrReplace(summarySample);
|
db.getDaoSession().getHuaweiWorkoutSummarySampleDao().insertOrReplace(summarySample);
|
||||||
|
|
||||||
@ -1735,6 +1738,44 @@ public class HuaweiSupportProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void addWorkoutSwimSegmentsData(Long workoutId, List<Workout.WorkoutSwimSegments.Response.Block> paceList, short number) {
|
||||||
|
if (workoutId == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try (DBHandler db = GBApplication.acquireDB()) {
|
||||||
|
HuaweiWorkoutSwimSegmentsSampleDao dao = db.getDaoSession().getHuaweiWorkoutSwimSegmentsSampleDao();
|
||||||
|
|
||||||
|
if(number == 0) {
|
||||||
|
final DeleteQuery<HuaweiWorkoutSwimSegmentsSample> tableDeleteQuery = dao.queryBuilder()
|
||||||
|
.where(HuaweiWorkoutSwimSegmentsSampleDao.Properties.WorkoutId.eq(workoutId))
|
||||||
|
.buildDelete();
|
||||||
|
tableDeleteQuery.executeDeleteWithoutDetachingEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
int paceIndex = (int) dao.queryBuilder().where(HuaweiWorkoutSwimSegmentsSampleDao.Properties.WorkoutId.eq(workoutId)).count();
|
||||||
|
for (Workout.WorkoutSwimSegments.Response.Block block : paceList) {
|
||||||
|
HuaweiWorkoutSwimSegmentsSample swimSectionSample = new HuaweiWorkoutSwimSegmentsSample(
|
||||||
|
workoutId,
|
||||||
|
paceIndex++,
|
||||||
|
block.distance,
|
||||||
|
block.type,
|
||||||
|
block.pace,
|
||||||
|
block.pointIndex,
|
||||||
|
block.segment,
|
||||||
|
block.swimType,
|
||||||
|
block.strokes,
|
||||||
|
block.avgSwolf,
|
||||||
|
block.time
|
||||||
|
);
|
||||||
|
dao.insertOrReplace(swimSectionSample);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Failed to add workout swim section data to database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setWearLocation() {
|
public void setWearLocation() {
|
||||||
try {
|
try {
|
||||||
SetWearLocationRequest setWearLocationReq = new SetWearLocationRequest(this);
|
SetWearLocationRequest setWearLocationReq = new SetWearLocationRequest(this);
|
||||||
|
@ -22,9 +22,9 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -50,6 +50,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSample;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSwimSegmentsSample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSwimSegmentsSampleDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||||
@ -310,6 +312,20 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
|||||||
return ActivityKind.UNKNOWN;
|
return ActivityKind.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getSwimStyle(byte swimType) {
|
||||||
|
switch (swimType) {
|
||||||
|
case 1:
|
||||||
|
return "breaststroke";
|
||||||
|
case 3:
|
||||||
|
return "butterfly";
|
||||||
|
case 4:
|
||||||
|
return "backstroke";
|
||||||
|
case 5:
|
||||||
|
return "medley";
|
||||||
|
}
|
||||||
|
return "freestyle";
|
||||||
|
}
|
||||||
|
|
||||||
public void parseWorkout(Long workoutId) {
|
public void parseWorkout(Long workoutId) {
|
||||||
LOG.debug("Parsing workout ID {}", workoutId);
|
LOG.debug("Parsing workout ID {}", workoutId);
|
||||||
if (workoutId == null)
|
if (workoutId == null)
|
||||||
@ -361,6 +377,10 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
|||||||
HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.eq(summary.getWorkoutId())
|
HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.eq(summary.getWorkoutId())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
QueryBuilder<HuaweiWorkoutSwimSegmentsSample> qbSegments = session.getHuaweiWorkoutSwimSegmentsSampleDao().queryBuilder().orderAsc(HuaweiWorkoutSwimSegmentsSampleDao.Properties.SegmentIndex).where(
|
||||||
|
HuaweiWorkoutSwimSegmentsSampleDao.Properties.WorkoutId.eq(summary.getWorkoutId())
|
||||||
|
);
|
||||||
|
|
||||||
ActivityKind type = huaweiTypeToGbType(summary.getType());
|
ActivityKind type = huaweiTypeToGbType(summary.getType());
|
||||||
|
|
||||||
ActivitySummaryData summaryData = new ActivitySummaryData();
|
ActivitySummaryData summaryData = new ActivitySummaryData();
|
||||||
@ -376,11 +396,6 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
|||||||
summaryData.add(ActivitySummaryEntries.STROKES, summary.getStrokes(), ActivitySummaryEntries.UNIT_STROKES);
|
summaryData.add(ActivitySummaryEntries.STROKES, summary.getStrokes(), ActivitySummaryEntries.UNIT_STROKES);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (summary.getAvgStrokeRate() != -1) {
|
|
||||||
// TODO: find out unit
|
|
||||||
summaryData.add(ActivitySummaryEntries.STROKE_RATE_AVG, summary.getAvgStrokeRate(), ActivitySummaryEntries.UNIT_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (summary.getPoolLength() != -1) {
|
if (summary.getPoolLength() != -1) {
|
||||||
summaryData.add(ActivitySummaryEntries.LANE_LENGTH, summary.getPoolLength(), ActivitySummaryEntries.UNIT_CM);
|
summaryData.add(ActivitySummaryEntries.LANE_LENGTH, summary.getPoolLength(), ActivitySummaryEntries.UNIT_CM);
|
||||||
}
|
}
|
||||||
@ -389,10 +404,6 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
|||||||
summaryData.add(ActivitySummaryEntries.LAPS, summary.getLaps(), ActivitySummaryEntries.UNIT_LAPS);
|
summaryData.add(ActivitySummaryEntries.LAPS, summary.getLaps(), ActivitySummaryEntries.UNIT_LAPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (summary.getAvgSwolf() != -1) {
|
|
||||||
summaryData.add(ActivitySummaryEntries.SWOLF_AVG, summary.getAvgSwolf(), ActivitySummaryEntries.UNIT_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(summary.getWorkoutLoad() > 0) {
|
if(summary.getWorkoutLoad() > 0) {
|
||||||
summaryData.add(ActivitySummaryEntries.WORKOUT_LOAD, summary.getWorkoutLoad(), ActivitySummaryEntries.UNIT_NONE);
|
summaryData.add(ActivitySummaryEntries.WORKOUT_LOAD, summary.getWorkoutLoad(), ActivitySummaryEntries.UNIT_NONE);
|
||||||
}
|
}
|
||||||
@ -409,6 +420,10 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
|||||||
summaryData.add(ActivitySummaryEntries.RECOVERY_TIME, summary.getRecoveryTime() / 60.0, ActivitySummaryEntries.UNIT_HOURS);
|
summaryData.add(ActivitySummaryEntries.RECOVERY_TIME, summary.getRecoveryTime() / 60.0, ActivitySummaryEntries.UNIT_HOURS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(summary.getSwimType() != -1) {
|
||||||
|
summaryData.add(ActivitySummaryEntries.SWIM_STYLE, getSwimStyle(summary.getSwimType()));
|
||||||
|
}
|
||||||
|
|
||||||
Integer summaryMinAltitude = summary.getMinAltitude();
|
Integer summaryMinAltitude = summary.getMinAltitude();
|
||||||
Integer summaryMaxAltitude = summary.getMaxAltitude();
|
Integer summaryMaxAltitude = summary.getMaxAltitude();
|
||||||
Integer elevationGain = summary.getElevationGain();
|
Integer elevationGain = summary.getElevationGain();
|
||||||
@ -417,6 +432,10 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
|||||||
int minHeartRatePeak = summary.getMinHeartRatePeak() & 0xff;
|
int minHeartRatePeak = summary.getMinHeartRatePeak() & 0xff;
|
||||||
int maxHeartRatePeak = summary.getMaxHeartRatePeak() & 0xff;
|
int maxHeartRatePeak = summary.getMaxHeartRatePeak() & 0xff;
|
||||||
|
|
||||||
|
int avgStrokeRate = summary.getAvgStrokeRate();
|
||||||
|
|
||||||
|
int avgSwolf = summary.getAvgSwolf();
|
||||||
|
|
||||||
boolean unknownData = false;
|
boolean unknownData = false;
|
||||||
if (!dataSamples.isEmpty()) {
|
if (!dataSamples.isEmpty()) {
|
||||||
int speed = 0;
|
int speed = 0;
|
||||||
@ -640,12 +659,17 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (swolfCount > 0) {
|
if (swolfCount > 0) {
|
||||||
summaryData.add(ActivitySummaryEntries.SWOLF_AVG, swolf, ActivitySummaryEntries.UNIT_NONE);
|
if(avgSwolf == -1) {
|
||||||
|
avgSwolf = swolf;
|
||||||
|
}
|
||||||
summaryData.add(ActivitySummaryEntries.SWOLF_MAX, maxSwolf, ActivitySummaryEntries.UNIT_NONE);
|
summaryData.add(ActivitySummaryEntries.SWOLF_MAX, maxSwolf, ActivitySummaryEntries.UNIT_NONE);
|
||||||
summaryData.add(ActivitySummaryEntries.SWOLF_MIN, minSwolf, ActivitySummaryEntries.UNIT_NONE);
|
summaryData.add(ActivitySummaryEntries.SWOLF_MIN, minSwolf, ActivitySummaryEntries.UNIT_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strokeRateCount > 0) {
|
if (strokeRateCount > 0) {
|
||||||
|
if(avgStrokeRate == -1) {
|
||||||
|
avgStrokeRate = strokeRate;
|
||||||
|
}
|
||||||
// TODO: find out unit?
|
// TODO: find out unit?
|
||||||
summaryData.add(ActivitySummaryEntries.STROKE_RATE_AVG, strokeRate, ActivitySummaryEntries.UNIT_NONE);
|
summaryData.add(ActivitySummaryEntries.STROKE_RATE_AVG, strokeRate, ActivitySummaryEntries.UNIT_NONE);
|
||||||
|
|
||||||
@ -695,6 +719,14 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(avgSwolf > 0) {
|
||||||
|
summaryData.add(ActivitySummaryEntries.SWOLF_AVG, avgSwolf, ActivitySummaryEntries.UNIT_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avgStrokeRate > 0) {
|
||||||
|
summaryData.add(ActivitySummaryEntries.STROKE_RATE_AVG, avgStrokeRate, ActivitySummaryEntries.UNIT_STROKES_PER_MINUTE);
|
||||||
|
}
|
||||||
|
|
||||||
if (minHeartRatePeak > 0) {
|
if (minHeartRatePeak > 0) {
|
||||||
summaryData.add(ActivitySummaryEntries.HR_MIN, minHeartRatePeak, ActivitySummaryEntries.UNIT_BPM);
|
summaryData.add(ActivitySummaryEntries.HR_MIN, minHeartRatePeak, ActivitySummaryEntries.UNIT_BPM);
|
||||||
}
|
}
|
||||||
@ -816,6 +848,69 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final LinkedHashMap<String, ActivitySummaryTableRowEntry> segmentsTable = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
try (CloseableListIterator<HuaweiWorkoutSwimSegmentsSample> it = qbSegments.build().listIterator()) {
|
||||||
|
|
||||||
|
int currentIndex = 1;
|
||||||
|
int tableIndex = 1;
|
||||||
|
while (it.hasNext()) {
|
||||||
|
HuaweiWorkoutSwimSegmentsSample sample = it.next();
|
||||||
|
|
||||||
|
if (sample.getType() != unitType)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
final List<ActivitySummaryValue> columns = new LinkedList<>();
|
||||||
|
// TODO: add proper units for type == 1. MILES
|
||||||
|
columns.add(new ActivitySummaryValue(currentIndex++, ActivitySummaryEntries.UNIT_NONE));
|
||||||
|
columns.add(new ActivitySummaryValue(getSwimStyle(sample.getSwimType()), ActivitySummaryEntries.UNIT_NONE));
|
||||||
|
columns.add(new ActivitySummaryValue(sample.getDistance(), ActivitySummaryEntries.UNIT_METERS));
|
||||||
|
columns.add(new ActivitySummaryValue(sample.getTime(), ActivitySummaryEntries.UNIT_SECONDS));
|
||||||
|
|
||||||
|
|
||||||
|
segmentsTable.put("segments_table_" + tableIndex++,
|
||||||
|
new ActivitySummaryTableRowEntry(
|
||||||
|
ActivitySummaryEntries.GROUP_PACE,
|
||||||
|
columns,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<ActivitySummaryValue> columns2 = new LinkedList<>();
|
||||||
|
// TODO: add proper units for type == 1. MILES and SECONDS PER MILE
|
||||||
|
columns2.add(new ActivitySummaryValue("", ActivitySummaryEntries.UNIT_NONE));
|
||||||
|
columns2.add(new ActivitySummaryValue(sample.getStrokes(), ActivitySummaryEntries.UNIT_STROKES));
|
||||||
|
columns2.add(new ActivitySummaryValue(sample.getAvgSwolf(), ActivitySummaryEntries.UNIT_NONE));
|
||||||
|
columns2.add(new ActivitySummaryValue(sample.getPace(), ActivitySummaryEntries.UNIT_NONE)); //TODO: seconds / 100 meters
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
segmentsTable.put("segments_table_" + tableIndex++,
|
||||||
|
new ActivitySummaryTableRowEntry(
|
||||||
|
ActivitySummaryEntries.GROUP_PACE,
|
||||||
|
columns2,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
segmentsTable.put("segments_table_" + tableIndex++,
|
||||||
|
new ActivitySummaryTableRowEntry(
|
||||||
|
ActivitySummaryEntries.GROUP_PACE,
|
||||||
|
new ArrayList<>(),
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!segmentsTable.isEmpty()) {
|
||||||
|
for (final Map.Entry<String, ActivitySummaryTableRowEntry> e : segmentsTable.entrySet()) {
|
||||||
|
summaryData.add(e.getKey(), e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (unknownData) {
|
if (unknownData) {
|
||||||
summaryData.add(
|
summaryData.add(
|
||||||
GBApplication.getContext().getString(R.string.unknownDataEncountered),
|
GBApplication.getContext().getString(R.string.unknownDataEncountered),
|
||||||
|
@ -112,6 +112,16 @@ public class GetWorkoutDataRequest extends Request {
|
|||||||
);
|
);
|
||||||
nextRequest.setFinalizeReq(this.finalizeReq);
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
this.nextRequest(nextRequest);
|
this.nextRequest(nextRequest);
|
||||||
|
} else if (this.workoutNumbers.segmentsCount > 0) {
|
||||||
|
GetWorkoutSwimSegmentsRequest nextRequest = new GetWorkoutSwimSegmentsRequest(
|
||||||
|
this.supportProvider,
|
||||||
|
this.workoutNumbers,
|
||||||
|
this.remainder,
|
||||||
|
(short) 0,
|
||||||
|
this.databaseId
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
|
this.nextRequest(nextRequest);
|
||||||
} else {
|
} else {
|
||||||
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(this.databaseId);
|
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(this.databaseId);
|
||||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
||||||
|
@ -89,7 +89,17 @@ public class GetWorkoutPaceRequest extends Request {
|
|||||||
);
|
);
|
||||||
nextRequest.setFinalizeReq(this.finalizeReq);
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
this.nextRequest(nextRequest);
|
this.nextRequest(nextRequest);
|
||||||
} else {
|
} else if (this.workoutNumbers.segmentsCount > 0) {
|
||||||
|
GetWorkoutSwimSegmentsRequest nextRequest = new GetWorkoutSwimSegmentsRequest(
|
||||||
|
this.supportProvider,
|
||||||
|
this.workoutNumbers,
|
||||||
|
this.remainder,
|
||||||
|
(short) 0,
|
||||||
|
this.databaseId
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
|
this.nextRequest(nextRequest);
|
||||||
|
} else {
|
||||||
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(this.databaseId);
|
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(this.databaseId);
|
||||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Workout;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiWorkoutGbParser;
|
||||||
|
|
||||||
|
public class GetWorkoutSwimSegmentsRequest extends Request {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GetWorkoutSwimSegmentsRequest.class);
|
||||||
|
|
||||||
|
Workout.WorkoutCount.Response.WorkoutNumbers workoutNumbers;
|
||||||
|
List<Workout.WorkoutCount.Response.WorkoutNumbers> remainder;
|
||||||
|
short number;
|
||||||
|
Long databaseId;
|
||||||
|
|
||||||
|
public GetWorkoutSwimSegmentsRequest(HuaweiSupportProvider support, Workout.WorkoutCount.Response.WorkoutNumbers workoutNumbers, List<Workout.WorkoutCount.Response.WorkoutNumbers> remainder, short number, Long databaseId) {
|
||||||
|
super(support);
|
||||||
|
|
||||||
|
this.serviceId = Workout.id;
|
||||||
|
this.commandId = Workout.WorkoutSwimSegments.id;
|
||||||
|
|
||||||
|
this.workoutNumbers = workoutNumbers;
|
||||||
|
this.remainder = remainder;
|
||||||
|
this.number = number;
|
||||||
|
|
||||||
|
this.databaseId = databaseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new Workout.WorkoutSwimSegments.Request(paramsProvider,this.workoutNumbers.workoutNumber, this.number).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processResponse() throws ResponseParseException {
|
||||||
|
if (!(receivedPacket instanceof Workout.WorkoutSwimSegments.Response))
|
||||||
|
throw new ResponseTypeMismatchException(receivedPacket, Workout.WorkoutSwimSegments.Response.class);
|
||||||
|
|
||||||
|
Workout.WorkoutSwimSegments.Response packet = (Workout.WorkoutSwimSegments.Response) receivedPacket;
|
||||||
|
|
||||||
|
if (packet.workoutNumber != this.workoutNumbers.workoutNumber)
|
||||||
|
throw new WorkoutParseException("Incorrect workout number!");
|
||||||
|
|
||||||
|
if (packet.segmentNumber != this.number)
|
||||||
|
throw new WorkoutParseException("Incorrect pace number!");
|
||||||
|
|
||||||
|
LOG.info("Workout {} segment {}:", this.workoutNumbers.workoutNumber, this.number);
|
||||||
|
LOG.info("Workout : " + packet.workoutNumber);
|
||||||
|
LOG.info("Segments : " + packet.segmentNumber);
|
||||||
|
LOG.info("Block num: " + packet.blocks.size());
|
||||||
|
LOG.info("Blocks : " + Arrays.toString(packet.blocks.toArray()));
|
||||||
|
|
||||||
|
supportProvider.addWorkoutSwimSegmentsData(this.databaseId, packet.blocks, packet.segmentNumber);
|
||||||
|
|
||||||
|
if (this.workoutNumbers.segmentsCount > this.number + 1) {
|
||||||
|
GetWorkoutSwimSegmentsRequest nextRequest = new GetWorkoutSwimSegmentsRequest(
|
||||||
|
this.supportProvider,
|
||||||
|
this.workoutNumbers,
|
||||||
|
this.remainder,
|
||||||
|
(short) (this.number + 1),
|
||||||
|
this.databaseId
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
|
this.nextRequest(nextRequest);
|
||||||
|
} else {
|
||||||
|
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(this.databaseId);
|
||||||
|
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!remainder.isEmpty()) {
|
||||||
|
GetWorkoutTotalsRequest nextRequest = new GetWorkoutTotalsRequest(
|
||||||
|
GetWorkoutSwimSegmentsRequest.this.supportProvider,
|
||||||
|
remainder.remove(0),
|
||||||
|
remainder
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(GetWorkoutSwimSegmentsRequest.this.finalizeReq);
|
||||||
|
// Cannot do this with nextRequest because it's in a callback
|
||||||
|
try {
|
||||||
|
nextRequest.doPerform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
finalizeReq.handleException(new ResponseParseException("Cannot send next request", e));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
supportProvider.endOfWorkoutSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -103,7 +103,17 @@ public class GetWorkoutTotalsRequest extends Request {
|
|||||||
);
|
);
|
||||||
nextRequest.setFinalizeReq(this.finalizeReq);
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
this.nextRequest(nextRequest);
|
this.nextRequest(nextRequest);
|
||||||
} else {
|
} else if (this.workoutNumbers.segmentsCount > 0) {
|
||||||
|
GetWorkoutSwimSegmentsRequest nextRequest = new GetWorkoutSwimSegmentsRequest(
|
||||||
|
this.supportProvider,
|
||||||
|
this.workoutNumbers,
|
||||||
|
this.remainder,
|
||||||
|
(short) 0,
|
||||||
|
databaseId
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
|
this.nextRequest(nextRequest);
|
||||||
|
} else {
|
||||||
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(databaseId);
|
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(databaseId);
|
||||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, databaseId, new Runnable() {
|
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, databaseId, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user