From af64ff3a793c4f923bce27f12938aab960e78b14 Mon Sep 17 00:00:00 2001 From: Me7c7 Date: Thu, 10 Oct 2024 21:23:34 +0300 Subject: [PATCH] Huawei: fix workouts pace --- .../gadgetbridge/daogen/GBDaoGenerator.java | 6 +- .../schema/GadgetbridgeUpdate_83.java | 47 +++++++++++ .../devices/huawei/packets/Workout.java | 10 ++- .../devices/huawei/HuaweiSupportProvider.java | 84 +++++++++++-------- .../devices/huawei/HuaweiWorkoutGbParser.java | 31 ++++--- 5 files changed, 128 insertions(+), 50 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_83.java diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java index 322f25086..7a3b2e5ac 100644 --- a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java +++ b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java @@ -54,7 +54,7 @@ public class GBDaoGenerator { public static void main(String[] args) throws Exception { - final Schema schema = new Schema(82, MAIN_PACKAGE + ".entities"); + final Schema schema = new Schema(83, MAIN_PACKAGE + ".entities"); Entity userAttributes = addUserAttributes(schema); Entity user = addUserInfo(schema, userAttributes); @@ -1418,10 +1418,12 @@ public class GBDaoGenerator { Property id = workoutPaceSample.addLongProperty("workoutId").primaryKey().notNull().getProperty(); workoutPaceSample.addToOne(summaryEntity, id); + workoutPaceSample.addIntProperty("paceIndex").notNull().primaryKey(); workoutPaceSample.addIntProperty("distance").notNull().primaryKey(); workoutPaceSample.addByteProperty("type").notNull().primaryKey(); workoutPaceSample.addIntProperty("pace").notNull(); - workoutPaceSample.addIntProperty("correction").notNull(); + workoutPaceSample.addIntProperty("pointIndex").notNull(); + workoutPaceSample.addIntProperty("correction"); return workoutPaceSample; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_83.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_83.java new file mode 100644 index 000000000..defa85732 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_83.java @@ -0,0 +1,47 @@ +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.HuaweiWorkoutPaceSampleDao; + +public class GadgetbridgeUpdate_83 implements DBUpdateScript { + @Override + public void upgradeSchema(final SQLiteDatabase db) { + if (!DBHelper.existsColumn(HuaweiWorkoutPaceSampleDao.TABLENAME, HuaweiWorkoutPaceSampleDao.Properties.PaceIndex.columnName, db) && !DBHelper.existsColumn(HuaweiWorkoutPaceSampleDao.TABLENAME, HuaweiWorkoutPaceSampleDao.Properties.PointIndex.columnName, db)) { + String MOVE_DATA_TO_TEMP_TABLE = "ALTER TABLE " + HuaweiWorkoutPaceSampleDao.TABLENAME + " RENAME TO " +HuaweiWorkoutPaceSampleDao.TABLENAME + "_temp;"; + db.execSQL(MOVE_DATA_TO_TEMP_TABLE); + + String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS \"" + HuaweiWorkoutPaceSampleDao.TABLENAME + + "\" (\""+HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.columnName+"\" INTEGER NOT NULL ," + + "\""+ HuaweiWorkoutPaceSampleDao.Properties.PaceIndex.columnName +"\" INTEGER NOT NULL ," + + "\""+ HuaweiWorkoutPaceSampleDao.Properties.Distance.columnName +"\" INTEGER NOT NULL ," + + "\""+ HuaweiWorkoutPaceSampleDao.Properties.Type.columnName +"\" INTEGER NOT NULL ," + + "\""+ HuaweiWorkoutPaceSampleDao.Properties.Pace.columnName +"\" INTEGER NOT NULL ," + + "\""+ HuaweiWorkoutPaceSampleDao.Properties.PointIndex.columnName +"\" INTEGER NOT NULL ," + + "\""+ HuaweiWorkoutPaceSampleDao.Properties.Correction.columnName +"\" INTEGER ," + + "PRIMARY KEY (\""+HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.columnName+"\" ,\""+ HuaweiWorkoutPaceSampleDao.Properties.PaceIndex.columnName +"\" ,\""+ HuaweiWorkoutPaceSampleDao.Properties.Distance.columnName +"\", \""+ HuaweiWorkoutPaceSampleDao.Properties.Type.columnName +"\") ON CONFLICT REPLACE) WITHOUT ROWID;"; + db.execSQL(CREATE_TABLE); + + String MIGATE_DATA = "INSERT INTO " + HuaweiWorkoutPaceSampleDao.TABLENAME + + " (" +HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.columnName+ "," + + HuaweiWorkoutPaceSampleDao.Properties.PaceIndex.columnName + "," + + HuaweiWorkoutPaceSampleDao.Properties.Distance.columnName+ "," + + HuaweiWorkoutPaceSampleDao.Properties.Type.columnName + "," + + HuaweiWorkoutPaceSampleDao.Properties.Pace.columnName + "," + + HuaweiWorkoutPaceSampleDao.Properties.PointIndex.columnName + "," + + HuaweiWorkoutPaceSampleDao.Properties.Correction.columnName + ") " + + " SELECT WORKOUT_ID, 0, DISTANCE, TYPE, PACE, 0, CORRECTION FROM " +HuaweiWorkoutPaceSampleDao.TABLENAME + "_temp;"; + + db.execSQL(MIGATE_DATA); + + String DROP_TEMP_TABLE = "drop table if exists " +HuaweiWorkoutPaceSampleDao.TABLENAME + "_temp;"; + db.execSQL(DROP_TEMP_TABLE); + } + } + + @Override + public void downgradeSchema(final SQLiteDatabase db) { + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Workout.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Workout.java index 74753e94e..1ed3e6dfb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Workout.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Workout.java @@ -475,7 +475,9 @@ public class Workout { public short distance = -1; public byte type = -1; public int pace = -1; + public short pointIndex = 0; public short correction = 0; + public boolean hasCorrection = false; @Override public String toString() { @@ -483,7 +485,9 @@ public class Workout { "distance=" + distance + ", type=" + type + ", pace=" + pace + + ", pointIndex=" + pointIndex + ", correction=" + correction + + ", hasCorrection=" + hasCorrection + '}'; } } @@ -509,8 +513,12 @@ public class Workout { block.distance = blockTlv.getShort(0x04); block.type = blockTlv.getByte(0x05); block.pace = blockTlv.getInteger(0x06); - if (blockTlv.contains(0x09)) + if (blockTlv.contains(0x07)) + block.pointIndex = blockTlv.getShort(0x07); + if (blockTlv.contains(0x09)) { + block.hasCorrection = true; block.correction = blockTlv.getShort(0x09); + } blocks.add(block); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java index 44a4b00f4..8cce53cd1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java @@ -38,6 +38,7 @@ import java.util.List; import java.util.Random; import java.util.UUID; +import de.greenrobot.dao.query.DeleteQuery; import de.greenrobot.dao.query.QueryBuilder; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; @@ -463,7 +464,7 @@ public class HuaweiSupportProvider { RequestCallback finalizeReq = new RequestCallback() { @Override public void call() { - int status = (int)deviceStatusReq.status; + int status = (int) deviceStatusReq.status; if (status == -0x01 || status == 0x00 || status == 0x01) { initializeDeviceDealHiChain(linkParamsReq); } else { @@ -477,7 +478,7 @@ public class HuaweiSupportProvider { } }; if (huaweiType == HuaweiDeviceType.BLE) { //Only BLE known, check later for AW and SMART - initializeDeviceDealHiChain(linkParamsReq); + initializeDeviceDealHiChain(linkParamsReq); } else { deviceStatusReq.setFinalizeReq(finalizeReq); deviceStatusReq.doPerform(); @@ -515,10 +516,10 @@ public class HuaweiSupportProvider { try { if (isHiChain()) { - if (paramsProvider.getDeviceSupportType() == 4 ) - paramsProvider.setAuthMode((byte)4); + if (paramsProvider.getDeviceSupportType() == 4) + paramsProvider.setAuthMode((byte) 4); else - paramsProvider.setAuthMode((byte)2); + paramsProvider.setAuthMode((byte) 2); final GetSecurityNegotiationRequest securityNegoReq = new GetSecurityNegotiationRequest(this); RequestCallback securityFinalizeReq = new RequestCallback(this) { @Override @@ -546,13 +547,15 @@ public class HuaweiSupportProvider { } } - protected void initializeDeviceNotify() {} //TODO + protected void initializeDeviceNotify() { + } //TODO RequestCallback configureReq = new RequestCallback() { @Override public void call() { initializeDeviceConfigure(); } + @Override public void timeout(Request request) { LOG.error("Authentication timed out"); @@ -563,6 +566,7 @@ public class HuaweiSupportProvider { GBApplication.deviceService(device).disconnect(); } } + @Override public void handleException(Request.ResponseParseException e) { LOG.error("Authentication exception", e); @@ -736,7 +740,7 @@ public class HuaweiSupportProvider { protected void createRandomMacAddress() { SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(deviceMac); - macAddress = sharedPrefs.getString(HuaweiConstants.PREF_HUAWEI_ADDRESS, null); + macAddress = sharedPrefs.getString(HuaweiConstants.PREF_HUAWEI_ADDRESS, null); if (macAddress == null || macAddress.isEmpty()) { StringBuilder mac = new StringBuilder("FF:FF:FF"); Random r = new Random(); @@ -766,7 +770,7 @@ public class HuaweiSupportProvider { protected void createAndroidID() { SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(deviceMac); - androidID = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_FAKE_ANDROID_ID, null); + androidID = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_FAKE_ANDROID_ID, null); if (androidID == null || androidID.isEmpty()) { androidID = StringUtils.bytesToHex(HuaweiCrypto.generateNonce()); LOG.debug("Created androidID: " + androidID); @@ -841,7 +845,7 @@ public class HuaweiSupportProvider { // Queue all the requests for (int i = 1; i < initRequestQueue.size(); i++) { initRequestQueue.get(i - 1).setupTimeoutUntilNext(initTimeout); - if(initRequestQueue.get(i - 1) instanceof SendSetUpDeviceStatusRequest) { + if (initRequestQueue.get(i - 1) instanceof SendSetUpDeviceStatusRequest) { // NOTE: The watch is never answer to this command. To decrease init time timeout for it is 50 ms initRequestQueue.get(i - 1).setupTimeoutUntilNext(50); } @@ -855,8 +859,8 @@ public class HuaweiSupportProvider { gbDevice.setState(GBDevice.State.INITIALIZED); gbDevice.sendDeviceUpdateIntent(getContext(), GBDevice.DeviceUpdateSubject.DEVICE_STATE); - if(getHuaweiCoordinator().supportsP2PService()) { - if(getHuaweiCoordinator().supportsCalendar()) { + if (getHuaweiCoordinator().supportsP2PService()) { + if (getHuaweiCoordinator().supportsCalendar()) { if (HuaweiP2PCalendarService.getRegisteredInstance(huaweiP2PManager) == null) { HuaweiP2PCalendarService calendarService = new HuaweiP2PCalendarService(huaweiP2PManager); calendarService.register(); @@ -980,7 +984,7 @@ public class HuaweiSupportProvider { } public void onSocketRead(byte[] data) { - responseManager.handleData(data); + responseManager.handleData(data); } public void removeInProgressRequests(Request req) { @@ -1342,7 +1346,7 @@ public class HuaweiSupportProvider { public void onReset(int flags) { try { - if(flags== GBDeviceProtocol.RESET_FLAGS_FACTORY_RESET) { + if (flags == GBDeviceProtocol.RESET_FLAGS_FACTORY_RESET) { SendFactoryResetRequest sendFactoryResetReq = new SendFactoryResetRequest(this); sendFactoryResetReq.doPerform(); } @@ -1453,9 +1457,9 @@ public class HuaweiSupportProvider { } } else if ( callSpec.command == CallSpec.CALL_ACCEPT || - callSpec.command == CallSpec.CALL_START || - callSpec.command == CallSpec.CALL_REJECT || - callSpec.command == CallSpec.CALL_END + callSpec.command == CallSpec.CALL_START || + callSpec.command == CallSpec.CALL_REJECT || + callSpec.command == CallSpec.CALL_END ) { StopNotificationRequest stopNotificationRequest = new StopNotificationRequest(this); try { @@ -1675,13 +1679,23 @@ public class HuaweiSupportProvider { try (DBHandler db = GBApplication.acquireDB()) { HuaweiWorkoutPaceSampleDao dao = db.getDaoSession().getHuaweiWorkoutPaceSampleDao(); + final DeleteQuery tableDeleteQuery = dao.queryBuilder() + .where(HuaweiWorkoutPaceSampleDao.Properties.WorkoutId.eq(workoutId)) + .buildDelete(); + tableDeleteQuery.executeDeleteWithoutDetachingEntities(); + + int paceIndex = 0; for (Workout.WorkoutPace.Response.Block block : paceList) { + + Integer correction = block.hasCorrection ? (int) block.correction : null; HuaweiWorkoutPaceSample paceSample = new HuaweiWorkoutPaceSample( workoutId, + paceIndex++, block.distance, block.type, block.pace, - block.correction + block.pointIndex, + correction ); dao.insertOrReplace(paceSample); } @@ -1773,14 +1787,14 @@ public class HuaweiSupportProvider { } public void setTemperatureUnit() { - try { - SetTemperatureUnitSetting setTemperatureUnitSetting = new SetTemperatureUnitSetting(this); - setTemperatureUnitSetting.doPerform(); - } catch (IOException e) { - // TODO: Use translatable string - GB.toast(context, "Failed to set temperature unit", Toast.LENGTH_SHORT, GB.ERROR, e); - LOG.error("Failed to configure TemperatureUnitSetting", e); - } + try { + SetTemperatureUnitSetting setTemperatureUnitSetting = new SetTemperatureUnitSetting(this); + setTemperatureUnitSetting.doPerform(); + } catch (IOException e) { + // TODO: Use translatable string + GB.toast(context, "Failed to set temperature unit", Toast.LENGTH_SHORT, GB.ERROR, e); + LOG.error("Failed to configure TemperatureUnitSetting", e); + } } public void setContinuousSkinTemperatureMeasurement() { @@ -1920,7 +1934,7 @@ public class HuaweiSupportProvider { } public void onInstallApp(Uri uri) { - LOG.info("enter onAppInstall uri: "+uri); + LOG.info("enter onAppInstall uri: " + uri); HuaweiFwHelper huaweiFwHelper = new HuaweiFwHelper(uri, getContext()); HuaweiUploadManager.FileUploadInfo fileInfo = new HuaweiUploadManager.FileUploadInfo(); @@ -1999,6 +2013,7 @@ public class HuaweiSupportProvider { LOG.error("Failed to update progress notification", e); } } + private List gbWatchFaces = null; private List gbWatchApps = null; @@ -2011,11 +2026,12 @@ public class HuaweiSupportProvider { this.gbWatchApps = gbWatchApps; updateAppList(); } + private void updateAppList() { - ArrayList gbDeviceApps=new ArrayList<>(); - if(this.gbWatchFaces != null) + ArrayList gbDeviceApps = new ArrayList<>(); + if (this.gbWatchFaces != null) gbDeviceApps.addAll(this.gbWatchFaces); - if(this.gbWatchApps != null) + if (this.gbWatchApps != null) gbDeviceApps.addAll(this.gbWatchApps); final GBDeviceEventAppInfo appInfoCmd = new GBDeviceEventAppInfo(); appInfoCmd.apps = gbDeviceApps.toArray(new GBDeviceApp[0]); @@ -2028,11 +2044,11 @@ public class HuaweiSupportProvider { huaweiWatchfaceManager.requestWatchfaceList(); huaweiAppManager.requestAppList(); } - + public void onAppStart(final UUID uuid, boolean start) { if (start) { //NOTE: to prevent exception in watchfaces code - if(!huaweiAppManager.startApp(uuid)) { + if (!huaweiAppManager.startApp(uuid)) { huaweiWatchfaceManager.setWatchface(uuid); } } @@ -2040,7 +2056,7 @@ public class HuaweiSupportProvider { public void onAppDelete(final UUID uuid) { //NOTE: to prevent exception in watchfaces code - if(!huaweiAppManager.deleteApp(uuid)){ + if (!huaweiAppManager.deleteApp(uuid)) { huaweiWatchfaceManager.deleteWatchface(uuid); } } @@ -2092,14 +2108,14 @@ public class HuaweiSupportProvider { public void onAddCalendarEvent(final CalendarEventSpec calendarEventSpec) { HuaweiP2PCalendarService service = HuaweiP2PCalendarService.getRegisteredInstance(huaweiP2PManager); - if(service != null) { + if (service != null) { service.onAddCalendarEvent(calendarEventSpec); } } public void onDeleteCalendarEvent(final byte type, long id) { HuaweiP2PCalendarService service = HuaweiP2PCalendarService.getRegisteredInstance(huaweiP2PManager); - if(service != null) { + if (service != null) { service.onDeleteCalendarEvent(type, id); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWorkoutGbParser.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWorkoutGbParser.java index c173bcb21..ae388b3a4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWorkoutGbParser.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWorkoutGbParser.java @@ -35,6 +35,7 @@ import de.greenrobot.dao.query.CloseableListIterator; import de.greenrobot.dao.query.QueryBuilder; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.SettingsActivity; import nodomain.freeyourgadget.gadgetbridge.activities.workouts.entries.ActivitySummaryTableRowEntry; import nodomain.freeyourgadget.gadgetbridge.activities.workouts.entries.ActivitySummaryValue; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; @@ -661,25 +662,30 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser { Arrays.asList( new ActivitySummaryValue("#", ActivitySummaryEntries.UNIT_RAW_STRING), new ActivitySummaryValue("distance"), - new ActivitySummaryValue("watchface_dialog_widget_type"), - new ActivitySummaryValue("Pace"), - new ActivitySummaryValue("paceCorrection") + new ActivitySummaryValue("Pace") ), true, true ) ); + String measurementSystem = GBApplication.getPrefs().getString(SettingsActivity.PREF_MEASUREMENT_SYSTEM, "metric"); + + byte unitType = (byte) (measurementSystem.equals("metric")?0:1); try (CloseableListIterator it = qbPace.build().listIterator()) { HashMap typeCount = new HashMap<>(); HashMap typePace = new HashMap<>(); + int currentIndex = 1; while (it.hasNext()) { int index = it.nextIndex(); HuaweiWorkoutPaceSample sample = it.next(); - int count = 1; + if(sample.getType() != unitType) + continue; + int pace = sample.getPace(); + int count = 1; Integer previousCount = typeCount.get(sample.getType()); Integer previousPace = typePace.get(sample.getType()); @@ -689,19 +695,18 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser { pace += previousPace; typeCount.put(sample.getType(), count); typePace.put(sample.getType(), pace); + double distance = sample.getDistance(); + + if(sample.getCorrection() != null) { + distance += sample.getCorrection() / 10000d; + } final List columns = new LinkedList<>(); - columns.add(new ActivitySummaryValue(index, ActivitySummaryEntries.UNIT_NONE)); - columns.add(new ActivitySummaryValue(sample.getDistance(), ActivitySummaryEntries.UNIT_KILOMETERS)); - columns.add(new ActivitySummaryValue(sample.getType(), ActivitySummaryEntries.UNIT_NONE)); // TODO: find out types + // TODO: add proper units for type == 1. MILES and SECONDS PER MILE + columns.add(new ActivitySummaryValue(currentIndex++, ActivitySummaryEntries.UNIT_NONE)); + columns.add(new ActivitySummaryValue(distance, ActivitySummaryEntries.UNIT_KILOMETERS)); columns.add(new ActivitySummaryValue(sample.getPace(), ActivitySummaryEntries.UNIT_SECONDS_PER_KM)); - if (sample.getCorrection() != 0) { - columns.add(new ActivitySummaryValue(sample.getCorrection() / 10f, ActivitySummaryEntries.UNIT_METERS)); - } else { - columns.add(new ActivitySummaryValue("stats_empty_value")); - } - pacesTable.put("paces_table_" + index, new ActivitySummaryTableRowEntry( ActivitySummaryEntries.GROUP_PACE,