mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-27 04:16:49 +01:00
Huawei: Workout GPS synchronization
This commit is contained in:
parent
52798393a4
commit
159ebfd891
@ -46,7 +46,7 @@ public class GBDaoGenerator {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final Schema schema = new Schema(78, MAIN_PACKAGE + ".entities");
|
||||
final Schema schema = new Schema(79, MAIN_PACKAGE + ".entities");
|
||||
|
||||
Entity userAttributes = addUserAttributes(schema);
|
||||
Entity user = addUserInfo(schema, userAttributes);
|
||||
@ -137,8 +137,8 @@ public class GBDaoGenerator {
|
||||
addHuaweiActivitySample(schema, user, device);
|
||||
|
||||
Entity huaweiWorkoutSummary = addHuaweiWorkoutSummarySample(schema, user, device);
|
||||
addHuaweiWorkoutDataSample(schema, user, device, huaweiWorkoutSummary);
|
||||
addHuaweiWorkoutPaceSample(schema, user, device, huaweiWorkoutSummary);
|
||||
addHuaweiWorkoutDataSample(schema, huaweiWorkoutSummary);
|
||||
addHuaweiWorkoutPaceSample(schema, huaweiWorkoutSummary);
|
||||
|
||||
addCalendarSyncState(schema, device);
|
||||
addAlarms(schema, user, device);
|
||||
@ -1307,10 +1307,12 @@ public class GBDaoGenerator {
|
||||
|
||||
workoutSummary.addByteArrayProperty("rawData");
|
||||
|
||||
workoutSummary.addStringProperty("gpxFileLocation");
|
||||
|
||||
return workoutSummary;
|
||||
}
|
||||
|
||||
private static Entity addHuaweiWorkoutDataSample(Schema schema, Entity user, Entity device, Entity summaryEntity) {
|
||||
private static Entity addHuaweiWorkoutDataSample(Schema schema, Entity summaryEntity) {
|
||||
Entity workoutDataSample = addEntity(schema, "HuaweiWorkoutDataSample");
|
||||
|
||||
workoutDataSample.setJavaDoc("Contains Huawei Workout data samples (multiple per workout)");
|
||||
@ -1345,7 +1347,7 @@ public class GBDaoGenerator {
|
||||
return workoutDataSample;
|
||||
}
|
||||
|
||||
private static Entity addHuaweiWorkoutPaceSample(Schema schema, Entity user, Entity device, Entity summaryEntity) {
|
||||
private static Entity addHuaweiWorkoutPaceSample(Schema schema, Entity summaryEntity) {
|
||||
Entity workoutPaceSample = addEntity(schema, "HuaweiWorkoutPaceSample");
|
||||
|
||||
workoutPaceSample.setJavaDoc("Contains Huawei Workout pace data samples (one per workout)");
|
||||
|
@ -0,0 +1,38 @@
|
||||
/* Copyright (C) 2024 Martin.JM
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
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_79 implements DBUpdateScript {
|
||||
@Override
|
||||
public void upgradeSchema(final SQLiteDatabase db) {
|
||||
if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.GpxFileLocation.columnName, db)) {
|
||||
final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \""
|
||||
+ HuaweiWorkoutSummarySampleDao.Properties.GpxFileLocation.columnName + "\" TEXT";
|
||||
db.execSQL(statement);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downgradeSchema(final SQLiteDatabase db) {
|
||||
}
|
||||
}
|
@ -26,9 +26,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
||||
@ -38,13 +36,8 @@ import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
|
||||
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.HuaweiWorkoutDataSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
|
||||
@ -87,21 +80,7 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin
|
||||
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||
long deviceId = device.getId();
|
||||
QueryBuilder<?> qb = session.getHuaweiActivitySampleDao().queryBuilder();
|
||||
qb.where(HuaweiActivitySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
|
||||
QueryBuilder<HuaweiWorkoutSummarySample> qb2 = session.getHuaweiWorkoutSummarySampleDao().queryBuilder();
|
||||
List<HuaweiWorkoutSummarySample> workouts = qb2.where(HuaweiWorkoutSummarySampleDao.Properties.DeviceId.eq(deviceId)).build().list();
|
||||
for (HuaweiWorkoutSummarySample sample : workouts) {
|
||||
session.getHuaweiWorkoutDataSampleDao().queryBuilder().where(
|
||||
HuaweiWorkoutDataSampleDao.Properties.WorkoutId.eq(sample.getWorkoutId())
|
||||
).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
}
|
||||
|
||||
session.getHuaweiWorkoutSummarySampleDao().queryBuilder().where(HuaweiWorkoutSummarySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
|
||||
session.getBaseActivitySummaryDao().queryBuilder().where(BaseActivitySummaryDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
huaweiCoordinator.deleteDevice(gbDevice, device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,7 +29,9 @@ import java.util.TreeMap;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.CameraActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AppManagerActivity;
|
||||
@ -40,11 +42,21 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.App;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Notifications;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Notifications.NotificationConstraintsType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Watchface;
|
||||
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.HuaweiWorkoutDataSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.*;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class HuaweiCoordinator {
|
||||
Logger LOG = LoggerFactory.getLogger(HuaweiCoordinator.class);
|
||||
|
||||
@ -56,6 +68,7 @@ public class HuaweiCoordinator {
|
||||
ByteBuffer notificationConstraints = null;
|
||||
|
||||
private boolean supportsTruSleepNewSync = false;
|
||||
private boolean supportsGpsNewSync = false;
|
||||
|
||||
private Watchface.WatchfaceDeviceParams watchfaceDeviceParams;
|
||||
|
||||
@ -92,6 +105,28 @@ public class HuaweiCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||
long deviceId = device.getId();
|
||||
QueryBuilder<?> qb = session.getHuaweiActivitySampleDao().queryBuilder();
|
||||
qb.where(HuaweiActivitySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
|
||||
QueryBuilder<HuaweiWorkoutSummarySample> qb2 = session.getHuaweiWorkoutSummarySampleDao().queryBuilder();
|
||||
List<HuaweiWorkoutSummarySample> workouts = qb2.where(HuaweiWorkoutSummarySampleDao.Properties.DeviceId.eq(deviceId)).build().list();
|
||||
for (HuaweiWorkoutSummarySample sample : workouts) {
|
||||
session.getHuaweiWorkoutDataSampleDao().queryBuilder().where(
|
||||
HuaweiWorkoutDataSampleDao.Properties.WorkoutId.eq(sample.getWorkoutId())
|
||||
).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
|
||||
session.getHuaweiWorkoutPaceSampleDao().queryBuilder().where(
|
||||
HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.eq(sample.getWorkoutId())
|
||||
).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
}
|
||||
|
||||
session.getHuaweiWorkoutSummarySampleDao().queryBuilder().where(HuaweiWorkoutSummarySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
|
||||
session.getBaseActivitySummaryDao().queryBuilder().where(BaseActivitySummaryDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
}
|
||||
|
||||
private SharedPreferences getCapabilitiesSharedPreferences() {
|
||||
return GBApplication.getContext().getSharedPreferences("huawei_coordinator_capatilities" + parent.getDeviceType().name(), Context.MODE_PRIVATE);
|
||||
}
|
||||
@ -694,4 +729,12 @@ public class HuaweiCoordinator {
|
||||
public void setSupportsTruSleepNewSync(boolean supportsTruSleepNewSync) {
|
||||
this.supportsTruSleepNewSync = supportsTruSleepNewSync;
|
||||
}
|
||||
|
||||
public boolean isSupportsGpsNewSync() {
|
||||
return supportsGpsNewSync;
|
||||
}
|
||||
|
||||
public void setSupportsGpsNewSync(boolean supportsGpsNewSync) {
|
||||
this.supportsGpsNewSync = supportsGpsNewSync;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,102 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.huawei;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class HuaweiGpsParser {
|
||||
|
||||
public static class GpsPoint {
|
||||
public int timestamp;
|
||||
public double latitude;
|
||||
public double longitude;
|
||||
public boolean altitudeSupported;
|
||||
public double altitude;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GpsPoint{" +
|
||||
"timestamp=" + timestamp +
|
||||
", longitude=" + longitude +
|
||||
", latitude=" + latitude +
|
||||
", altitudeSupported=" + altitudeSupported +
|
||||
", altitude=" + altitude +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static GpsPoint[] parseHuaweiGps(byte[] data) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// Skip trim
|
||||
buffer.position(0x20);
|
||||
|
||||
int timestamp;
|
||||
double lon_start;
|
||||
double lat_start;
|
||||
boolean alt_support;
|
||||
double alt_start;
|
||||
|
||||
byte fileType = buffer.get();
|
||||
if ((fileType & 0x03) != 0x03) {
|
||||
alt_support = false;
|
||||
timestamp = buffer.getInt();
|
||||
lon_start = buffer.getDouble();
|
||||
lat_start = buffer.getDouble();
|
||||
alt_start = 0;
|
||||
buffer.position(62); // Skip past unknown fields/padding
|
||||
} else {
|
||||
alt_support = true;
|
||||
timestamp = buffer.getInt();
|
||||
lon_start = buffer.getDouble();
|
||||
lat_start = buffer.getDouble();
|
||||
alt_start = buffer.getDouble();
|
||||
buffer.position(70); // Skip past unknown fields/padding
|
||||
}
|
||||
|
||||
lat_start = lat_start * 0.017453292519943;
|
||||
lon_start = lon_start * 0.017453292519943;
|
||||
|
||||
// Working values
|
||||
int time = timestamp;
|
||||
double lat = lat_start;
|
||||
double lon = lon_start;
|
||||
double alt = alt_start;
|
||||
|
||||
int data_size = 15;
|
||||
if (alt_support)
|
||||
data_size += 4;
|
||||
|
||||
ArrayList<GpsPoint> retv = new ArrayList<>(buffer.remaining() / data_size);
|
||||
while (buffer.remaining() > data_size) {
|
||||
short time_delta = buffer.getShort();
|
||||
buffer.getShort(); // Unknown value
|
||||
float lon_delta = buffer.getFloat();
|
||||
float lat_delta = buffer.getFloat();
|
||||
buffer.get(); buffer.get(); buffer.get(); // Unknown values
|
||||
|
||||
time = time + time_delta;
|
||||
lat = lat + lat_delta;
|
||||
lon = lon + lon_delta;
|
||||
|
||||
GpsPoint point = new GpsPoint();
|
||||
point.timestamp = time;
|
||||
point.latitude = (lat / 6383807.0d + lat_start) / 0.017453292519943d;
|
||||
point.longitude = (lon / 6383807.0d / Math.cos(lat_start) + lon_start) / 0.017453292519943d;
|
||||
point.altitudeSupported = alt_support;
|
||||
if (alt_support) {
|
||||
// TODO: not sure about this
|
||||
float alt_delta = buffer.getFloat();
|
||||
alt = alt + alt_delta;
|
||||
point.altitude = alt;
|
||||
}
|
||||
retv.add(point);
|
||||
}
|
||||
|
||||
return retv.toArray(new GpsPoint[0]);
|
||||
}
|
||||
}
|
@ -27,9 +27,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
||||
@ -39,13 +37,8 @@ import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
|
||||
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.HuaweiWorkoutDataSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
|
||||
@ -96,21 +89,7 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i
|
||||
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||
long deviceId = device.getId();
|
||||
QueryBuilder<?> qb = session.getHuaweiActivitySampleDao().queryBuilder();
|
||||
qb.where(HuaweiActivitySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
|
||||
QueryBuilder<HuaweiWorkoutSummarySample> qb2 = session.getHuaweiWorkoutSummarySampleDao().queryBuilder();
|
||||
List<HuaweiWorkoutSummarySample> workouts = qb2.where(HuaweiWorkoutSummarySampleDao.Properties.DeviceId.eq(deviceId)).build().list();
|
||||
for (HuaweiWorkoutSummarySample sample : workouts) {
|
||||
session.getHuaweiWorkoutDataSampleDao().queryBuilder().where(
|
||||
HuaweiWorkoutDataSampleDao.Properties.WorkoutId.eq(sample.getWorkoutId())
|
||||
).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
}
|
||||
|
||||
session.getHuaweiWorkoutSummarySampleDao().queryBuilder().where(HuaweiWorkoutSummarySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
|
||||
session.getBaseActivitySummaryDao().queryBuilder().where(BaseActivitySummaryDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
huaweiCoordinator.deleteDevice(gbDevice, device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1515,6 +1515,7 @@ public class DeviceConfig {
|
||||
|
||||
public static class Response extends HuaweiPacket {
|
||||
public boolean truSleepNewSync = false;
|
||||
public boolean gpsNewSync = false;
|
||||
|
||||
public Response(ParamsProvider paramsProvider) {
|
||||
super(paramsProvider);
|
||||
@ -1532,6 +1533,7 @@ public class DeviceConfig {
|
||||
// Tag 2 -> File support
|
||||
byte value = this.tlv.getByte(0x02);
|
||||
truSleepNewSync = (value & 2) != 0;
|
||||
gpsNewSync = (value & 8) != 0;
|
||||
}
|
||||
|
||||
// Tag 3 -> SmartWatchVersion
|
||||
|
@ -31,6 +31,7 @@ public class FileDownloadService0A {
|
||||
Type of files that can be downloaded through here:
|
||||
- debug files
|
||||
- sleep files
|
||||
- gps files
|
||||
- rrisqi file
|
||||
*/
|
||||
|
||||
@ -68,6 +69,26 @@ public class FileDownloadService0A {
|
||||
}
|
||||
}
|
||||
|
||||
public static class GpsFileRequest extends HuaweiPacket {
|
||||
public GpsFileRequest(ParamsProvider paramsProvider, short workoutId) {
|
||||
super(paramsProvider);
|
||||
|
||||
this.serviceId = FileDownloadService0A.id;
|
||||
this.commandId = id;
|
||||
|
||||
this.tlv = new HuaweiTLV()
|
||||
.put(0x02, (byte) 0x02)
|
||||
.put(0x86, new HuaweiTLV()
|
||||
.put(0x07, (byte) 0x01) // Might be type?
|
||||
.put(0x88, new HuaweiTLV()
|
||||
.put(0x09, workoutId)
|
||||
)
|
||||
);
|
||||
|
||||
this.complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Response extends HuaweiPacket {
|
||||
public String[] fileNames;
|
||||
|
||||
@ -77,7 +98,11 @@ public class FileDownloadService0A {
|
||||
|
||||
@Override
|
||||
public void parseTlv() throws ParseException {
|
||||
String possibleNames = this.tlv.getString(0x01);
|
||||
String possibleNames;
|
||||
if (this.tlv.contains(0x01))
|
||||
possibleNames = this.tlv.getString(0x01);
|
||||
else // For GPS, also has workoutId (0x09) and another tag (0x0e), not sure of the meaning
|
||||
possibleNames = this.tlv.getObject(0x8b).getObject(0x8c).getString(0x0d);
|
||||
fileNames = possibleNames.split(";");
|
||||
}
|
||||
}
|
||||
@ -87,13 +112,16 @@ public class FileDownloadService0A {
|
||||
public static final int id = 0x02;
|
||||
|
||||
public static class Request extends HuaweiPacket {
|
||||
public Request(ParamsProvider paramsProvider) {
|
||||
public Request(ParamsProvider paramsProvider, boolean truSleep) {
|
||||
super(paramsProvider);
|
||||
|
||||
this.serviceId = FileDownloadService0A.id;
|
||||
this.commandId = id;
|
||||
|
||||
this.tlv = new HuaweiTLV().put(0x06, (byte) 1);
|
||||
if (truSleep)
|
||||
this.tlv = new HuaweiTLV().put(0x06, (byte) 0x01);
|
||||
else
|
||||
this.tlv = new HuaweiTLV().put(0x06, (byte) 0x02).put(0x07, (byte) 0x03);
|
||||
|
||||
this.complete = true;
|
||||
}
|
||||
@ -151,7 +179,8 @@ public class FileDownloadService0A {
|
||||
|
||||
@Override
|
||||
public void parseTlv() throws ParseException {
|
||||
this.fileLength = this.tlv.getInteger(0x02);
|
||||
if (this.tlv.contains(0x02))
|
||||
this.fileLength = this.tlv.getInteger(0x02);
|
||||
if (this.tlv.contains(0x04))
|
||||
this.transferType = this.tlv.getByte(0x04);
|
||||
if (this.tlv.contains(0x05))
|
||||
|
@ -33,6 +33,7 @@ public class FileDownloadService2C {
|
||||
public enum FileType {
|
||||
SLEEP_STATE,
|
||||
SLEEP_DATA,
|
||||
GPS,
|
||||
UNKNOWN; // Never use this as input
|
||||
|
||||
static byte fileTypeToByte(FileType fileType) {
|
||||
@ -41,6 +42,8 @@ public class FileDownloadService2C {
|
||||
return (byte) 0x0e;
|
||||
case SLEEP_DATA:
|
||||
return (byte) 0x0f;
|
||||
case GPS:
|
||||
return (byte) 0x11;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
@ -52,6 +55,8 @@ public class FileDownloadService2C {
|
||||
return FileType.SLEEP_STATE;
|
||||
case 0x0f:
|
||||
return FileType.SLEEP_DATA;
|
||||
case 0x11:
|
||||
return FileType.GPS;
|
||||
default:
|
||||
return FileType.UNKNOWN;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileDownloadService0A;
|
||||
@ -102,48 +103,153 @@ public class HuaweiFileDownloadManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only for internal use
|
||||
*/
|
||||
public enum FileType {
|
||||
DEBUG,
|
||||
SLEEP_STATE,
|
||||
SLEEP_DATA,
|
||||
GPS,
|
||||
UNKNOWN // Never for input!
|
||||
}
|
||||
|
||||
/**
|
||||
* Only for internal use, though also used in exception
|
||||
*/
|
||||
public static class FileDownloadCallback {
|
||||
public void downloadComplete(FileRequest fileRequest) { }
|
||||
|
||||
public void downloadException(HuaweiFileDownloadException e) {
|
||||
if (e.fileRequest != null)
|
||||
LOG.error("Error downloading file: {}{}", e.fileRequest.getFilename(), e.fileRequest.isNewSync() ? " (newsync)" : "", e);
|
||||
else
|
||||
LOG.error("Error in file download", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FileRequest {
|
||||
// Inputs
|
||||
|
||||
public String filename;
|
||||
public FileType fileType;
|
||||
public boolean newSync;
|
||||
private final String filename;
|
||||
private final FileType fileType;
|
||||
private final boolean newSync;
|
||||
|
||||
// Sleep type only
|
||||
public int startTime;
|
||||
public int endTime;
|
||||
FileDownloadCallback fileDownloadCallback = null;
|
||||
|
||||
// Sleep type only - for 2C GPS they are set to zero
|
||||
private int startTime = 0;
|
||||
private int endTime = 0;
|
||||
|
||||
// GPS type only
|
||||
private short workoutId;
|
||||
private Long databaseId;
|
||||
|
||||
private FileRequest(String filename, FileType fileType, boolean newSync, int startTime, int endTime, FileDownloadCallback fileDownloadCallback) {
|
||||
this.filename = filename;
|
||||
this.fileType = fileType;
|
||||
this.newSync = newSync;
|
||||
this.fileDownloadCallback = fileDownloadCallback;
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public static FileRequest sleepStateFileRequest(boolean supportsTruSleepNewSync, int startTime, int endTime, FileDownloadCallback fileDownloadCallback) {
|
||||
return new FileRequest("sleep_state.bin", FileType.SLEEP_STATE, supportsTruSleepNewSync, startTime, endTime, fileDownloadCallback);
|
||||
}
|
||||
|
||||
public static FileRequest sleepDataFileRequest(boolean supportsTruSleepNewSync, int startTime, int endTime, FileDownloadCallback fileDownloadCallback) {
|
||||
return new FileRequest("sleep_data.bin", FileType.SLEEP_DATA, supportsTruSleepNewSync, startTime, endTime, fileDownloadCallback);
|
||||
}
|
||||
|
||||
private FileRequest(String filename, FileType fileType, boolean newSync, FileDownloadCallback fileDownloadCallback) {
|
||||
this.filename = filename;
|
||||
this.fileType = fileType;
|
||||
this.newSync = newSync;
|
||||
this.fileDownloadCallback = fileDownloadCallback;
|
||||
}
|
||||
|
||||
public static FileRequest debugFileRequest(String filename, FileDownloadCallback fileDownloadCallback) {
|
||||
return new FileRequest(filename, FileType.DEBUG, false, fileDownloadCallback);
|
||||
}
|
||||
|
||||
private FileRequest(@Nullable String filename, FileType fileType, boolean newSync, short workoutId, Long databaseId, FileDownloadCallback fileDownloadCallback) {
|
||||
this.filename = filename;
|
||||
this.fileType = fileType;
|
||||
this.newSync = newSync;
|
||||
this.fileDownloadCallback = fileDownloadCallback;
|
||||
this.workoutId = workoutId;
|
||||
this.databaseId = databaseId;
|
||||
}
|
||||
|
||||
public static FileRequest workoutGpsFileRequest(boolean newSync, short workoutId, Long databaseId, FileDownloadCallback fileDownloadCallback) {
|
||||
if (newSync)
|
||||
return new FileRequest(String.format(Locale.getDefault(), "%d_gps.bin", workoutId), FileType.GPS, true, workoutId, databaseId, fileDownloadCallback);
|
||||
else
|
||||
return new FileRequest(null, FileType.GPS, false, workoutId, databaseId, fileDownloadCallback);
|
||||
}
|
||||
|
||||
// Retrieved
|
||||
|
||||
public int fileSize;
|
||||
public int maxBlockSize;
|
||||
public int timeout; // TODO: unit?
|
||||
public ByteBuffer buffer;
|
||||
private int fileSize;
|
||||
private int maxBlockSize;
|
||||
private int timeout; // TODO: unit?
|
||||
private ByteBuffer buffer;
|
||||
|
||||
public int startOfBlockOffset;
|
||||
public int currentBlockSize;
|
||||
private int startOfBlockOffset;
|
||||
private int currentBlockSize;
|
||||
|
||||
// Old sync only
|
||||
public String[] filenames;
|
||||
public byte lastPacketNumber;
|
||||
private String[] filenames;
|
||||
private byte lastPacketNumber;
|
||||
|
||||
// New sync only
|
||||
public byte fileId;
|
||||
public boolean noEncrypt;
|
||||
private byte fileId;
|
||||
private boolean noEncrypt;
|
||||
|
||||
public byte getFileId() {
|
||||
return fileId;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public FileType getFileType() {
|
||||
return fileType;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
if (buffer == null)
|
||||
return new byte[] {};
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
public int getCurrentOffset() {
|
||||
return buffer.position();
|
||||
}
|
||||
|
||||
public boolean isNewSync() {
|
||||
return newSync;
|
||||
}
|
||||
|
||||
public int getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public int getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public short getWorkoutId() {
|
||||
return workoutId;
|
||||
}
|
||||
|
||||
public Long getDatabaseId() {
|
||||
return databaseId;
|
||||
}
|
||||
|
||||
public int getCurrentBlockSize() {
|
||||
return currentBlockSize;
|
||||
}
|
||||
|
||||
public boolean isNoEncrypt() {
|
||||
return noEncrypt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,37 +325,25 @@ public class HuaweiFileDownloadManager {
|
||||
private final ArrayList<FileRequest> fileRequests;
|
||||
private FileRequest currentFileRequest;
|
||||
|
||||
// If the GB interface needs to be updated at the end of the queue of downloads
|
||||
private boolean needSync = false;
|
||||
|
||||
public HuaweiFileDownloadManager(HuaweiSupportProvider supportProvider) {
|
||||
this.supportProvider = supportProvider;
|
||||
handler = new Handler(Looper.getMainLooper());
|
||||
isBusy = false;
|
||||
fileRequests = new ArrayList<>();
|
||||
timeout = () -> {
|
||||
this.supportProvider.downloadException(new HuaweiFileDownloadTimeoutException(currentFileRequest));
|
||||
this.currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadTimeoutException(currentFileRequest));
|
||||
reset();
|
||||
};
|
||||
}
|
||||
|
||||
public void downloadDebug(String filename) {
|
||||
FileRequest request = new FileRequest();
|
||||
request.filename = filename;
|
||||
request.fileType = FileType.DEBUG;
|
||||
request.newSync = false;
|
||||
public void addToQueue(FileRequest fileRequest, boolean needSync) {
|
||||
synchronized (supportProvider) {
|
||||
fileRequests.add(request);
|
||||
}
|
||||
startDownload();
|
||||
}
|
||||
|
||||
public void downloadSleep(boolean supportsTruSleepNewSync, String filename, int startTime, int endTime) {
|
||||
FileRequest request = new FileRequest();
|
||||
request.filename = filename;
|
||||
request.fileType = (filename.equals("sleep_state.bin"))?FileType.SLEEP_STATE: FileType.SLEEP_DATA;
|
||||
request.newSync = supportsTruSleepNewSync;
|
||||
request.startTime = startTime;
|
||||
request.endTime = endTime;
|
||||
synchronized (supportProvider) {
|
||||
fileRequests.add(request);
|
||||
fileRequests.add(fileRequest);
|
||||
if (needSync)
|
||||
this.needSync = true;
|
||||
}
|
||||
startDownload();
|
||||
}
|
||||
@ -275,7 +369,7 @@ public class HuaweiFileDownloadManager {
|
||||
|
||||
@Override
|
||||
public void handleException(Request.ResponseParseException e) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadRequestException(null, this.getClass(), e));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadRequestException(null, this.getClass(), e));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -285,11 +379,15 @@ public class HuaweiFileDownloadManager {
|
||||
initFileDataReceiver(); // Make sure the fileDataReceiver is ready
|
||||
|
||||
synchronized (this.supportProvider) {
|
||||
if (this.isBusy)
|
||||
if (this.isBusy) {
|
||||
LOG.debug("A new download is started while a previous is in progress.");
|
||||
return; // Already downloading, this file will come eventually
|
||||
}
|
||||
if (this.fileRequests.isEmpty()) {
|
||||
// No more files to download
|
||||
supportProvider.downloadQueueEmpty();
|
||||
supportProvider.downloadQueueEmpty(this.needSync);
|
||||
// Don't need sync after this anymore
|
||||
this.needSync = false;
|
||||
return;
|
||||
}
|
||||
this.isBusy = true;
|
||||
@ -305,7 +403,7 @@ public class HuaweiFileDownloadManager {
|
||||
GetFileDownloadInitRequest r = (GetFileDownloadInitRequest) request;
|
||||
if (r.newSync) {
|
||||
if (!currentFileRequest.filename.equals(r.filename)) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadFileMismatchException(
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadFileMismatchException(
|
||||
currentFileRequest,
|
||||
r.filename
|
||||
));
|
||||
@ -313,7 +411,7 @@ public class HuaweiFileDownloadManager {
|
||||
return;
|
||||
}
|
||||
if (currentFileRequest.fileType != r.fileType) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadFileMismatchException(
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadFileMismatchException(
|
||||
currentFileRequest,
|
||||
r.fileType
|
||||
));
|
||||
@ -329,13 +427,39 @@ public class HuaweiFileDownloadManager {
|
||||
}
|
||||
getFileInfo();
|
||||
} else {
|
||||
if (!arrayContains(r.filenames, currentFileRequest.filename)) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadFileMismatchException(
|
||||
currentFileRequest,
|
||||
r.filenames
|
||||
));
|
||||
reset();
|
||||
return;
|
||||
if (currentFileRequest.fileType == FileType.GPS) {
|
||||
if (r.filenames.length == 0) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
for (String filename : r.filenames) {
|
||||
// We only download the gps file itself right now
|
||||
if (!filename.contains("_gps.bin"))
|
||||
continue;
|
||||
|
||||
// Add download request with the filename at the start of the queue
|
||||
FileRequest fileRequest = new FileRequest(
|
||||
filename,
|
||||
FileType.GPS,
|
||||
currentFileRequest.newSync,
|
||||
currentFileRequest.workoutId,
|
||||
currentFileRequest.databaseId,
|
||||
currentFileRequest.fileDownloadCallback
|
||||
);
|
||||
synchronized (supportProvider) {
|
||||
fileRequests.add(0, fileRequest);
|
||||
}
|
||||
}
|
||||
currentFileRequest = fileRequests.remove(0); // Replace with the file to download
|
||||
} else {
|
||||
if (!arrayContains(r.filenames, currentFileRequest.filename)) {
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadFileMismatchException(
|
||||
currentFileRequest,
|
||||
r.filenames
|
||||
));
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
currentFileRequest.filenames = r.filenames;
|
||||
getDownloadParameters();
|
||||
@ -344,13 +468,13 @@ public class HuaweiFileDownloadManager {
|
||||
|
||||
@Override
|
||||
public void handleException(Request.ResponseParseException e) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadRequestException(currentFileRequest, this.getClass(), e));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadRequestException(currentFileRequest, this.getClass(), e));
|
||||
}
|
||||
});
|
||||
try {
|
||||
getFileDownloadInitRequest.doPerform();
|
||||
} catch (IOException e) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadSendException(currentFileRequest, getFileDownloadInitRequest, e));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadSendException(currentFileRequest, getFileDownloadInitRequest, e));
|
||||
reset();
|
||||
}
|
||||
}
|
||||
@ -359,7 +483,10 @@ public class HuaweiFileDownloadManager {
|
||||
// Old sync only, can never be multiple at the same time
|
||||
// Assuming currentRequest is the correct one the entire time
|
||||
// Which may no longer be the case when we implement multi-download for new sync
|
||||
GetFileParametersRequest getFileParametersRequest = new GetFileParametersRequest(supportProvider);
|
||||
GetFileParametersRequest getFileParametersRequest = new GetFileParametersRequest(supportProvider,
|
||||
currentFileRequest.fileType == FileType.SLEEP_STATE ||
|
||||
currentFileRequest.fileType == FileType.SLEEP_DATA
|
||||
);
|
||||
getFileParametersRequest.setFinalizeReq(new Request.RequestCallback() {
|
||||
@Override
|
||||
public void call() {
|
||||
@ -370,14 +497,14 @@ public class HuaweiFileDownloadManager {
|
||||
|
||||
@Override
|
||||
public void handleException(Request.ResponseParseException e) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadRequestException(null, this.getClass(), e));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadRequestException(null, this.getClass(), e));
|
||||
reset();
|
||||
}
|
||||
});
|
||||
try {
|
||||
getFileParametersRequest.doPerform();
|
||||
} catch (IOException e) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadSendException(currentFileRequest, getFileParametersRequest, e));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadSendException(currentFileRequest, getFileParametersRequest, e));
|
||||
reset();
|
||||
}
|
||||
}
|
||||
@ -390,7 +517,7 @@ public class HuaweiFileDownloadManager {
|
||||
GetFileInfoRequest r = (GetFileInfoRequest) request;
|
||||
if (r.newSync) {
|
||||
if (currentFileRequest.fileId != r.fileId) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadFileMismatchException(currentFileRequest, r.fileId, true));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadFileMismatchException(currentFileRequest, r.fileId, true));
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
@ -412,21 +539,19 @@ public class HuaweiFileDownloadManager {
|
||||
|
||||
@Override
|
||||
public void handleException(Request.ResponseParseException e) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadRequestException(null, this.getClass(), e));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadRequestException(null, this.getClass(), e));
|
||||
reset();
|
||||
}
|
||||
});
|
||||
try {
|
||||
getFileInfoRequest.doPerform();
|
||||
} catch (IOException e) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadSendException(currentFileRequest, getFileInfoRequest, e));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadSendException(currentFileRequest, getFileInfoRequest, e));
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadNextFileBlock() {
|
||||
handler.removeCallbacks(this.timeout);
|
||||
|
||||
if (currentFileRequest.buffer == null) // New file
|
||||
currentFileRequest.buffer = ByteBuffer.allocate(currentFileRequest.fileSize);
|
||||
currentFileRequest.lastPacketNumber = -1; // Counts per block
|
||||
@ -439,6 +564,9 @@ public class HuaweiFileDownloadManager {
|
||||
// Start listening for file data
|
||||
this.supportProvider.addInProgressRequest(fileDataReceiver);
|
||||
|
||||
handler.removeCallbacks(this.timeout);
|
||||
handler.postDelayed(HuaweiFileDownloadManager.this.timeout, currentFileRequest.timeout * 1000L);
|
||||
|
||||
GetFileBlockRequest getFileBlockRequest = new GetFileBlockRequest(supportProvider, currentFileRequest);
|
||||
getFileBlockRequest.setFinalizeReq(new Request.RequestCallback() {
|
||||
@Override
|
||||
@ -451,20 +579,20 @@ public class HuaweiFileDownloadManager {
|
||||
try {
|
||||
getFileBlockRequest.doPerform();
|
||||
} catch (IOException e) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadSendException(currentFileRequest, getFileBlockRequest, e));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadSendException(currentFileRequest, getFileBlockRequest, e));
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFileData(boolean newSync, byte number, byte[] data) {
|
||||
if (newSync && currentFileRequest.fileId != number) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadFileMismatchException(currentFileRequest, number, true));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadFileMismatchException(currentFileRequest, number, true));
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
if (!newSync) {
|
||||
if (currentFileRequest.lastPacketNumber != number - 1) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadFileMismatchException(currentFileRequest, number, false));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadFileMismatchException(currentFileRequest, number, false));
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
@ -496,13 +624,12 @@ public class HuaweiFileDownloadManager {
|
||||
try {
|
||||
getFileDownloadCompleteRequest.doPerform();
|
||||
} catch (IOException e) {
|
||||
supportProvider.downloadException(new HuaweiFileDownloadSendException(currentFileRequest, getFileDownloadCompleteRequest, e));
|
||||
currentFileRequest.fileDownloadCallback.downloadException(new HuaweiFileDownloadSendException(currentFileRequest, getFileDownloadCompleteRequest, e));
|
||||
reset();
|
||||
}
|
||||
|
||||
// Handle file data
|
||||
if (currentFileRequest.buffer != null) // File size was zero
|
||||
supportProvider.downloadComplete(currentFileRequest.filename, currentFileRequest.buffer.array());
|
||||
currentFileRequest.fileDownloadCallback.downloadComplete(currentFileRequest);
|
||||
|
||||
if (!this.currentFileRequest.newSync && !this.fileRequests.isEmpty() && !this.fileRequests.get(0).newSync) {
|
||||
// Old sync can potentially take a shortcut
|
||||
|
@ -30,6 +30,7 @@ import androidx.annotation.NonNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -54,6 +55,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCoordinatorSupplier;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCoordinatorSupplier.HuaweiDeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCrypto;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiGpsParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTruSleepParser;
|
||||
@ -71,6 +73,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.export.ActivityTrackExporter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.export.GPXExporter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProviderType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
@ -79,11 +83,14 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityPoint;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityTrack;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Contact;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.GPSCoordinate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
@ -166,6 +173,8 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetN
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FitnessData;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SetWorkModeRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.MediaManager;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
@ -173,6 +182,48 @@ import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
public class HuaweiSupportProvider {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HuaweiSupportProvider.class);
|
||||
|
||||
private class SyncState {
|
||||
private boolean activitySync = false;
|
||||
private boolean workoutSync = false;
|
||||
private int workoutGpsDownload = 0;
|
||||
|
||||
public void setActivitySync(boolean state) {
|
||||
this.activitySync = state;
|
||||
updateState();
|
||||
}
|
||||
|
||||
public void setWorkoutSync(boolean state) {
|
||||
this.workoutSync = state;
|
||||
updateState();
|
||||
}
|
||||
|
||||
public void startWorkoutGpsDownload() {
|
||||
this.workoutGpsDownload += 1;
|
||||
}
|
||||
|
||||
public void stopWorkoutGpsDownload() {
|
||||
this.workoutGpsDownload -= 1;
|
||||
updateState();
|
||||
}
|
||||
|
||||
public void updateState() {
|
||||
updateState(true);
|
||||
}
|
||||
|
||||
public void updateState(boolean needSync) {
|
||||
if (!activitySync && !workoutSync && workoutGpsDownload == 0) {
|
||||
if (getDevice().isBusy()) {
|
||||
getDevice().unsetBusyTask();
|
||||
getDevice().sendDeviceUpdateIntent(context);
|
||||
}
|
||||
if (needSync)
|
||||
GB.signalActivityDataFinish(getDevice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final SyncState syncState = new SyncState();
|
||||
|
||||
private final int initTimeout = 2000;
|
||||
|
||||
private HuaweiBRSupport brSupport;
|
||||
@ -1097,6 +1148,8 @@ public class HuaweiSupportProvider {
|
||||
}
|
||||
|
||||
private void fetchActivityData() {
|
||||
syncState.setActivitySync(true);
|
||||
|
||||
int sleepStart = 0;
|
||||
int stepStart = 0;
|
||||
final int end = (int) (System.currentTimeMillis() / 1000);
|
||||
@ -1144,13 +1197,13 @@ public class HuaweiSupportProvider {
|
||||
@Override
|
||||
public void call() {
|
||||
if (!downloadTruSleepData(start, end))
|
||||
handleSyncFinished();
|
||||
syncState.setActivitySync(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleException(Request.ResponseParseException e) {
|
||||
LOG.error("Fitness totals exception", e);
|
||||
handleSyncFinished();
|
||||
syncState.setActivitySync(false);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1161,14 +1214,14 @@ public class HuaweiSupportProvider {
|
||||
getFitnessTotalsRequest.doPerform();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Exception on starting fitness totals request", e);
|
||||
handleSyncFinished();
|
||||
syncState.setActivitySync(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleException(Request.ResponseParseException e) {
|
||||
LOG.error("Step data count exception", e);
|
||||
handleSyncFinished();
|
||||
syncState.setActivitySync(false);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1179,14 +1232,14 @@ public class HuaweiSupportProvider {
|
||||
getStepDataCountRequest.doPerform();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Exception on starting step data count request", e);
|
||||
handleSyncFinished();
|
||||
syncState.setActivitySync(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleException(Request.ResponseParseException e) {
|
||||
LOG.error("Sleep data count exception", e);
|
||||
handleSyncFinished();
|
||||
syncState.setActivitySync(false);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1194,11 +1247,13 @@ public class HuaweiSupportProvider {
|
||||
getSleepDataCountRequest.doPerform();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Exception on starting sleep data count request", e);
|
||||
handleSyncFinished();
|
||||
syncState.setActivitySync(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchWorkoutData() {
|
||||
syncState.setWorkoutSync(true);
|
||||
|
||||
int start = 0;
|
||||
int end = (int) (System.currentTimeMillis() / 1000);
|
||||
|
||||
@ -1261,13 +1316,13 @@ public class HuaweiSupportProvider {
|
||||
getWorkoutCountRequest.setFinalizeReq(new RequestCallback() {
|
||||
@Override
|
||||
public void call() {
|
||||
handleSyncFinished();
|
||||
syncState.setWorkoutSync(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleException(Request.ResponseParseException e) {
|
||||
LOG.error("Workout parsing exception", e);
|
||||
handleSyncFinished();
|
||||
syncState.setWorkoutSync(false);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1275,18 +1330,10 @@ public class HuaweiSupportProvider {
|
||||
getWorkoutCountRequest.doPerform();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Exception on starting workout count request", e);
|
||||
handleSyncFinished();
|
||||
syncState.setWorkoutSync(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSyncFinished() {
|
||||
if (gbDevice.isBusy()) {
|
||||
gbDevice.unsetBusyTask();
|
||||
gbDevice.sendDeviceUpdateIntent(context);
|
||||
}
|
||||
GB.signalActivityDataFinish(getDevice());
|
||||
}
|
||||
|
||||
public void onReset(int flags) {
|
||||
try {
|
||||
if(flags== GBDeviceProtocol.RESET_FLAGS_FACTORY_RESET) {
|
||||
@ -1559,7 +1606,8 @@ public class HuaweiSupportProvider {
|
||||
packet.poolLength,
|
||||
packet.laps,
|
||||
packet.avgSwolf,
|
||||
raw
|
||||
raw,
|
||||
null
|
||||
);
|
||||
db.getDaoSession().getHuaweiWorkoutSummarySampleDao().insertOrReplace(summarySample);
|
||||
|
||||
@ -2073,52 +2121,151 @@ public class HuaweiSupportProvider {
|
||||
if (!getHuaweiCoordinator().supportsTruSleep())
|
||||
return false;
|
||||
|
||||
huaweiFileDownloadManager.downloadSleep(
|
||||
huaweiFileDownloadManager.addToQueue(HuaweiFileDownloadManager.FileRequest.sleepStateFileRequest(
|
||||
getHuaweiCoordinator().getSupportsTruSleepNewSync(),
|
||||
"sleep_state.bin", // new String[] {"sleep_state.bin"}, // Later also "sleep_data.bin", but we don't use it right now
|
||||
start,
|
||||
end
|
||||
);
|
||||
end,
|
||||
new HuaweiFileDownloadManager.FileDownloadCallback() {
|
||||
@Override
|
||||
public void downloadComplete(HuaweiFileDownloadManager.FileRequest fileRequest) {
|
||||
if (fileRequest.getData().length != 0) {
|
||||
LOG.debug("Parsing sleep state file");
|
||||
HuaweiTruSleepParser.TruSleepStatus[] results = HuaweiTruSleepParser.parseState(fileRequest.getData());
|
||||
for (HuaweiTruSleepParser.TruSleepStatus status : results)
|
||||
addSleepActivity(status.startTime, status.endTime, (byte) 0x06, (byte) 0x0a);
|
||||
} else
|
||||
LOG.debug("Sleep state file empty");
|
||||
syncState.setActivitySync(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadException(HuaweiFileDownloadManager.HuaweiFileDownloadException e) {
|
||||
super.downloadException(e);
|
||||
syncState.setActivitySync(false);
|
||||
}
|
||||
}
|
||||
), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a file download is complete
|
||||
* @param fileName Filename of the file
|
||||
* @param fileContents Contents of the file
|
||||
*/
|
||||
public void downloadComplete(String fileName, byte[] fileContents) {
|
||||
LOG.debug("File download complete: {}: {}", fileName, GB.hexdump(fileContents));
|
||||
public void downloadWorkoutGpsFiles(short workoutId, Long databaseId) {
|
||||
syncState.startWorkoutGpsDownload();
|
||||
|
||||
if (fileName.equals("sleep_state.bin")) {
|
||||
HuaweiTruSleepParser.TruSleepStatus[] results = HuaweiTruSleepParser.parseState(fileContents);
|
||||
for (HuaweiTruSleepParser.TruSleepStatus status : results)
|
||||
addSleepActivity(status.startTime, status.endTime, (byte) 0x06, (byte) 0x0a);
|
||||
// This should only be called once per sync - also if we start downloading more sleep data
|
||||
GB.signalActivityDataFinish(getDevice());
|
||||
// Unsetting busy is done at the end of all downloads
|
||||
} // "sleep_data.bin" later as well
|
||||
huaweiFileDownloadManager.addToQueue(HuaweiFileDownloadManager.FileRequest.workoutGpsFileRequest(
|
||||
getHuaweiCoordinator().isSupportsGpsNewSync(),
|
||||
workoutId,
|
||||
databaseId,
|
||||
new HuaweiFileDownloadManager.FileDownloadCallback() {
|
||||
@Override
|
||||
public void downloadComplete(HuaweiFileDownloadManager.FileRequest fileRequest) {
|
||||
syncState.stopWorkoutGpsDownload();
|
||||
|
||||
if (fileRequest.getData().length == 0) {
|
||||
LOG.debug("GPS file empty");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.debug("Parsing GPS file");
|
||||
|
||||
HuaweiGpsParser.GpsPoint[] points = HuaweiGpsParser.parseHuaweiGps(fileRequest.getData());
|
||||
|
||||
LOG.debug("Received {} GPS points", points.length);
|
||||
|
||||
if (points.length == 0) {
|
||||
LOG.debug("No GPS points returned");
|
||||
return;
|
||||
}
|
||||
|
||||
ActivityTrack track = new ActivityTrack();
|
||||
|
||||
track.setName("Workout " + fileRequest.getWorkoutId());
|
||||
track.setBaseTime(DateTimeUtils.parseTimeStamp(points[0].timestamp));
|
||||
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
track.setUser(DBHelper.getUser(db.getDaoSession()));
|
||||
track.setDevice(DBHelper.getDevice(gbDevice, db.getDaoSession()));
|
||||
} catch (Exception e) {
|
||||
LOG.error("Cannot acquire DB, set user, or set device for Activity track, continuing anyway");
|
||||
}
|
||||
|
||||
for (HuaweiGpsParser.GpsPoint point : points) {
|
||||
GPSCoordinate coordinate;
|
||||
if (point.altitudeSupported)
|
||||
coordinate = new GPSCoordinate(point.longitude, point.latitude, point.altitude);
|
||||
else
|
||||
coordinate = new GPSCoordinate(point.longitude, point.latitude);
|
||||
|
||||
ActivityPoint activityPoint = new ActivityPoint();
|
||||
activityPoint.setTime(DateTimeUtils.parseTimeStamp(point.timestamp));
|
||||
activityPoint.setLocation(coordinate);
|
||||
|
||||
track.addTrackPoint(activityPoint);
|
||||
}
|
||||
|
||||
String filename = FileUtils.makeValidFileName("workout_" + fileRequest.getWorkoutId() + "_" + points[0].timestamp + ".gpx");
|
||||
File targetFile;
|
||||
try {
|
||||
targetFile = new File(
|
||||
getDevice().getDeviceCoordinator().getWritableExportDirectory(getDevice()),
|
||||
filename
|
||||
);
|
||||
} catch (IOException e) {
|
||||
// TODO: Translatable string
|
||||
GB.toast(context, "Could not open Workout GPS file to write to", Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||
LOG.error("Could not open Workout GPS file to write to", e);
|
||||
return;
|
||||
}
|
||||
|
||||
GPXExporter exporter = new GPXExporter();
|
||||
exporter.setCreator(GBApplication.app().getNameAndVersion());
|
||||
try {
|
||||
exporter.performExport(track, targetFile);
|
||||
} catch (IOException | ActivityTrackExporter.GPXTrackEmptyException e) {
|
||||
// TODO: Translatable string
|
||||
GB.toast(context, "Failed to export Workout GPX file", Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||
LOG.error("Failed to export Workout GPX file", e);
|
||||
return;
|
||||
}
|
||||
|
||||
Long databaseId = fileRequest.getDatabaseId();
|
||||
if (databaseId == null) {
|
||||
// TODO: Translatable string
|
||||
GB.toast(context, "Cannot link GPX to workout", Toast.LENGTH_SHORT, GB.ERROR);
|
||||
LOG.error("Cannot link GPX to workout");
|
||||
return;
|
||||
}
|
||||
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
DaoSession daoSession = db.getDaoSession();
|
||||
HuaweiWorkoutSummarySample sample = daoSession.getHuaweiWorkoutSummarySampleDao().load(databaseId);
|
||||
sample.setGpxFileLocation(targetFile.getAbsolutePath());
|
||||
sample.update();
|
||||
} catch (Exception e) {
|
||||
// TODO: Translatable string
|
||||
GB.toast(context, "Failed to save Workout GPX file location", Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||
LOG.error("Failed to save Workout GPX file location", e);
|
||||
return;
|
||||
}
|
||||
|
||||
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(databaseId);
|
||||
|
||||
LOG.debug("Completed workout GPS parsing and inserting");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadException(HuaweiFileDownloadManager.HuaweiFileDownloadException e) {
|
||||
super.downloadException(e);
|
||||
syncState.stopWorkoutGpsDownload();
|
||||
}
|
||||
}
|
||||
), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when there are no more files left to download
|
||||
*/
|
||||
public void downloadQueueEmpty() {
|
||||
if (gbDevice.isBusy()) {
|
||||
gbDevice.unsetBusyTask();
|
||||
gbDevice.sendDeviceUpdateIntent(context);
|
||||
}
|
||||
}
|
||||
|
||||
public void downloadException(HuaweiFileDownloadManager.HuaweiFileDownloadException e) {
|
||||
GB.toast("Error downloading file", Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||
if (e.fileRequest != null)
|
||||
LOG.error("Error downloading file: {}{}", e.fileRequest.filename, e.fileRequest.newSync ? " (newsync)" : "", e);
|
||||
else
|
||||
LOG.error("Error in file download", e);
|
||||
|
||||
// We also reset the sync state, just to get back to working as nicely as possible
|
||||
handleSyncFinished();
|
||||
public void downloadQueueEmpty(boolean needSync) {
|
||||
syncState.updateState(needSync);
|
||||
}
|
||||
|
||||
public void onTestNewFunction() {
|
||||
@ -2126,17 +2273,27 @@ public class HuaweiSupportProvider {
|
||||
gbDevice.setBusyTask("Downloading file...");
|
||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||
|
||||
huaweiFileDownloadManager.downloadSleep(
|
||||
huaweiFileDownloadManager.addToQueue(HuaweiFileDownloadManager.FileRequest.sleepStateFileRequest(
|
||||
getHuaweiCoordinator().getSupportsTruSleepNewSync(),
|
||||
"sleep_state.bin",
|
||||
0,
|
||||
(int) (System.currentTimeMillis() / 1000)
|
||||
);
|
||||
huaweiFileDownloadManager.downloadSleep(
|
||||
(int) (System.currentTimeMillis() / 1000),
|
||||
new HuaweiFileDownloadManager.FileDownloadCallback() {
|
||||
@Override
|
||||
public void downloadComplete(HuaweiFileDownloadManager.FileRequest fileRequest) {
|
||||
// Handle file contents
|
||||
}
|
||||
}
|
||||
), true);
|
||||
huaweiFileDownloadManager.addToQueue(HuaweiFileDownloadManager.FileRequest.sleepDataFileRequest(
|
||||
getHuaweiCoordinator().getSupportsTruSleepNewSync(),
|
||||
"sleep_data.bin",
|
||||
0,
|
||||
(int) (System.currentTimeMillis() / 1000)
|
||||
);
|
||||
(int) (System.currentTimeMillis() / 1000),
|
||||
new HuaweiFileDownloadManager.FileDownloadCallback() {
|
||||
@Override
|
||||
public void downloadComplete(HuaweiFileDownloadManager.FileRequest fileRequest) {
|
||||
// Handle file contents
|
||||
}
|
||||
}
|
||||
), true);
|
||||
}
|
||||
}
|
||||
|
@ -304,6 +304,10 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
||||
}
|
||||
|
||||
public void parseWorkout(Long workoutId) {
|
||||
LOG.debug("Parsing workout ID {}", workoutId);
|
||||
if (workoutId == null)
|
||||
return;
|
||||
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
final DaoSession session = db.getDaoSession();
|
||||
final Device device = DBHelper.getDevice(gbDevice, session);
|
||||
@ -718,6 +722,11 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
||||
if (baseSummary.getName() == null) {
|
||||
baseSummary.setName("Workout " + summary.getWorkoutNumber());
|
||||
}
|
||||
|
||||
if (baseSummary.getGpxTrack() == null) {
|
||||
baseSummary.setGpxTrack(summary.getGpxFileLocation());
|
||||
}
|
||||
|
||||
// start time never changes
|
||||
baseSummary.setEndTime(new Date(summary.getEndTimestamp() * 1000L));
|
||||
baseSummary.setActivityKind(type.getCode());
|
||||
|
@ -29,7 +29,7 @@ public class GetFileBlockRequest extends Request {
|
||||
|
||||
public GetFileBlockRequest(HuaweiSupportProvider support, HuaweiFileDownloadManager.FileRequest request) {
|
||||
super(support);
|
||||
if (request.newSync) {
|
||||
if (request.isNewSync()) {
|
||||
this.serviceId = FileDownloadService2C.id;
|
||||
this.commandId = FileDownloadService2C.RequestBlock.id;
|
||||
} else {
|
||||
@ -42,20 +42,20 @@ public class GetFileBlockRequest extends Request {
|
||||
@Override
|
||||
protected List<byte[]> createRequest() throws Request.RequestCreationException {
|
||||
try {
|
||||
if (this.request.newSync)
|
||||
if (this.request.isNewSync())
|
||||
return new FileDownloadService2C.RequestBlock(
|
||||
paramsProvider,
|
||||
this.request.fileId,
|
||||
this.request.buffer.position(),
|
||||
this.request.currentBlockSize,
|
||||
this.request.noEncrypt
|
||||
this.request.getFileId(),
|
||||
this.request.getCurrentOffset(),
|
||||
this.request.getCurrentBlockSize(),
|
||||
this.request.isNoEncrypt()
|
||||
).serialize();
|
||||
else
|
||||
return new FileDownloadService0A.RequestBlock.Request(
|
||||
paramsProvider,
|
||||
this.request.filename,
|
||||
this.request.buffer.position(),
|
||||
this.request.currentBlockSize
|
||||
this.request.getFilename(),
|
||||
this.request.getCurrentOffset(),
|
||||
this.request.getCurrentBlockSize()
|
||||
).serialize();
|
||||
} catch (HuaweiPacket.CryptoException e) {
|
||||
throw new Request.RequestCreationException(e);
|
||||
|
@ -30,7 +30,7 @@ public class GetFileDownloadCompleteRequest extends Request {
|
||||
|
||||
public GetFileDownloadCompleteRequest(HuaweiSupportProvider support, HuaweiFileDownloadManager.FileRequest request) {
|
||||
super(support);
|
||||
if (request.newSync) {
|
||||
if (request.isNewSync()) {
|
||||
this.serviceId = FileDownloadService2C.id;
|
||||
this.commandId = FileDownloadService2C.FileDownloadCompleteRequest.id;
|
||||
} else {
|
||||
@ -43,8 +43,8 @@ public class GetFileDownloadCompleteRequest extends Request {
|
||||
@Override
|
||||
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||
try {
|
||||
if (request.newSync)
|
||||
return new FileDownloadService2C.FileDownloadCompleteRequest(paramsProvider, this.request.fileId).serialize();
|
||||
if (request.isNewSync())
|
||||
return new FileDownloadService2C.FileDownloadCompleteRequest(paramsProvider, this.request.getFileId()).serialize();
|
||||
else
|
||||
return new FileDownloadService0A.FileDownloadCompleteRequest(paramsProvider).serialize();
|
||||
} catch (HuaweiPacket.CryptoException e) {
|
||||
|
@ -41,7 +41,7 @@ public class GetFileDownloadInitRequest extends Request {
|
||||
|
||||
public GetFileDownloadInitRequest(HuaweiSupportProvider support, HuaweiFileDownloadManager.FileRequest request) {
|
||||
super(support);
|
||||
if (request.newSync) {
|
||||
if (request.isNewSync()) {
|
||||
this.serviceId = FileDownloadService2C.id;
|
||||
this.commandId = FileDownloadService2C.FileDownloadInit.id;
|
||||
} else {
|
||||
@ -57,6 +57,8 @@ public class GetFileDownloadInitRequest extends Request {
|
||||
return FileDownloadService2C.FileType.SLEEP_STATE;
|
||||
case SLEEP_DATA:
|
||||
return FileDownloadService2C.FileType.SLEEP_DATA;
|
||||
case GPS:
|
||||
return FileDownloadService2C.FileType.GPS;
|
||||
default:
|
||||
return FileDownloadService2C.FileType.UNKNOWN;
|
||||
}
|
||||
@ -68,6 +70,8 @@ public class GetFileDownloadInitRequest extends Request {
|
||||
return HuaweiFileDownloadManager.FileType.SLEEP_STATE;
|
||||
case SLEEP_DATA:
|
||||
return HuaweiFileDownloadManager.FileType.SLEEP_DATA;
|
||||
case GPS:
|
||||
return HuaweiFileDownloadManager.FileType.GPS;
|
||||
default:
|
||||
return HuaweiFileDownloadManager.FileType.UNKNOWN;
|
||||
}
|
||||
@ -76,16 +80,18 @@ public class GetFileDownloadInitRequest extends Request {
|
||||
@Override
|
||||
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||
try {
|
||||
if (this.request.newSync) {
|
||||
FileDownloadService2C.FileType type = convertFileTypeTo2C(request.fileType);
|
||||
if (this.request.isNewSync()) {
|
||||
FileDownloadService2C.FileType type = convertFileTypeTo2C(request.getFileType());
|
||||
if (type == FileDownloadService2C.FileType.UNKNOWN)
|
||||
throw new RequestCreationException("Cannot convert type " + request.fileType);
|
||||
return new FileDownloadService2C.FileDownloadInit.Request(paramsProvider, request.filename, type, request.startTime, request.endTime).serialize();
|
||||
throw new RequestCreationException("Cannot convert type " + request.getFileType());
|
||||
return new FileDownloadService2C.FileDownloadInit.Request(paramsProvider, request.getFilename(), type, request.getStartTime(), request.getEndTime()).serialize();
|
||||
} else {
|
||||
if (this.request.fileType == HuaweiFileDownloadManager.FileType.DEBUG)
|
||||
if (this.request.getFileType() == HuaweiFileDownloadManager.FileType.DEBUG)
|
||||
return new FileDownloadService0A.FileDownloadInit.DebugFilesRequest(paramsProvider).serialize();
|
||||
else if (this.request.fileType == HuaweiFileDownloadManager.FileType.SLEEP_STATE)
|
||||
return new FileDownloadService0A.FileDownloadInit.SleepFilesRequest(paramsProvider, request.startTime, request.endTime).serialize();
|
||||
else if (this.request.getFileType() == HuaweiFileDownloadManager.FileType.SLEEP_STATE)
|
||||
return new FileDownloadService0A.FileDownloadInit.SleepFilesRequest(paramsProvider, request.getStartTime(), request.getEndTime()).serialize();
|
||||
else if (this.request.getFileType() == HuaweiFileDownloadManager.FileType.GPS)
|
||||
return new FileDownloadService0A.FileDownloadInit.GpsFileRequest(paramsProvider, request.getWorkoutId()).serialize();
|
||||
else
|
||||
throw new RequestCreationException("Unknown file type");
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ public class GetFileInfoRequest extends Request {
|
||||
|
||||
public GetFileInfoRequest(HuaweiSupportProvider support, HuaweiFileDownloadManager.FileRequest request) {
|
||||
super(support);
|
||||
if (request.newSync) {
|
||||
if (request.isNewSync()) {
|
||||
this.serviceId = FileDownloadService2C.id;
|
||||
this.commandId = FileDownloadService2C.FileInfo.id;
|
||||
} else {
|
||||
@ -53,10 +53,10 @@ public class GetFileInfoRequest extends Request {
|
||||
@Override
|
||||
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||
try {
|
||||
if (this.request.newSync)
|
||||
return new FileDownloadService2C.FileInfo.Request(paramsProvider, this.request.fileId).serialize();
|
||||
if (this.request.isNewSync())
|
||||
return new FileDownloadService2C.FileInfo.Request(paramsProvider, this.request.getFileId()).serialize();
|
||||
else
|
||||
return new FileDownloadService0A.FileInfo.Request(paramsProvider, this.request.filename).serialize();
|
||||
return new FileDownloadService0A.FileInfo.Request(paramsProvider, this.request.getFilename()).serialize();
|
||||
} catch (HuaweiPacket.CryptoException e) {
|
||||
throw new RequestCreationException(e);
|
||||
}
|
||||
|
@ -24,19 +24,22 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupport
|
||||
|
||||
public class GetFileParametersRequest extends Request {
|
||||
|
||||
private final boolean truSleep;
|
||||
|
||||
private int maxBlockSize;
|
||||
private int timeout;
|
||||
|
||||
public GetFileParametersRequest(HuaweiSupportProvider support) {
|
||||
public GetFileParametersRequest(HuaweiSupportProvider support, boolean truSleep) {
|
||||
super(support);
|
||||
this.serviceId = FileDownloadService0A.id;
|
||||
this.commandId = FileDownloadService0A.FileParameters.id;
|
||||
this.truSleep = truSleep;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||
try {
|
||||
return new FileDownloadService0A.FileParameters.Request(paramsProvider).serialize();
|
||||
return new FileDownloadService0A.FileParameters.Request(paramsProvider, truSleep).serialize();
|
||||
} catch (HuaweiPacket.CryptoException e) {
|
||||
throw new RequestCreationException(e);
|
||||
}
|
||||
|
@ -56,5 +56,6 @@ public class GetSettingRelatedRequest extends Request {
|
||||
LOG.debug("handle Setting Related");
|
||||
|
||||
supportProvider.getHuaweiCoordinator().setSupportsTruSleepNewSync(((DeviceConfig.SettingRelated.Response) receivedPacket).truSleepNewSync);
|
||||
supportProvider.getHuaweiCoordinator().setSupportsGpsNewSync(((DeviceConfig.SettingRelated.Response) receivedPacket).gpsNewSync);
|
||||
}
|
||||
}
|
||||
|
@ -113,6 +113,7 @@ public class GetWorkoutDataRequest extends Request {
|
||||
this.nextRequest(nextRequest);
|
||||
} else {
|
||||
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(this.databaseId);
|
||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId);
|
||||
|
||||
if (!remainder.isEmpty()) {
|
||||
GetWorkoutTotalsRequest nextRequest = new GetWorkoutTotalsRequest(
|
||||
|
@ -90,6 +90,7 @@ public class GetWorkoutPaceRequest extends Request {
|
||||
this.nextRequest(nextRequest);
|
||||
} else {
|
||||
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(this.databaseId);
|
||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId);
|
||||
|
||||
if (!remainder.isEmpty()) {
|
||||
GetWorkoutTotalsRequest nextRequest = new GetWorkoutTotalsRequest(
|
||||
|
@ -104,6 +104,7 @@ public class GetWorkoutTotalsRequest extends Request {
|
||||
this.nextRequest(nextRequest);
|
||||
} else {
|
||||
new HuaweiWorkoutGbParser(getDevice()).parseWorkout(databaseId);
|
||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, databaseId);
|
||||
|
||||
if (!remainder.isEmpty()) {
|
||||
GetWorkoutTotalsRequest nextRequest = new GetWorkoutTotalsRequest(
|
||||
|
Loading…
Reference in New Issue
Block a user