mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-10 09:01:55 +01:00
Huawei: Sync dict data over P2P. Sync skin temperature.
This commit is contained in:
parent
68caf6a60f
commit
ae84678de8
@ -54,7 +54,7 @@ public class GBDaoGenerator {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final Schema schema = new Schema(85, MAIN_PACKAGE + ".entities");
|
||||
final Schema schema = new Schema(86, MAIN_PACKAGE + ".entities");
|
||||
|
||||
Entity userAttributes = addUserAttributes(schema);
|
||||
Entity user = addUserInfo(schema, userAttributes);
|
||||
@ -153,6 +153,9 @@ public class GBDaoGenerator {
|
||||
addHuaweiWorkoutPaceSample(schema, huaweiWorkoutSummary);
|
||||
addHuaweiWorkoutSwimSegmentsSample(schema, huaweiWorkoutSummary);
|
||||
|
||||
Entity huaweiDictData = addHuaweiDictData(schema, user, device);
|
||||
addHuaweiDictDataValues(schema, huaweiDictData);
|
||||
|
||||
addCalendarSyncState(schema, device);
|
||||
addAlarms(schema, user, device);
|
||||
addReminders(schema, user, device);
|
||||
@ -1468,6 +1471,42 @@ public class GBDaoGenerator {
|
||||
return workoutSwimSegmentsSample;
|
||||
}
|
||||
|
||||
private static Entity addHuaweiDictData(Schema schema, Entity user, Entity device) {
|
||||
Entity dictData = addEntity(schema, "HuaweiDictData");
|
||||
|
||||
dictData.setJavaDoc("Contains Huawei Dict Data");
|
||||
|
||||
dictData.addLongProperty("dictId").primaryKey().autoincrement();
|
||||
|
||||
Property deviceId = dictData.addLongProperty("deviceId").notNull().getProperty();
|
||||
dictData.addToOne(device, deviceId);
|
||||
Property userId = dictData.addLongProperty("userId").notNull().getProperty();
|
||||
dictData.addToOne(user, userId);
|
||||
|
||||
dictData.addIntProperty("dictClass").notNull();
|
||||
dictData.addLongProperty("startTimestamp").notNull();
|
||||
dictData.addLongProperty("endTimestamp");
|
||||
dictData.addLongProperty("modifyTimestamp");
|
||||
|
||||
return dictData;
|
||||
}
|
||||
|
||||
private static Entity addHuaweiDictDataValues(Schema schema, Entity summaryEntity) {
|
||||
Entity dictDataValues = addEntity(schema, "HuaweiDictDataValues");
|
||||
|
||||
dictDataValues.setJavaDoc("Contains Huawei Dict data values");
|
||||
|
||||
Property id = dictDataValues.addLongProperty("dictId").primaryKey().notNull().getProperty();
|
||||
dictDataValues.addToOne(summaryEntity, id);
|
||||
|
||||
dictDataValues.addIntProperty("dictType").notNull().primaryKey();
|
||||
dictDataValues.addByteProperty("tag").notNull().primaryKey();
|
||||
dictDataValues.addByteArrayProperty("value");
|
||||
|
||||
return dictDataValues;
|
||||
}
|
||||
|
||||
|
||||
private static void addTemperatureProperties(Entity activitySample) {
|
||||
activitySample.addFloatProperty(SAMPLE_TEMPERATURE).notNull().codeBeforeGetter(OVERRIDE);
|
||||
activitySample.addIntProperty(SAMPLE_TEMPERATURE_TYPE).notNull().codeBeforeGetter(OVERRIDE);
|
||||
|
@ -60,6 +60,7 @@ public class TemperatureChartFragment extends AbstractChartFragment<TemperatureC
|
||||
|
||||
protected final int TOTAL_DAYS = getRangeDays();
|
||||
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
BACKGROUND_COLOR = GBApplication.getBackgroundColor(requireContext());
|
||||
|
@ -41,6 +41,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiBRSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiWorkoutGbParser;
|
||||
@ -187,6 +188,11 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin
|
||||
return huaweiCoordinator.supportsMusic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTemperatureMeasurement() {
|
||||
return huaweiCoordinator.supportsTemperature();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||
return huaweiCoordinator.getInstallHandler(uri, context);
|
||||
@ -207,6 +213,11 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin
|
||||
return new HuaweiSpo2SampleProvider(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeSampleProvider<? extends TemperatureSample> getTemperatureSampleProvider(final GBDevice device, final DaoSession session) {
|
||||
return new HuaweiTemperatureSampleProvider(device, session);
|
||||
}
|
||||
|
||||
public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) {
|
||||
return huaweiCoordinator.getDeviceSpecificSettings(device);
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiActivitySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictData;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataValuesDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
||||
@ -134,6 +137,16 @@ public class HuaweiCoordinator {
|
||||
session.getHuaweiWorkoutSummarySampleDao().queryBuilder().where(HuaweiWorkoutSummarySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
|
||||
session.getBaseActivitySummaryDao().queryBuilder().where(BaseActivitySummaryDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
|
||||
QueryBuilder<HuaweiDictData> qb3 = session.getHuaweiDictDataDao().queryBuilder();
|
||||
List<HuaweiDictData> dictData = qb3.where(HuaweiDictDataDao.Properties.DeviceId.eq(deviceId)).build().list();
|
||||
for (HuaweiDictData data : dictData) {
|
||||
session.getHuaweiDictDataValuesDao().queryBuilder().where(
|
||||
HuaweiDictDataValuesDao.Properties.DictId.eq(data.getDictId())
|
||||
).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
}
|
||||
|
||||
session.getHuaweiDictDataDao().queryBuilder().where(HuaweiDictDataDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
}
|
||||
|
||||
private SharedPreferences getCapabilitiesSharedPreferences() {
|
||||
|
@ -42,6 +42,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiLESupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiWorkoutGbParser;
|
||||
@ -196,6 +197,11 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i
|
||||
return huaweiCoordinator.supportsMusic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTemperatureMeasurement() {
|
||||
return huaweiCoordinator.supportsTemperature();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||
return huaweiCoordinator.getInstallHandler(uri, context);
|
||||
@ -216,6 +222,11 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i
|
||||
return new HuaweiSpo2SampleProvider(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeSampleProvider<? extends TemperatureSample> getTemperatureSampleProvider(final GBDevice device, final DaoSession session) {
|
||||
return new HuaweiTemperatureSampleProvider(device, session);
|
||||
}
|
||||
|
||||
public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) {
|
||||
return huaweiCoordinator.getDeviceSpecificSettings(device);
|
||||
}
|
||||
|
@ -243,6 +243,10 @@ public class HuaweiTLV {
|
||||
return ByteBuffer.wrap(getBytes(tag)).getShort();
|
||||
}
|
||||
|
||||
public Long getLong(int tag) throws HuaweiPacket.MissingTagException {
|
||||
return ByteBuffer.wrap(getBytes(tag)).getLong();
|
||||
}
|
||||
|
||||
public Integer getAsInteger(int tag) throws HuaweiPacket.MissingTagException {
|
||||
byte[] bytes = getBytes(tag);
|
||||
if(bytes.length == 1) {
|
||||
|
@ -0,0 +1,190 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.huawei;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import de.greenrobot.dao.Property;
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiActivitySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictData;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataValues;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataValuesDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.p2p.HuaweiP2PDataDictionarySyncService;
|
||||
|
||||
public class HuaweiTemperatureSampleProvider implements TimeSampleProvider<TemperatureSample> {
|
||||
|
||||
private final Logger LOG = LoggerFactory.getLogger(HuaweiTemperatureSampleProvider.class);
|
||||
|
||||
protected static class HuaweiTemperatureSample implements TemperatureSample {
|
||||
private final long timestamp;
|
||||
private final float temperature;
|
||||
|
||||
public HuaweiTemperatureSample(long timestamp, float temperature) {
|
||||
this.timestamp = timestamp;
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTemperatureType() { return 0;}
|
||||
}
|
||||
|
||||
private final GBDevice device;
|
||||
private final DaoSession session;
|
||||
|
||||
public HuaweiTemperatureSampleProvider(GBDevice device, DaoSession session) {
|
||||
this.device = device;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
private double conv2Double(byte[] b) {
|
||||
return ByteBuffer.wrap(b).getDouble();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<TemperatureSample> getAllSamples(long timestampFrom, long timestampTo) {
|
||||
|
||||
List<TemperatureSample> ret = new ArrayList<>();
|
||||
|
||||
Long userId = DBHelper.getUser(this.session).getId();
|
||||
Long deviceId = DBHelper.getDevice(this.device, this.session).getId();
|
||||
|
||||
if (deviceId == null || userId == null)
|
||||
return ret;
|
||||
|
||||
QueryBuilder<HuaweiDictData> qb = this.session.getHuaweiDictDataDao().queryBuilder();
|
||||
qb.where(HuaweiDictDataDao.Properties.DeviceId.eq(deviceId))
|
||||
.where(HuaweiDictDataDao.Properties.UserId.eq(userId))
|
||||
.where(HuaweiDictDataDao.Properties.DictClass.eq(400012))
|
||||
.where(HuaweiDictDataDao.Properties.StartTimestamp.between(timestampFrom, timestampTo));
|
||||
final List<HuaweiDictData> dictData = qb.build().list();
|
||||
|
||||
if (dictData.isEmpty())
|
||||
return ret;
|
||||
|
||||
List<Long> ids = dictData.stream().map(HuaweiDictData::getDictId).collect(Collectors.toList());
|
||||
|
||||
QueryBuilder<HuaweiDictDataValues> qbv = this.session.getHuaweiDictDataValuesDao().queryBuilder();
|
||||
|
||||
qbv.where(HuaweiDictDataValuesDao.Properties.DictType.eq(400012430)).where(HuaweiDictDataValuesDao.Properties.Tag.eq(10)).where(HuaweiDictDataValuesDao.Properties.DictId.in(ids));
|
||||
|
||||
final List<HuaweiDictDataValues> valuesData = qbv.build().list();
|
||||
|
||||
if (valuesData.isEmpty())
|
||||
return ret;
|
||||
|
||||
for(HuaweiDictDataValues vl: valuesData) {
|
||||
double skinTemperature = conv2Double(vl.getValue());
|
||||
if(skinTemperature >= 20 && skinTemperature <= 42) {
|
||||
ret.add(new HuaweiTemperatureSample(vl.getHuaweiDictData().getStartTimestamp(), (float) skinTemperature));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSample(TemperatureSample timeSample) {
|
||||
throw new UnsupportedOperationException("read-only sample provider");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSamples(List<TemperatureSample> timeSamples) {
|
||||
throw new UnsupportedOperationException("read-only sample provider");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemperatureSample createSample() {
|
||||
throw new UnsupportedOperationException("read-only sample provider");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TemperatureSample getLatestSample() {
|
||||
Long userId = DBHelper.getUser(this.session).getId();
|
||||
Long deviceId = DBHelper.getDevice(this.device, this.session).getId();
|
||||
|
||||
if (deviceId == null || userId == null)
|
||||
return null;
|
||||
|
||||
QueryBuilder<HuaweiDictData> qb = this.session.getHuaweiDictDataDao().queryBuilder();
|
||||
qb.where(HuaweiDictDataDao.Properties.DeviceId.eq(deviceId))
|
||||
.where(HuaweiDictDataDao.Properties.UserId.eq(userId))
|
||||
.where(HuaweiDictDataDao.Properties.DictClass.eq(400012));
|
||||
qb.orderDesc(HuaweiDictDataDao.Properties.StartTimestamp).limit(1);
|
||||
|
||||
final List<HuaweiDictData> data = qb.build().list();
|
||||
if (data.isEmpty())
|
||||
return null;
|
||||
|
||||
|
||||
QueryBuilder<HuaweiDictDataValues> qbv = this.session.getHuaweiDictDataValuesDao().queryBuilder();
|
||||
qbv.where(HuaweiDictDataValuesDao.Properties.DictType.eq(400012430)).where(HuaweiDictDataValuesDao.Properties.Tag.eq(10)).where(HuaweiDictDataValuesDao.Properties.DictId.eq(data.get(0).getDictId()));
|
||||
final List<HuaweiDictDataValues> valuesData = qbv.build().list();
|
||||
|
||||
if (valuesData.isEmpty())
|
||||
return null;
|
||||
|
||||
return new HuaweiTemperatureSample(valuesData.get(0).getHuaweiDictData().getStartTimestamp(), (float) conv2Double(valuesData.get(0).getValue()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TemperatureSample getFirstSample() {
|
||||
Long userId = DBHelper.getUser(this.session).getId();
|
||||
Long deviceId = DBHelper.getDevice(this.device, this.session).getId();
|
||||
|
||||
if (deviceId == null || userId == null)
|
||||
return null;
|
||||
|
||||
QueryBuilder<HuaweiDictData> qb = this.session.getHuaweiDictDataDao().queryBuilder();
|
||||
qb.where(HuaweiDictDataDao.Properties.DeviceId.eq(deviceId))
|
||||
.where(HuaweiDictDataDao.Properties.UserId.eq(userId))
|
||||
.where(HuaweiDictDataDao.Properties.DictClass.eq(400012));
|
||||
qb.orderAsc(HuaweiDictDataDao.Properties.StartTimestamp).limit(1);
|
||||
|
||||
final List<HuaweiDictData> data = qb.build().list();
|
||||
if (data.isEmpty())
|
||||
return null;
|
||||
|
||||
QueryBuilder<HuaweiDictDataValues> qbv = this.session.getHuaweiDictDataValuesDao().queryBuilder();
|
||||
qbv.where(HuaweiDictDataValuesDao.Properties.DictType.eq(400012430)).where(HuaweiDictDataValuesDao.Properties.Tag.eq(10)).where(HuaweiDictDataValuesDao.Properties.DictId.eq(data.get(0).getDictId()));
|
||||
final List<HuaweiDictDataValues> valuesData = qbv.build().list();
|
||||
|
||||
if (valuesData.isEmpty())
|
||||
return null;
|
||||
|
||||
return new HuaweiTemperatureSample(valuesData.get(0).getHuaweiDictData().getStartTimestamp(), (float) conv2Double(valuesData.get(0).getValue()));
|
||||
}
|
||||
}
|
@ -31,8 +31,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -70,6 +68,10 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictData;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataValues;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataValuesDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSample;
|
||||
@ -105,6 +107,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.p2p.HuaweiP2PCalendarService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.p2p.HuaweiP2PTrackService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.p2p.HuaweiP2PDataDictionarySyncService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.AcceptAgreementsRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetAppInfoParams;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetContactsCount;
|
||||
@ -887,6 +890,10 @@ public class HuaweiSupportProvider {
|
||||
trackService.register();
|
||||
}
|
||||
}
|
||||
if (HuaweiP2PDataDictionarySyncService.getRegisteredInstance(huaweiP2PManager) == null) {
|
||||
HuaweiP2PDataDictionarySyncService trackService = new HuaweiP2PDataDictionarySyncService(huaweiP2PManager);
|
||||
trackService.register();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1184,6 +1191,7 @@ public class HuaweiSupportProvider {
|
||||
|
||||
private void fetchActivityData() {
|
||||
syncState.setActivitySync(true);
|
||||
fetchActivityDataP2P();
|
||||
|
||||
int sleepStart = 0;
|
||||
int stepStart = 0;
|
||||
@ -1242,6 +1250,7 @@ public class HuaweiSupportProvider {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
getStepDataCountRequest.setFinalizeReq(new RequestCallback() {
|
||||
@Override
|
||||
public void call() {
|
||||
@ -1286,6 +1295,18 @@ public class HuaweiSupportProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchActivityDataP2P() {
|
||||
HuaweiP2PDataDictionarySyncService P2PSyncService = HuaweiP2PDataDictionarySyncService.getRegisteredInstance(huaweiP2PManager);
|
||||
if (P2PSyncService != null && getHuaweiCoordinator().supportsTemperature()) {
|
||||
P2PSyncService.sendSyncRequest(400012, new HuaweiP2PDataDictionarySyncService.DictionarySyncCallback() {
|
||||
@Override
|
||||
public void onComplete(boolean complete) {
|
||||
LOG.info("Sync P2P Temperature complete");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchWorkoutData() {
|
||||
syncState.setWorkoutSync(true);
|
||||
|
||||
@ -1721,7 +1742,7 @@ public class HuaweiSupportProvider {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
HuaweiWorkoutPaceSampleDao dao = db.getDaoSession().getHuaweiWorkoutPaceSampleDao();
|
||||
|
||||
if(number == 0) {
|
||||
if (number == 0) {
|
||||
final DeleteQuery<HuaweiWorkoutPaceSample> tableDeleteQuery = dao.queryBuilder()
|
||||
.where(HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.eq(workoutId))
|
||||
.buildDelete();
|
||||
@ -1756,7 +1777,7 @@ public class HuaweiSupportProvider {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
HuaweiWorkoutSwimSegmentsSampleDao dao = db.getDaoSession().getHuaweiWorkoutSwimSegmentsSampleDao();
|
||||
|
||||
if(number == 0) {
|
||||
if (number == 0) {
|
||||
final DeleteQuery<HuaweiWorkoutSwimSegmentsSample> tableDeleteQuery = dao.queryBuilder()
|
||||
.where(HuaweiWorkoutSwimSegmentsSampleDao.Properties.WorkoutId.eq(workoutId))
|
||||
.buildDelete();
|
||||
@ -1785,6 +1806,92 @@ public class HuaweiSupportProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public void addDictData(List<HuaweiP2PDataDictionarySyncService.DictData> dictData) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
||||
Long deviceId = DBHelper.getDevice(gbDevice, db.getDaoSession()).getId();
|
||||
|
||||
for (HuaweiP2PDataDictionarySyncService.DictData data : dictData) {
|
||||
// Avoid duplicates
|
||||
QueryBuilder<HuaweiDictData> qb = db.getDaoSession().getHuaweiDictDataDao().queryBuilder().where(
|
||||
HuaweiDictDataDao.Properties.UserId.eq(userId),
|
||||
HuaweiDictDataDao.Properties.DeviceId.eq(deviceId),
|
||||
HuaweiDictDataDao.Properties.DictClass.eq(data.getDictClass()),
|
||||
HuaweiDictDataDao.Properties.StartTimestamp.eq(data.getStartTimestamp())
|
||||
);
|
||||
List<HuaweiDictData> results = qb.build().list();
|
||||
Long dictId = null;
|
||||
if (!results.isEmpty())
|
||||
dictId = results.get(0).getDictId();
|
||||
|
||||
HuaweiDictData dictSample = new HuaweiDictData(
|
||||
dictId,
|
||||
deviceId,
|
||||
userId,
|
||||
data.getDictClass(),
|
||||
data.getStartTimestamp(),
|
||||
data.getEndTimestamp(),
|
||||
data.getModifyTimestamp()
|
||||
);
|
||||
db.getDaoSession().getHuaweiDictDataDao().insertOrReplace(dictSample);
|
||||
addDictDataValue(dictSample.getDictId(), data.getData());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to add dict data", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDictDataValue(Long dictId, List<HuaweiP2PDataDictionarySyncService.DictData.DictDataValue> dictDataValues) {
|
||||
if (dictId == null)
|
||||
return;
|
||||
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
HuaweiDictDataValuesDao dao = db.getDaoSession().getHuaweiDictDataValuesDao();
|
||||
|
||||
for (HuaweiP2PDataDictionarySyncService.DictData.DictDataValue dataValues : dictDataValues) {
|
||||
|
||||
HuaweiDictDataValues dictValue = new HuaweiDictDataValues(
|
||||
dictId,
|
||||
dataValues.getDataType(),
|
||||
dataValues.getTag(),
|
||||
dataValues.getValue()
|
||||
);
|
||||
dao.insertOrReplace(dictValue);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to add dict value to database", e);
|
||||
}
|
||||
}
|
||||
|
||||
public long getLastDataDictLastTimestamp(int dictClass) {
|
||||
long lastTimestamp = 0;
|
||||
if (dictClass == 0)
|
||||
return lastTimestamp;
|
||||
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
||||
Long deviceId = DBHelper.getDevice(gbDevice, db.getDaoSession()).getId();
|
||||
|
||||
QueryBuilder<HuaweiDictData> qb = db.getDaoSession().getHuaweiDictDataDao().queryBuilder().where(
|
||||
HuaweiDictDataDao.Properties.UserId.eq(userId),
|
||||
HuaweiDictDataDao.Properties.DeviceId.eq(deviceId),
|
||||
HuaweiDictDataDao.Properties.DictClass.eq(dictClass)
|
||||
);
|
||||
List<HuaweiDictData> results = qb.build().list();
|
||||
for (HuaweiDictData data : results) {
|
||||
if (data.getModifyTimestamp() != null) {
|
||||
lastTimestamp = Math.max(lastTimestamp, data.getModifyTimestamp());
|
||||
}
|
||||
if (data.getEndTimestamp() != null) {
|
||||
lastTimestamp = Math.max(lastTimestamp, data.getEndTimestamp());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to select last timestsmp value to database", e);
|
||||
}
|
||||
return lastTimestamp;
|
||||
}
|
||||
|
||||
|
||||
public void setWearLocation() {
|
||||
try {
|
||||
@ -2021,7 +2128,7 @@ public class HuaweiSupportProvider {
|
||||
|
||||
HuaweiUploadManager.FileUploadInfo fileInfo = new HuaweiUploadManager.FileUploadInfo();
|
||||
|
||||
if(huaweiFwHelper.isMusic()) {
|
||||
if (huaweiFwHelper.isMusic()) {
|
||||
getHuaweiMusicManager().addUploadMusic(huaweiFwHelper.getMusicInfo());
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,279 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.p2p;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiP2PManager;
|
||||
|
||||
public class HuaweiP2PDataDictionarySyncService extends HuaweiBaseP2PService {
|
||||
private final Logger LOG = LoggerFactory.getLogger(HuaweiP2PDataDictionarySyncService.class);
|
||||
|
||||
public static final String MODULE = "hw.unitedevice.datadictionarysync";
|
||||
|
||||
private AtomicBoolean serviceAvailable = new AtomicBoolean(false);
|
||||
|
||||
public interface DictionarySyncCallback {
|
||||
void onComplete(boolean complete);
|
||||
}
|
||||
|
||||
private final Map<Integer, DictionarySyncCallback> currentRequests = new HashMap<>();
|
||||
|
||||
public HuaweiP2PDataDictionarySyncService(HuaweiP2PManager manager) {
|
||||
super(manager);
|
||||
LOG.info("P2PDataDictionarySyncService");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModule() {
|
||||
return HuaweiP2PDataDictionarySyncService.MODULE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPackage() {
|
||||
return "hw.watch.health.filesync";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFingerprint() {
|
||||
return "SystemApp";
|
||||
}
|
||||
|
||||
public static byte[] dictToBytes(int value) {
|
||||
return new byte[]{
|
||||
(byte) (value >>> 16),
|
||||
(byte) (value >>> 8),
|
||||
(byte) value};
|
||||
}
|
||||
|
||||
public void sendSyncRequest(int dictClass, DictionarySyncCallback callback) {
|
||||
|
||||
if (!serviceAvailable.get()) {
|
||||
LOG.info("P2PDataDictionarySyncService not available");
|
||||
callback.onComplete(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if(currentRequests.containsKey(dictClass)) {
|
||||
LOG.info("P2PDataDictionarySyncService current class in progress");
|
||||
callback.onComplete(false);
|
||||
return;
|
||||
}
|
||||
|
||||
long startTime = manager.getSupportProvider().getLastDataDictLastTimestamp(dictClass);
|
||||
if(startTime > 0) {
|
||||
startTime += 1000;
|
||||
}
|
||||
|
||||
HuaweiTLV tlv = new HuaweiTLV()
|
||||
.put(0x1, (byte) 1)
|
||||
.put(0x2, dictToBytes(dictClass)) //-- skin temperature
|
||||
.put(0x5, Long.valueOf(startTime))
|
||||
.put(0x6, Long.valueOf(System.currentTimeMillis()))
|
||||
.put(0x0d, (byte) 1);
|
||||
byte[] data = tlv.serialize();
|
||||
if (data == null) {
|
||||
LOG.error("Incorrect data");
|
||||
callback.onComplete(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ByteBuffer packet = ByteBuffer.allocate(1 + data.length);
|
||||
packet.put((byte) 0x1); // type tlv
|
||||
packet.put(data);
|
||||
packet.flip();
|
||||
|
||||
LOG.info("P2PDataDictionarySyncService send command");
|
||||
currentRequests.put(dictClass, callback);
|
||||
|
||||
sendCommand(packet.array(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registered() {
|
||||
sendPing(new HuaweiP2PCallback() {
|
||||
@Override
|
||||
public void onResponse(int code, byte[] data) {
|
||||
if ((byte) code != (byte) 0xca)
|
||||
return;
|
||||
serviceAvailable.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister() {
|
||||
serviceAvailable.set(false);
|
||||
}
|
||||
|
||||
public static class DictData {
|
||||
public static class DictDataValue {
|
||||
private final int dataType;
|
||||
private final byte tag;
|
||||
private final byte[] value;
|
||||
|
||||
public DictDataValue(int dataType, byte tag, byte[] value) {
|
||||
this.dataType = dataType;
|
||||
this.tag = tag;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public byte getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public byte[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("HuaweiDictDataValue{");
|
||||
sb.append("dataType=").append(dataType);
|
||||
sb.append(", tag=").append(tag);
|
||||
sb.append(", value=");
|
||||
if (value == null) sb.append("null");
|
||||
else {
|
||||
sb.append('[');
|
||||
for (int i = 0; i < value.length; ++i)
|
||||
sb.append(i == 0 ? "" : ", ").append(value[i]);
|
||||
sb.append(']');
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final int dictClass;
|
||||
private final long startTimestamp;
|
||||
private final long endTimestamp;
|
||||
private final long modifyTimestamp;
|
||||
private final List<DictDataValue> data;
|
||||
|
||||
public DictData(int dictClass, long startTimestamp, long endTimestamp, long modifyTimestamp, List<DictDataValue> data) {
|
||||
this.dictClass = dictClass;
|
||||
this.startTimestamp = startTimestamp;
|
||||
this.endTimestamp = endTimestamp;
|
||||
this.modifyTimestamp = modifyTimestamp;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public int getDictClass() { return dictClass; }
|
||||
|
||||
public long getStartTimestamp() {
|
||||
return startTimestamp;
|
||||
}
|
||||
|
||||
public long getEndTimestamp() {
|
||||
return endTimestamp;
|
||||
}
|
||||
|
||||
public long getModifyTimestamp() {
|
||||
return modifyTimestamp;
|
||||
}
|
||||
|
||||
public List<DictDataValue> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("HuaweiDictSample{");
|
||||
sb.append("startTime=").append(startTimestamp);
|
||||
sb.append(", endTime=").append(endTimestamp);
|
||||
sb.append(", modifyTime=").append(modifyTimestamp);
|
||||
sb.append(", data=").append(data);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleData(byte[] data) {
|
||||
LOG.info("P2PDataDictionarySyncService handleData: {}", data.length);
|
||||
if (data[0] == 1) {
|
||||
DictionarySyncCallback callback = null;
|
||||
try {
|
||||
|
||||
|
||||
HuaweiTLV tlv = new HuaweiTLV();
|
||||
tlv.parse(data, 1, data.length - 1);
|
||||
|
||||
int operation = tlv.getInteger(0x01); ///???
|
||||
int dictClass = tlv.getInteger(0x02);
|
||||
|
||||
if(!currentRequests.containsKey(dictClass)) {
|
||||
return;
|
||||
}
|
||||
callback = currentRequests.remove(dictClass);
|
||||
|
||||
if(callback == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//NOTE: all tags with high bit set should be parsed as container
|
||||
|
||||
List<DictData> result = new ArrayList<>();
|
||||
|
||||
for (HuaweiTLV blockTlv : tlv.getObjects(0x83)) {
|
||||
for (HuaweiTLV l : blockTlv.getObjects(0x84)) {
|
||||
//5 - start time, 6 - end time, 0xc - modify time
|
||||
long startTimestamp = l.getLong(0x5);
|
||||
long endTimestamp = 0;
|
||||
long modifyTimestamp = 0;
|
||||
if (l.contains(0x6))
|
||||
endTimestamp = l.getLong(0x6);
|
||||
if (l.contains(0xc))
|
||||
modifyTimestamp = l.getLong(0xc);
|
||||
List<DictData.DictDataValue> dataValues = new ArrayList<>();
|
||||
for (HuaweiTLV l1 : l.getObjects(0x87)) {
|
||||
for (HuaweiTLV ll : l1.getObjects(0x88)) {
|
||||
int type = ll.getInteger(0x9);
|
||||
// 10 - Double - data
|
||||
// 11 - String - metadata
|
||||
if (ll.contains(0xa))
|
||||
dataValues.add(new DictData.DictDataValue(type, (byte) 0xa, ll.getBytes(0xa)));
|
||||
if (ll.contains(0xb))
|
||||
dataValues.add(new DictData.DictDataValue(type, (byte) 0xb, ll.getBytes(0xb)));
|
||||
}
|
||||
}
|
||||
result.add(new DictData(dictClass, startTimestamp, endTimestamp, modifyTimestamp, dataValues));
|
||||
}
|
||||
}
|
||||
|
||||
manager.getSupportProvider().addDictData(result);
|
||||
|
||||
if (!result.isEmpty()) {
|
||||
sendSyncRequest(dictClass, callback);
|
||||
} else {
|
||||
callback.onComplete(true);
|
||||
}
|
||||
} catch (HuaweiPacket.MissingTagException e) {
|
||||
LOG.error("P2PDataDictionarySyncService parse error", e);
|
||||
if(callback != null) {
|
||||
callback.onComplete(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static HuaweiP2PDataDictionarySyncService getRegisteredInstance(HuaweiP2PManager manager) {
|
||||
return (HuaweiP2PDataDictionarySyncService) manager.getRegisteredService(HuaweiP2PDataDictionarySyncService.MODULE);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user