mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-30 05:52:57 +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 {
|
||||
final Schema schema = new Schema(84, MAIN_PACKAGE + ".entities");
|
||||
final Schema schema = new Schema(85, MAIN_PACKAGE + ".entities");
|
||||
|
||||
Entity userAttributes = addUserAttributes(schema);
|
||||
Entity user = addUserInfo(schema, userAttributes);
|
||||
@ -151,6 +151,7 @@ public class GBDaoGenerator {
|
||||
Entity huaweiWorkoutSummary = addHuaweiWorkoutSummarySample(schema, user, device);
|
||||
addHuaweiWorkoutDataSample(schema, huaweiWorkoutSummary);
|
||||
addHuaweiWorkoutPaceSample(schema, huaweiWorkoutSummary);
|
||||
addHuaweiWorkoutSwimSegmentsSample(schema, huaweiWorkoutSummary);
|
||||
|
||||
addCalendarSyncState(schema, device);
|
||||
addAlarms(schema, user, device);
|
||||
@ -1387,6 +1388,8 @@ public class GBDaoGenerator {
|
||||
|
||||
workoutSummary.addByteArrayProperty("recoveryHeartRates");
|
||||
|
||||
workoutSummary.addByteProperty("swimType").notNull();
|
||||
|
||||
return workoutSummary;
|
||||
}
|
||||
|
||||
@ -1443,6 +1446,28 @@ public class GBDaoGenerator {
|
||||
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) {
|
||||
activitySample.addFloatProperty(SAMPLE_TEMPERATURE).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.HuaweiWorkoutSummarySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSwimSegmentsSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
@ -124,6 +125,10 @@ public class HuaweiCoordinator {
|
||||
session.getHuaweiWorkoutPaceSampleDao().queryBuilder().where(
|
||||
HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.eq(sample.getWorkoutId())
|
||||
).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();
|
||||
|
@ -570,6 +570,8 @@ public class HuaweiPacket {
|
||||
return new Workout.WorkoutData.Response(paramsProvider).fromPacket(this);
|
||||
case Workout.WorkoutPace.id:
|
||||
return new Workout.WorkoutPace.Response(paramsProvider).fromPacket(this);
|
||||
case Workout.WorkoutSwimSegments.id:
|
||||
return new Workout.WorkoutSwimSegments.Response(paramsProvider).fromPacket(this);
|
||||
default:
|
||||
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
||||
return this;
|
||||
|
@ -58,6 +58,8 @@ public class Workout {
|
||||
public short workoutNumber;
|
||||
public short dataCount;
|
||||
public short paceCount;
|
||||
public short segmentsCount = 0;
|
||||
|
||||
}
|
||||
|
||||
public short count;
|
||||
@ -84,6 +86,9 @@ public class Workout {
|
||||
workoutNumber.workoutNumber = subContainerTlv.getShort(0x06);
|
||||
workoutNumber.dataCount = subContainerTlv.getShort(0x07);
|
||||
workoutNumber.paceCount = subContainerTlv.getShort(0x08);
|
||||
if(subContainerTlv.contains(0x09)) {
|
||||
workoutNumber.segmentsCount = subContainerTlv.getShort(0x09);
|
||||
}
|
||||
this.workoutNumbers.add(workoutNumber);
|
||||
}
|
||||
}
|
||||
@ -143,6 +148,8 @@ public class Workout {
|
||||
|
||||
public byte[] recoveryHeartRates = null;
|
||||
|
||||
public byte swimType = -1;
|
||||
|
||||
|
||||
public Response(ParamsProvider paramsProvider) {
|
||||
super(paramsProvider);
|
||||
@ -184,7 +191,8 @@ public class Workout {
|
||||
this.duration = container.getInteger(0x12);
|
||||
if (container.contains(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))
|
||||
this.strokes = container.getShort(0x16);
|
||||
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 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.HuaweiWorkoutSummarySample;
|
||||
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.GPXExporter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProviderType;
|
||||
@ -1646,7 +1648,8 @@ public class HuaweiSupportProvider {
|
||||
packet.recoveryTime,
|
||||
packet.minHeartRatePeak,
|
||||
packet.maxHeartRatePeak,
|
||||
recoveryHeartRates
|
||||
recoveryHeartRates,
|
||||
packet.swimType
|
||||
);
|
||||
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() {
|
||||
try {
|
||||
SetWearLocationRequest setWearLocationReq = new SetWearLocationRequest(this);
|
||||
|
@ -22,9 +22,9 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
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.HuaweiWorkoutSummarySample;
|
||||
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.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
@ -310,6 +312,20 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
||||
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) {
|
||||
LOG.debug("Parsing workout ID {}", workoutId);
|
||||
if (workoutId == null)
|
||||
@ -361,6 +377,10 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
||||
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());
|
||||
|
||||
ActivitySummaryData summaryData = new ActivitySummaryData();
|
||||
@ -376,11 +396,6 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (summary.getAvgSwolf() != -1) {
|
||||
summaryData.add(ActivitySummaryEntries.SWOLF_AVG, summary.getAvgSwolf(), ActivitySummaryEntries.UNIT_NONE);
|
||||
}
|
||||
|
||||
if(summary.getWorkoutLoad() > 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
if(summary.getSwimType() != -1) {
|
||||
summaryData.add(ActivitySummaryEntries.SWIM_STYLE, getSwimStyle(summary.getSwimType()));
|
||||
}
|
||||
|
||||
Integer summaryMinAltitude = summary.getMinAltitude();
|
||||
Integer summaryMaxAltitude = summary.getMaxAltitude();
|
||||
Integer elevationGain = summary.getElevationGain();
|
||||
@ -417,6 +432,10 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
||||
int minHeartRatePeak = summary.getMinHeartRatePeak() & 0xff;
|
||||
int maxHeartRatePeak = summary.getMaxHeartRatePeak() & 0xff;
|
||||
|
||||
int avgStrokeRate = summary.getAvgStrokeRate();
|
||||
|
||||
int avgSwolf = summary.getAvgSwolf();
|
||||
|
||||
boolean unknownData = false;
|
||||
if (!dataSamples.isEmpty()) {
|
||||
int speed = 0;
|
||||
@ -640,12 +659,17 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
||||
}
|
||||
|
||||
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_MIN, minSwolf, ActivitySummaryEntries.UNIT_NONE);
|
||||
}
|
||||
|
||||
if (strokeRateCount > 0) {
|
||||
if(avgStrokeRate == -1) {
|
||||
avgStrokeRate = strokeRate;
|
||||
}
|
||||
// TODO: find out unit?
|
||||
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) {
|
||||
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) {
|
||||
summaryData.add(
|
||||
GBApplication.getContext().getString(R.string.unknownDataEncountered),
|
||||
|
@ -112,6 +112,16 @@ public class GetWorkoutDataRequest extends Request {
|
||||
);
|
||||
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||
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 {
|
||||
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(this.databaseId);
|
||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
||||
|
@ -89,7 +89,17 @@ public class GetWorkoutPaceRequest extends Request {
|
||||
);
|
||||
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||
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);
|
||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
||||
@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);
|
||||
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);
|
||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, databaseId, new Runnable() {
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user