diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ce456b0e..97225ad73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ###Changelog +###Version 0.19.1 +* Fix crash at startup +* HPlus: Improve reconnection to device +* Improve transliteration + ###Version 0.19.0 * Pebble: allow calendar sync with Timeline (Title, Location, Description) * Pebble: display calendar icon for reminders from AOSP Calendar diff --git a/app/build.gradle b/app/build.gradle index c9dcfd13c..71795f898 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,8 +26,8 @@ android { targetSdkVersion 25 // note: always bump BOTH versionCode and versionName! - versionName "0.19.0" - versionCode 93 + versionName "0.19.1" + versionCode 94 vectorDrawables.useSupportLibrary = true } buildTypes { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index 69b6efc1e..626b305b8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -139,6 +139,13 @@ public class GBApplication extends Application { prefs = new Prefs(sharedPrefs); gbPrefs = new GBPrefs(prefs); + if (!GBEnvironment.isEnvironmentSetup()) { + GBEnvironment.setupEnvironment(GBEnvironment.createDeviceEnvironment()); + // setup db after the environment is set up, but don't do it in test mode + // in test mode, it's done individually, see TestBase + setupDatabase(); + } + // don't do anything here before we set up logging, otherwise // slf4j may be implicitly initialized before we properly configured it. setupLogging(isFileLoggingEnabled()); @@ -149,13 +156,6 @@ public class GBApplication extends Application { setupExceptionHandler(); - if (!GBEnvironment.isEnvironmentSetup()) { - GBEnvironment.setupEnvironment(GBEnvironment.createDeviceEnvironment()); - // setup db after the environment is set up, but don't do it in test mode - // in test mode, it's done individually, see TestBase - setupDatabase(); - } - deviceManager = new DeviceManager(this); deviceService = createDeviceService(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java index 953951183..40713a897 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java @@ -121,6 +121,9 @@ public final class HPlusConstants { public static final byte DATA_DAY_SUMMARY_ALT = 0x39; public static final byte DATA_SLEEP = 0x1A; public static final byte DATA_VERSION = 0x18; + public static final byte DATA_VERSION1 = 0x2E; + + public static final byte DATA_UNKNOWN = 0x4d; public static final String PREF_HPLUS_SCREENTIME = "hplus_screentime"; public static final String PREF_HPLUS_ALLDAYHR = "hplus_alldayhr"; @@ -130,60 +133,61 @@ public final class HPlusConstants { public static final String PREF_HPLUS_SIT_START_TIME = "hplus_sit_start_time"; public static final String PREF_HPLUS_SIT_END_TIME = "hplus_sit_end_time"; - public static final Map transliterateMap = new HashMap(){ + public static final Map transliterateMap = new HashMap(){ { //These are missing - put('ó', (byte) 111); - put('Ó', (byte) 79); - put('í', (byte) 105); - put('Í', (byte) 73); - put('ú', (byte) 117); - put('Ú', (byte) 85); + put('ó', new byte[]{(byte) 111}); + put('Ó', new byte[]{(byte) 79}); + put('í', new byte[]{(byte) 105}); + put('Í', new byte[]{(byte) 73}); + put('ú', new byte[]{(byte) 117}); + put('Ú', new byte[]{(byte) 85}); //These mostly belong to the extended ASCII table - put('Ç', (byte) 128); - put('ü', (byte) 129); - put('é', (byte) 130); - put('â', (byte) 131); - put('ä', (byte) 132); - put('à', (byte) 133); - put('ã', (byte) 134); - put('ç', (byte) 135); - put('ê', (byte) 136); - put('ë', (byte) 137); - put('Ï', (byte) 139); - put('è', (byte) 138); - put('Î', (byte) 140); - put('Ì', (byte) 141); - put('Ã', (byte) 142); - put('Ä', (byte) 143); - put('É', (byte) 144); - put('æ', (byte) 145); - put('Æ', (byte) 146); - put('ô', (byte) 147); - put('ö', (byte) 148); - put('ò', (byte) 149); - put('û', (byte) 150); - put('ù', (byte) 151); - put('ÿ', (byte) 152); - put('Ö', (byte) 153); - put('Ü', (byte) 154); - put('¢', (byte) 155); - put('£', (byte) 156); - put('¥', (byte) 157); - put('ƒ', (byte) 159); - put('á', (byte) 160); - put('ñ', (byte) 164); - put('Ñ', (byte) 165); - put('ª', (byte) 166); - put('º', (byte) 167); - put('¿', (byte) 168); - put('¬', (byte) 170); - put('½', (byte) 171); - put('¼', (byte) 172); - put('¡', (byte) 173); - put('«', (byte) 174); - put('»', (byte) 175); + put('Ç', new byte[]{(byte) 128}); + put('ü', new byte[]{(byte) 129}); + put('é', new byte[]{(byte) 130}); + put('â', new byte[]{(byte) 131}); + put('ä', new byte[]{(byte) 132}); + put('à', new byte[]{(byte) 133}); + put('ã', new byte[]{(byte) 134}); + put('ç', new byte[]{(byte) 135}); + put('ê', new byte[]{(byte) 136}); + put('ë', new byte[]{(byte) 137}); + put('Ï', new byte[]{(byte) 139}); + put('è', new byte[]{(byte) 138}); + put('Î', new byte[]{(byte) 140}); + put('Ì', new byte[]{(byte) 141}); + put('Ã', new byte[]{(byte) 142}); + put('Ä', new byte[]{(byte) 143}); + put('É', new byte[]{(byte) 144}); + put('æ', new byte[]{(byte) 145}); + put('Æ', new byte[]{(byte) 146}); + put('ô', new byte[]{(byte) 147}); + put('ö', new byte[]{(byte) 148}); + put('ò', new byte[]{(byte) 149}); + put('û', new byte[]{(byte) 150}); + put('ù', new byte[]{(byte) 151}); + put('ÿ', new byte[]{(byte) 152}); + put('Ö', new byte[]{(byte) 153}); + put('Ü', new byte[]{(byte) 154}); + put('¢', new byte[]{(byte) 155}); + put('£', new byte[]{(byte) 156}); + put('¥', new byte[]{(byte) 157}); + put('ƒ', new byte[]{(byte) 159}); + put('á', new byte[]{(byte) 160}); + put('ñ', new byte[]{(byte) 164}); + put('Ñ', new byte[]{(byte) 165}); + put('ª', new byte[]{(byte) 166}); + put('º', new byte[]{(byte) 167}); + put('¿', new byte[]{(byte) 168}); + put('¬', new byte[]{(byte) 170}); + put('½', new byte[]{(byte) 171}); + put('¼', new byte[]{(byte) 172}); + put('¡', new byte[]{(byte) 173}); + put('«', new byte[]{(byte) 174}); + put('»', new byte[]{(byte) 175}); + put('°', new byte[]{(byte) 0xa1, (byte) 0xe3}); } }; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java index 7bc36f544..c6ce5f8a6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java @@ -198,7 +198,6 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { }else{ return HPlusConstants.ARG_TIMEMODE_12H; } - } public static byte getUnit(String address) { @@ -211,25 +210,25 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { } } - public static byte getUserWeight(String address) { + public static byte getUserWeight() { ActivityUser activityUser = new ActivityUser(); return (byte) (activityUser.getWeightKg() & 0xFF); } - public static byte getUserHeight(String address) { + public static byte getUserHeight() { ActivityUser activityUser = new ActivityUser(); return (byte) (activityUser.getHeightCm() & 0xFF); } - public static byte getUserAge(String address) { + public static byte getUserAge() { ActivityUser activityUser = new ActivityUser(); return (byte) (activityUser.getAge() & 0xFF); } - public static byte getUserGender(String address) { + public static byte getUserGender() { ActivityUser activityUser = new ActivityUser(); if (activityUser.getGender() == ActivityUser.GENDER_MALE) @@ -238,7 +237,7 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { return HPlusConstants.ARG_GENDER_FEMALE; } - public static int getGoal(String address) { + public static int getGoal() { ActivityUser activityUser = new ActivityUser(); return activityUser.getStepsGoal(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySlot.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySlot.java index abee8ff55..94c8d6c8f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySlot.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySlot.java @@ -51,7 +51,13 @@ public class HPlusDataRecordDaySlot extends HPlusDataRecord { */ public int heartRate; - public HPlusDataRecordDaySlot(byte[] data) { + private int age = 0; + /** + * Raw intensity calculated from calories + */ + public int intensity; + + public HPlusDataRecordDaySlot(byte[] data, int age) { super(data, TYPE_DAY_SLOT); int a = (data[4] & 0xFF) * 256 + (data[5] & 0xFF); @@ -77,6 +83,8 @@ public class HPlusDataRecordDaySlot extends HPlusDataRecord { slotTime.set(Calendar.SECOND, 0); timestamp = (int) (slotTime.getTimeInMillis() / 1000L); + + this.age = age; } public String toString(){ @@ -101,6 +109,9 @@ public class HPlusDataRecordDaySlot extends HPlusDataRecord { } secondsInactive += other.secondsInactive; + + intensity = (int) ((100*heartRate)/(208-0.7*age)); + } public boolean isValid(){ diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordRealtime.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordRealtime.java index b9d67c4f9..58902f464 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordRealtime.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordRealtime.java @@ -66,7 +66,7 @@ class HPlusDataRecordRealtime extends HPlusDataRecord { */ public int intensity; - public HPlusDataRecordRealtime(byte[] data) { + public HPlusDataRecordRealtime(byte[] data, int age) { super(data, TYPE_REALTIME); if (data.length < 15) { @@ -91,7 +91,7 @@ class HPlusDataRecordRealtime extends HPlusDataRecord { heartRate = ActivitySample.NOT_MEASURED; } else { - intensity = (int) (100 * Math.max(0, Math.min((heartRate - 60) / 120.0, 1))); // TODO: Calculate a proper value + intensity = (int) ((100*heartRate)/(208-0.7*age)); activityKind = ActivityKind.TYPE_UNKNOWN; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusHandlerThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusHandlerThread.java index 00911584a..ab0f6ab4a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusHandlerThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusHandlerThread.java @@ -123,6 +123,10 @@ class HPlusHandlerThread extends GBDeviceIoThread { break; } + if(gbDevice.getState() == GBDevice.State.NOT_CONNECTED){ + quit(); + } + Calendar now = GregorianCalendar.getInstance(); if (now.compareTo(mGetDaySlotsTime) > 0) { @@ -138,7 +142,6 @@ class HPlusHandlerThread extends GBDeviceIoThread { } if(now.compareTo(mHelloTime) > 0){ - LOG.info("Sending hello"); sendHello(); } @@ -155,10 +158,6 @@ class HPlusHandlerThread extends GBDeviceIoThread { synchronized (waitObject) { waitObject.notify(); } - StackTraceElement l[] = Thread.currentThread().getStackTrace(); - for(StackTraceElement e: l){ - LOG.warn(e.toString()); - } } @@ -221,12 +220,12 @@ class HPlusHandlerThread extends GBDeviceIoThread { * @param data the message from the device * @return boolean indicating success or fail */ - public boolean processIncomingDaySlotData(byte[] data) { + public boolean processIncomingDaySlotData(byte[] data, int age) { HPlusDataRecordDaySlot record; try{ - record = new HPlusDataRecordDaySlot(data); + record = new HPlusDataRecordDaySlot(data, age); } catch(IllegalArgumentException e){ LOG.info((e.getMessage())); return false; @@ -303,7 +302,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { sample.setSteps(storedRecord.steps); sample.setHeartRate(storedRecord.heartRate); sample.setRawKind(storedRecord.type); - + sample.setRawIntensity(record.intensity); sample.setProvider(provider); samples.add(sample); } @@ -384,11 +383,11 @@ class HPlusHandlerThread extends GBDeviceIoThread { * @param data the message from the device * @return boolean indicating success or fail */ - public boolean processRealtimeStats(byte[] data) { + public boolean processRealtimeStats(byte[] data, int age) { HPlusDataRecordRealtime record; try{ - record = new HPlusDataRecordRealtime(data); + record = new HPlusDataRecordRealtime(data, age); } catch(IllegalArgumentException e){ LOG.info((e.getMessage())); return false; @@ -497,8 +496,15 @@ class HPlusHandlerThread extends GBDeviceIoThread { * @return boolean indicating success or fail */ public boolean processVersion(byte[] data) { - int major = data[2] & 0xFF; - int minor = data[1] & 0xFF; + int major, minor; + + if(data.length == 11){ + major = data[10] & 0xFF; + minor = data[9] & 0xFF; + }else { + major = data[2] & 0xFF; + minor = data[1] & 0xFF; + } getDevice().setFirmwareVersion(major + "." + minor); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java index 09842fade..8557ad08a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java @@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.List; @@ -59,9 +60,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; -import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; -import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -91,7 +90,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { public HPlusSupport(DeviceType type) { super(LOG); - + LOG.info("HPlusSupport Instance Created"); deviceType = type; addSupportedService(HPlusConstants.UUID_SERVICE_HP); @@ -117,26 +116,26 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { protected TransactionBuilder initializeDevice(TransactionBuilder builder) { LOG.info("Initializing"); - builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext())); + gbDevice.setState(GBDevice.State.INITIALIZING); + gbDevice.sendDeviceUpdateIntent(getContext()); measureCharacteristic = getCharacteristic(HPlusConstants.UUID_CHARACTERISTIC_MEASURE); ctrlCharacteristic = getCharacteristic(HPlusConstants.UUID_CHARACTERISTIC_CONTROL); - //Initialize device - sendUserInfo(builder); //Sync preferences builder.notify(getCharacteristic(HPlusConstants.UUID_CHARACTERISTIC_MEASURE), true); builder.setGattCallback(this); builder.notify(measureCharacteristic, true); - builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext())); + //Initialize device + sendUserInfo(builder); //Sync preferences - if(syncHelper != null){ - syncHelper.setHPlusSupport(this); - }else { + gbDevice.setState(GBDevice.State.INITIALIZED); + gbDevice.sendDeviceUpdateIntent(getContext()); + + if(syncHelper == null) { syncHelper = new HPlusHandlerThread(getDevice(), getContext(), this); syncHelper.start(); } - syncHelper.sync(); getDevice().setFirmwareVersion("N/A"); @@ -293,7 +292,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { } private HPlusSupport setWeight(TransactionBuilder transaction) { - byte value = HPlusCoordinator.getUserWeight(getDevice().getAddress()); + byte value = HPlusCoordinator.getUserWeight(); transaction.write(ctrlCharacteristic, new byte[]{ HPlusConstants.CMD_SET_WEIGHT, value @@ -303,7 +302,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { } private HPlusSupport setHeight(TransactionBuilder transaction) { - byte value = HPlusCoordinator.getUserHeight(getDevice().getAddress()); + byte value = HPlusCoordinator.getUserHeight(); transaction.write(ctrlCharacteristic, new byte[]{ HPlusConstants.CMD_HEIGHT, value @@ -314,7 +313,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { private HPlusSupport setAge(TransactionBuilder transaction) { - byte value = HPlusCoordinator.getUserAge(getDevice().getAddress()); + byte value = HPlusCoordinator.getUserAge(); transaction.write(ctrlCharacteristic, new byte[]{ HPlusConstants.CMD_SET_AGE, value @@ -324,7 +323,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { } private HPlusSupport setGender(TransactionBuilder transaction) { - byte value = HPlusCoordinator.getUserGender(getDevice().getAddress()); + byte value = HPlusCoordinator.getUserGender(); transaction.write(ctrlCharacteristic, new byte[]{ HPlusConstants.CMD_SET_GENDER, value @@ -335,7 +334,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { private HPlusSupport setGoal(TransactionBuilder transaction) { - int value = HPlusCoordinator.getGoal(getDevice().getAddress()); + int value = HPlusCoordinator.getGoal(); transaction.write(ctrlCharacteristic, new byte[]{ HPlusConstants.CMD_SET_GOAL, (byte) ((value / 256) & 0xff), @@ -806,7 +805,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { byte[] cs; if (HPlusConstants.transliterateMap.containsKey(c)) { - cs = new byte[]{HPlusConstants.transliterateMap.get(c)}; + cs = HPlusConstants.transliterateMap.get(c); } else { try { if (HPlusCoordinator.getLanguage(this.gbDevice.getAddress()) == HPlusConstants.ARG_LANGUAGE_CN) @@ -839,10 +838,11 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { switch (data[0]) { case HPlusConstants.DATA_VERSION: + case HPlusConstants.DATA_VERSION1: return syncHelper.processVersion(data); case HPlusConstants.DATA_STATS: - boolean result = syncHelper.processRealtimeStats(data); + boolean result = syncHelper.processRealtimeStats(data, HPlusCoordinator.getUserAge()); if (result) { processExtraInfo (data); } @@ -856,17 +856,19 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { case HPlusConstants.DATA_DAY_SUMMARY: case HPlusConstants.DATA_DAY_SUMMARY_ALT: - return syncHelper.processIncomingDaySlotData(data); - + return syncHelper.processIncomingDaySlotData(data, HPlusCoordinator.getUserAge()); + case HPlusConstants.DATA_UNKNOWN: + return true; default: - LOG.info("Unhandled characteristic change: " + characteristicUUID + " code: " + data[0]); + + LOG.info("Unhandled characteristic change: " + characteristicUUID + " code: " + Arrays.toString(data)); return true; } } private void processExtraInfo (byte[] data) { try { - HPlusDataRecordRealtime record = new HPlusDataRecordRealtime(data); + HPlusDataRecordRealtime record = new HPlusDataRecordRealtime(data, HPlusCoordinator.getUserAge()); handleBatteryInfo(record.battery); diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 1f2729df7..464b0cda5 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,5 +1,10 @@ + + Fix crash at startup + Improve reconnection to device +* Improve transliteration + Pebble: allow calendar sync with Timeline (Title, Location, Description) Pebble: display calendar icon for reminders from AOSP Calendar diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java index 05b57a676..4b2a4151b 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java @@ -1,5 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.test; +import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList;