From 70a140f358f3e925fa974a69d548934ce5978459 Mon Sep 17 00:00:00 2001 From: Memiks Date: Sun, 13 Sep 2020 19:13:45 +0200 Subject: [PATCH] HPlus notficiation encoding weather improvments (#2012) fix indent change add only new functions from master branch correct issue with reformated code Merge branch 'master' into HPlus_improve_notifications update code formatting with Android Studio remove bad update of .gitignore HPlusSupport rebuild indexation remove unecessary change for pull request Improve HPlus support - update unicode support - update notification function - add first weather notification Merge pull request 'update master from upstream repository' (#4) from Freeyourgadget/Gadgetbridge:master into master Reviewed-on: https://codeberg.org/Memiks/Gadgetbridge/pulls/4 Merge pull request 'update master from upstream repository' (#2) from Freeyourgadget/Gadgetbridge:master into master Reviewed-on: https://codeberg.org/Memiks/Gadgetbridge/pulls/2 use my own android sdk image Sign apk add signed apk remove .drone.yml from git add drone.io compilation Merge pull request 'update master from upstream repository' (#1) from Freeyourgadget/Gadgetbridge:master into master Reviewed-on: https://codeberg.org/Memiks/Gadgetbridge/pulls/1 Co-authored-by: Andreas Shimokawa Co-authored-by: Memiks Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/2012 --- .../devices/hplus/HPlusConstants.java | 9 +- .../devices/hplus/HPlusCoordinator.java | 48 +++-- .../devices/hplus/HPlusWeatherCode.java | 197 ++++++++++++++++++ .../devices/hplus/SG2Coordinator.java | 21 +- .../devices/hplus/HPlusHandlerThread.java | 59 +++--- .../service/devices/hplus/HPlusSupport.java | 147 +++++++++---- 6 files changed, 383 insertions(+), 98 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusWeatherCode.java 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 8783b9eea..2d6016c89 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 @@ -18,8 +18,8 @@ package nodomain.freeyourgadget.gadgetbridge.devices.hplus; /* -* @author João Paulo Barraca <jpbarraca@gmail.com> -*/ + * @author João Paulo Barraca <jpbarraca@gmail.com> + */ import java.util.HashMap; import java.util.Map; @@ -88,6 +88,7 @@ public final class HPlusConstants { public static final byte CMD_SET_PREFS = 0x50; public static final byte CMD_SET_SIT_INTERVAL = 0x51; public static final byte CMD_SET_HEARTRATE_STATE = 0x32; + public static final byte CMD_SET_WEATHER_STATE = 0x5f; //GET messages public static final byte CMD_GET_VERSION = 0x17; @@ -131,8 +132,10 @@ 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 String PREF_HPLUS_UNICODE = "hplus_unicode"; + public static final String PREF_HPLUS_DISPLAY_NOTIFICATION_ICON = "hplus_display_notification_icon"; + public static final String PREF_HPLUS_NOTIFICATION_LINES = "hplus_notification_lines"; - public static final Map transliterateMap = new HashMap(){ + public static final Map transliterateMap = new HashMap() { { //These are missing put('ó', new byte[]{(byte) 111}); 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 35dada9f5..c643e9980 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 @@ -18,8 +18,8 @@ package nodomain.freeyourgadget.gadgetbridge.devices.hplus; /* -* @author João Paulo Barraca <jpbarraca@gmail.com> -*/ + * @author João Paulo Barraca <jpbarraca@gmail.com> + */ import android.annotation.TargetApi; import android.app.Activity; @@ -38,6 +38,7 @@ import java.util.Collections; import java.util.Locale; import androidx.annotation.NonNull; + import de.greenrobot.dao.query.QueryBuilder; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBException; @@ -62,7 +63,7 @@ import static nodomain.freeyourgadget.gadgetbridge.GBApplication.getContext; public class HPlusCoordinator extends AbstractDeviceCoordinator { protected static final Logger LOG = LoggerFactory.getLogger(HPlusCoordinator.class); - protected static Prefs prefs = GBApplication.getPrefs(); + protected static Prefs prefs = GBApplication.getPrefs(); @NonNull @Override @@ -85,7 +86,7 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { } @Override - public int getBondingStyle(){ + public int getBondingStyle() { return BONDING_STYLE_NONE; } @@ -191,9 +192,9 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { locale = new Locale(language); } - if (locale.getLanguage().equals(new Locale("cn").getLanguage())){ + if (locale.getLanguage().equals(new Locale("cn").getLanguage())) { return HPlusConstants.ARG_LANGUAGE_CN; - }else{ + } else { return HPlusConstants.ARG_LANGUAGE_EN; } } @@ -205,7 +206,7 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { if ("24h".equals(tmode)) { return HPlusConstants.ARG_TIMEMODE_24H; - }else{ + } else { return HPlusConstants.ARG_TIMEMODE_12H; } } @@ -213,9 +214,9 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { public static byte getUnit(String address) { String units = prefs.getString(SettingsActivity.PREF_MEASUREMENT_SYSTEM, getContext().getString(R.string.p_unit_metric)); - if(units.equals(getContext().getString(R.string.p_unit_metric))){ + if (units.equals(getContext().getString(R.string.p_unit_metric))) { return HPlusConstants.ARG_UNIT_METRIC; - }else{ + } else { return HPlusConstants.ARG_UNIT_IMPERIAL; } } @@ -260,9 +261,9 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { public static byte getAllDayHR(String address) { boolean value = (prefs.getBoolean(HPlusConstants.PREF_HPLUS_ALLDAYHR, true)); - if(value){ + if (value) { return HPlusConstants.ARG_HEARTRATE_ALLDAY_ON; - }else{ + } else { return HPlusConstants.ARG_HEARTRATE_ALLDAY_OFF; } } @@ -293,16 +294,36 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { return prefs.getInt(HPlusConstants.PREF_HPLUS_SIT_END_TIME, 0); } - public static void setUnicodeSupport(String address, boolean state){ + public static void setDisplayIncomingMessageIcon(String address, boolean state) { + SharedPreferences.Editor editor = prefs.getPreferences().edit(); + editor.putBoolean(HPlusConstants.PREF_HPLUS_DISPLAY_NOTIFICATION_ICON + "_" + address, state); + editor.apply(); + } + + public static boolean getDisplayIncomingMessageIcon(String address) { + return (prefs.getBoolean(HPlusConstants.PREF_HPLUS_DISPLAY_NOTIFICATION_ICON + "_" + address, false)); + } + + public static void setUnicodeSupport(String address, boolean state) { SharedPreferences.Editor editor = prefs.getPreferences().edit(); editor.putBoolean(HPlusConstants.PREF_HPLUS_UNICODE + "_" + address, state); editor.apply(); } - public static boolean getUnicodeSupport(String address){ + public static boolean getUnicodeSupport(String address) { return (prefs.getBoolean(HPlusConstants.PREF_HPLUS_UNICODE + "_" + address, false)); } + public static void setNotificationLinesNumber(String address, int lineNumber) { + SharedPreferences.Editor editor = prefs.getPreferences().edit(); + editor.putInt(HPlusConstants.PREF_HPLUS_NOTIFICATION_LINES + "_" + address, lineNumber); + editor.apply(); + } + + public static int getNotificationLinesNumber(String address) { + return (prefs.getInt(HPlusConstants.PREF_HPLUS_NOTIFICATION_LINES + "_" + address, 5)); + } + @Override public int[] getSupportedDeviceSpecificSettings(GBDevice device) { return new int[]{ @@ -312,3 +333,4 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { } } + \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusWeatherCode.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusWeatherCode.java new file mode 100644 index 000000000..4979d02fd --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusWeatherCode.java @@ -0,0 +1,197 @@ +/* Copyright (C) 2020 Lesur Frederic (memiks) + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.devices.hplus; + +public class HPlusWeatherCode { + // Weather code from https://github.com/heweather/WeatherIcon + public static final int SUNNY = 100; + public static final int CLOUDY = 101; + public static final int FEW_CLOUDS = 102; + public static final int PARTLY_CLOUDY = 103; + public static final int OVERCAST = 104; + public static final int CLEAR = 150; + public static final int PARTLY_CLOUDY_NIGHT = 153; + public static final int OVERCAST_NIGHT = 154; + public static final int SHOWER_RAIN = 300; + public static final int HEAVY_SHOWER_RAIN = 301; + public static final int THUNDERSHOWER = 302; + public static final int HEAVY_THUNDERSTORM = 303; + public static final int THUNDERSHOWER_WITH_HAIL = 304; + public static final int LIGHT_RAIN = 305; + public static final int MODERATE_RAIN = 306; + public static final int HEAVY_RAIN = 307; + public static final int EXTREME_RAIN = 308; + public static final int DRIZZLE_RAIN = 309; + public static final int STORM = 310; + public static final int HEAVY_STORM = 311; + public static final int SEVERE_STORM = 312; + public static final int FREEZING_RAIN = 313; + public static final int LIGHT_TO_MODERATE_RAIN = 314; + public static final int MODERATE_TO_HEAVY_RAIN = 315; + public static final int HEAVY_RAIN_TO_STORM = 316; + public static final int STORM_TO_HEAVY_STORM = 317; + public static final int HEAVY_TO_SEVERE_STORM = 318; + public static final int RAIN = 399; + public static final int SHOWER_RAIN_NIGHT = 350; + public static final int HEAVY_SHOWER_RAIN_NIGHT = 351; + public static final int LIGHT_SNOW = 400; + public static final int MODERATE_SNOW = 401; + public static final int HEAVY_SNOW = 402; + public static final int SNOWSTORM = 403; + public static final int SLEET = 404; + public static final int RAIN_AND_SNOW = 405; + public static final int SHOWER_SNOW = 406; + public static final int SNOW_FLURRY = 407; + public static final int LIGHT_TO_MODERATE_SNOW = 408; + public static final int MODERATE_TO_HEAVY_SNOW = 409; + public static final int HEAVY_SNOW_TO_SNOWSTORM = 410; + public static final int SNOW = 499; + public static final int SHOWER_SNOW_NIGHT = 456; + public static final int SNOW_FLURRY_NIGHT = 457; + public static final int MIST = 500; + public static final int FOGGY = 501; + public static final int HAZE = 502; + public static final int SAND = 503; + public static final int DUST = 504; + public static final int DUSTSTORM = 507; + public static final int SANDSTORM = 508; + public static final int DENSE_FOG = 509; + public static final int STRONG_FOG = 510; + public static final int MODERATE_HAZE = 511; + public static final int HEAVY_HAZE = 512; + public static final int SEVERE_HAZE = 513; + public static final int HEAVY_FOG = 514; + public static final int EXTRA_HEAVY_FOG = 515; + public static final int HOT = 900; + public static final int COLD = 901; + public static final int UNKNOWN = 999; + + public static final int mapOpenWeatherConditionToHPlusCondition(int openWeatherMapCondition) { + switch (openWeatherMapCondition) { + //Group 2xx: Thunderstorm + case 200: //thunderstorm with light rain: //11d + return HPlusWeatherCode.STORM; + case 201: //thunderstorm with rain: //11d + case 202: //thunderstorm with heavy rain: //11d + return HPlusWeatherCode.HEAVY_RAIN_TO_STORM; + case 210: //light thunderstorm:: //11d + case 211: //thunderstorm: //11d + case 230: //thunderstorm with light drizzle: //11d + case 231: //thunderstorm with drizzle: //11d + case 232: //thunderstorm with heavy drizzle: //11d + case 212: //heavy thunderstorm: //11d + case 221: //ragged thunderstorm: //11d + return HPlusWeatherCode.HEAVY_THUNDERSTORM; + //Group 3xx: Drizzle + case 300: //light intensity drizzle: //09d + case 301: //drizzle: //09d + case 302: //heavy intensity drizzle: //09d + case 310: //light intensity drizzle rain: //09d + case 311: //drizzle rain: //09d + case 312: //heavy intensity drizzle rain: //09d + case 313: //shower rain and drizzle: //09d + case 314: //heavy shower rain and drizzle: //09d + case 321: //shower drizzle: //09d + return HPlusWeatherCode.DRIZZLE_RAIN; + case 500: //light rain: //10d + return HPlusWeatherCode.LIGHT_RAIN; + case 501: //moderate rain: //10d + return HPlusWeatherCode.MODERATE_RAIN; + //Group 5xx: Rain + case 502: //heavy intensity rain: //10d + return HPlusWeatherCode.HEAVY_RAIN; + case 503: //very heavy rain: //10d + return HPlusWeatherCode.HEAVY_RAIN_TO_STORM; + case 504: //extreme rain: //10d + return HPlusWeatherCode.EXTREME_RAIN; + case 511: //freezing rain: //13d + return HPlusWeatherCode.FREEZING_RAIN; + case 520: //light intensity shower rain: //09d + case 521: //shower rain: //09d + return HPlusWeatherCode.SHOWER_RAIN; + case 522: //heavy intensity shower rain: //09d + case 531: //ragged shower rain: //09d + return HPlusWeatherCode.HEAVY_SHOWER_RAIN; + //Group 6xx: Snow + case 600: //light snow: //[[file:13d.png]] + return HPlusWeatherCode.LIGHT_SNOW; + case 601: //snow: //[[file:13d.png]] + return HPlusWeatherCode.SNOW; + case 620: //light shower snow: //[[file:13d.png]] + return HPlusWeatherCode.LIGHT_TO_MODERATE_SNOW; + case 602: //heavy snow: //[[file:13d.png]] + return HPlusWeatherCode.MODERATE_TO_HEAVY_SNOW; + case 611: //sleet: //[[file:13d.png]] + case 612: //shower sleet: //[[file:13d.png]] + return HPlusWeatherCode.SNOW_FLURRY; + case 621: //shower snow: //[[file:13d.png]] + case 622: //heavy shower snow: //[[file:13d.png]] + return HPlusWeatherCode.SHOWER_SNOW; + case 615: //light rain and snow: //[[file:13d.png]] + case 616: //rain and snow: //[[file:13d.png]] + return HPlusWeatherCode.RAIN_AND_SNOW; + //Group 7xx: Atmosphere + case 701: //mist: //[[file:50d.png]] + case 711: //smoke: //[[file:50d.png]] + case 721: //haze: //[[file:50d.png]] + case 731: //sandcase dust whirls: //[[file:50d.png]] + case 741: //fog: //[[file:50d.png]] + case 751: //sand: //[[file:50d.png]] + case 761: //dust: //[[file:50d.png]] + case 762: //volcanic ash: //[[file:50d.png]] + case 771: //squalls: //[[file:50d.png]] + case 781: //tornado: //[[file:50d.png]] + case 900: //tornado + return HPlusWeatherCode.SANDSTORM; + //Group 800: Clear + case 800: //clear sky: //[[file:01d.png]] [[file:01n.png]] + return HPlusWeatherCode.CLEAR; + //Group 80x: Clouds + case 801: //few clouds: //[[file:02d.png]] [[file:02n.png]] + return HPlusWeatherCode.FEW_CLOUDS; + case 802: //scattered clouds: //[[file:03d.png]] [[file:03d.png]] + case 803: //broken clouds: //[[file:04d.png]] [[file:03d.png]] + return HPlusWeatherCode.PARTLY_CLOUDY; + case 804: //overcast clouds: //[[file:04d.png]] [[file:04d.png]] + return HPlusWeatherCode.CLOUDY; + + //Group 90x: Extreme + case 901: //tropical storm + case 903: //cold + case 904: //hot + case 905: //windy + case 906: //hail + //Group 9xx: Additional + case 951: //calm + case 952: //light breeze + case 953: //gentle breeze + case 954: //moderate breeze + case 955: //fresh breeze + case 956: //strong breeze + case 957: //high windcase near gale + case 958: //gale + case 959: //severe gale + case 960: //storm + case 961: //violent storm + case 902: //hurricane + case 962: //hurricane + return HPlusWeatherCode.SEVERE_HAZE; + default: + return HPlusWeatherCode.UNKNOWN; + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/SG2Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/SG2Coordinator.java index b795e27bb..3c82d2ee4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/SG2Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/SG2Coordinator.java @@ -17,11 +17,13 @@ package nodomain.freeyourgadget.gadgetbridge.devices.hplus; /* -* @author Frederic LESUR contact@memiks.fr; -*/ + * @author Frederic LESUR contact@memiks.fr; + */ import androidx.annotation.NonNull; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; @@ -34,7 +36,10 @@ public class SG2Coordinator extends HPlusCoordinator { @Override public DeviceType getSupportedType(GBDeviceCandidate candidate) { String name = candidate.getDevice().getName(); - if(name != null && name.startsWith("SG2")){ + if (name != null && name.startsWith("SG2")) { + HPlusCoordinator.setNotificationLinesNumber(candidate.getDevice().getAddress(), 9); + HPlusCoordinator.setUnicodeSupport(candidate.getDevice().getAddress(), true); + HPlusCoordinator.setDisplayIncomingMessageIcon(candidate.getDevice().getAddress(), false); return DeviceType.SG2; } @@ -55,4 +60,14 @@ public class SG2Coordinator extends HPlusCoordinator { public boolean supportsWeather() { return true; } + + @Override + public boolean supportsSmartWakeup(GBDevice device) { + return true; + } + + @Override + public int getBondingStyle() { + return BONDING_STYLE_ASK; + } } 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 452286466..90b844b99 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 @@ -17,13 +17,15 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus; /* -* @author João Paulo Barraca <jpbarraca@gmail.com> -*/ + * @author João Paulo Barraca <jpbarraca@gmail.com> + */ import android.content.Context; import android.content.Intent; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,7 +36,6 @@ import java.util.Comparator; import java.util.GregorianCalendar; import java.util.List; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; @@ -56,39 +57,26 @@ import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread; class HPlusHandlerThread extends GBDeviceIoThread { private static final Logger LOG = LoggerFactory.getLogger(HPlusHandlerThread.class); - + private final Object waitObject = new Object(); + List mDaySlotRecords = new ArrayList<>(); private int CURRENT_DAY_SYNC_PERIOD = 24 * 60 * 60 * 365; //Never private int CURRENT_DAY_SYNC_RETRY_PERIOD = 10; - private int SLEEP_SYNC_PERIOD = 12 * 60 * 60; private int SLEEP_SYNC_RETRY_PERIOD = 30; - private int DAY_SUMMARY_SYNC_PERIOD = 24 * 60 * 60; private int DAY_SUMMARY_SYNC_RETRY_PERIOD = 30; - private int HELLO_PERIOD = 60 * 2; - private boolean mQuit = false; private HPlusSupport mHPlusSupport; - private int mLastSlotReceived = -1; private int mLastSlotRequested = 0; - private Calendar mLastSleepDayReceived = GregorianCalendar.getInstance(); private Calendar mGetDaySlotsTime = GregorianCalendar.getInstance(); private Calendar mGetSleepTime = GregorianCalendar.getInstance(); private Calendar mGetDaySummaryTime = GregorianCalendar.getInstance(); - private Calendar mHelloTime = GregorianCalendar.getInstance(); - private boolean mSlotsInitialSync = true; - private HPlusDataRecordRealtime prevRealTimeRecord = null; - - private final Object waitObject = new Object(); - - List mDaySlotRecords = new ArrayList<>(); - private HPlusDataRecordDaySlot mCurrentDaySlot = null; public HPlusHandlerThread(GBDevice gbDevice, Context context, HPlusSupport hplusSupport) { @@ -188,7 +176,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_CURR_DATA}); mHPlusSupport.performConnected(builder.getTransaction()); - } catch(Exception e) { + } catch (Exception e) { LOG.warn("HPlus: Synchronization exception: " + e); } @@ -203,7 +191,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { builder.write(mHPlusSupport.ctrlCharacteristic, HPlusConstants.CMD_ACTION_HELLO); mHPlusSupport.performConnected(builder.getTransaction()); - } catch(Exception e) { + } catch (Exception e) { } mHelloTime = GregorianCalendar.getInstance(); @@ -213,6 +201,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { waitObject.notify(); } } + /** * Process a message containing information regarding a day slot * A slot summarizes 10 minutes of data @@ -224,16 +213,16 @@ class HPlusHandlerThread extends GBDeviceIoThread { HPlusDataRecordDaySlot record; - try{ + try { record = new HPlusDataRecordDaySlot(data, age); - } catch(IllegalArgumentException e) { + } catch (IllegalArgumentException e) { LOG.info((e.getMessage())); return false; } Calendar now = GregorianCalendar.getInstance(); int nowSlot = now.get(Calendar.HOUR_OF_DAY) * 6 + (now.get(Calendar.MINUTE) / 10); - if (record.slot == nowSlot){ + if (record.slot == nowSlot) { if (mCurrentDaySlot != null && mCurrentDaySlot != record) { mCurrentDaySlot.accumulate(record); mDaySlotRecords.add(mCurrentDaySlot); @@ -272,7 +261,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { //Keep buffering if (record.slot != 143) return true; - } else { + } else { mGetDaySlotsTime = GregorianCalendar.getInstance(); mGetDaySlotsTime.add(Calendar.DAY_OF_MONTH, 1); } @@ -372,9 +361,9 @@ class HPlusHandlerThread extends GBDeviceIoThread { public boolean processIncomingSleepData(byte[] data) { HPlusDataRecordSleep record; - try{ + try { record = new HPlusDataRecordSleep(data); - } catch(IllegalArgumentException e){ + } catch (IllegalArgumentException e) { LOG.info((e.getMessage())); return false; } @@ -393,7 +382,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { List overlayList = new ArrayList<>(); List intervals = record.getIntervals(); - for(HPlusDataRecord.RecordInterval interval : intervals) { + for (HPlusDataRecord.RecordInterval interval : intervals) { overlayList.add(new HPlusHealthActivityOverlay(interval.timestampFrom, interval.timestampTo, interval.activityKind, deviceId, userId, null)); } @@ -428,7 +417,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { try { record = new HPlusDataRecordRealtime(data, age); - } catch(IllegalArgumentException e){ + } catch (IllegalArgumentException e) { LOG.info((e.getMessage())); return false; } @@ -487,7 +476,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { try { record = new HPlusDataRecordDaySummary(data); - } catch(IllegalArgumentException e) { + } catch (IllegalArgumentException e) { LOG.info((e.getMessage())); return false; } @@ -527,6 +516,8 @@ class HPlusHandlerThread extends GBDeviceIoThread { public boolean processVersion(byte[] data) { int major, minor; + LOG.info("Process Version Data: : '" + new String(data) + "'"); + if (data.length >= 11) { major = data[10] & 0xFF; minor = data[9] & 0xFF; @@ -555,7 +546,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { TransactionBuilder builder = new TransactionBuilder("requestSleepStats"); builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_SLEEP}); mHPlusSupport.performConnected(builder.getTransaction()); - } catch(Exception e) { + } catch (Exception e) { } @@ -596,7 +587,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { if (mLastSlotReceived == 143) mLastSlotReceived = -1; - byte hour = (byte) ((mLastSlotReceived + 1)/ 6); + byte hour = (byte) ((mLastSlotReceived + 1) / 6); byte minute = (byte) (((mLastSlotReceived + 1) % 6) * 10); byte nextHour = hour; @@ -610,10 +601,11 @@ class HPlusHandlerThread extends GBDeviceIoThread { TransactionBuilder builder = new TransactionBuilder("getNextDaySlot"); builder.write(mHPlusSupport.ctrlCharacteristic, msg); mHPlusSupport.performConnected(builder.getTransaction()); - } catch(Exception e) { + } catch (Exception e) { } } + /** * Request a batch of data with the summary of the previous days */ @@ -622,7 +614,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { TransactionBuilder builder = new TransactionBuilder("startSyncDaySummary"); builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_DAY_DATA}); mHPlusSupport.performConnected(builder.getTransaction()); - } catch(Exception e) { + } catch (Exception e) { } mGetDaySummaryTime = GregorianCalendar.getInstance(); @@ -631,6 +623,7 @@ class HPlusHandlerThread extends GBDeviceIoThread { /** * Helper function to create a sample + * * @param dbHandler The database handler * @param timestamp The sample timestamp * @return The sample just created 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 118693243..f7b219b93 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 @@ -18,8 +18,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus; /* -* @author João Paulo Barraca <jpbarraca@gmail.com> -*/ + * @author João Paulo Barraca <jpbarraca@gmail.com> + */ import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; @@ -44,6 +44,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.SettingsActivity; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusConstants; import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusWeatherCode; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; @@ -58,19 +59,15 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo; +import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.CurrentPosition; import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; -import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; - public class HPlusSupport extends AbstractBTLEDeviceSupport { private static final Logger LOG = LoggerFactory.getLogger(HPlusSupport.class); - + private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo(); public BluetoothGattCharacteristic ctrlCharacteristic = null; public BluetoothGattCharacteristic measureCharacteristic = null; - - private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo(); - private HPlusHandlerThread syncHelper; private DeviceType deviceType = DeviceType.UNKNOWN; @@ -110,7 +107,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { gbDevice.setState(GBDevice.State.INITIALIZED); gbDevice.sendDeviceUpdateIntent(getContext()); - if(syncHelper == null) { + if (syncHelper == null) { syncHelper = new HPlusHandlerThread(getDevice(), getContext(), this); syncHelper.start(); } @@ -417,7 +414,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { setCurrentDate(builder); setCurrentTime(builder); builder.queue(getQueue()); - }catch(IOException e){ + } catch (IOException e) { } } @@ -450,7 +447,8 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { builder.queue(getQueue()); GB.toast(getContext(), getContext().getString(R.string.user_feedback_all_alarms_disabled), Toast.LENGTH_SHORT, GB.INFO); - }catch(Exception e){} + } catch (Exception e) { + } } @@ -518,7 +516,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { @Override public void onFetchRecordedData(int dataTypes) { - if (syncHelper == null){ + if (syncHelper == null) { syncHelper = new HPlusHandlerThread(gbDevice, getContext(), this); syncHelper.start(); } @@ -534,7 +532,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { TransactionBuilder builder = performInitialized("Shutdown"); builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SHUTDOWN, HPlusConstants.ARG_SHUTDOWN_EN}); builder.queue(getQueue()); - }catch(Exception e){ + } catch (Exception e) { } } @@ -542,12 +540,12 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { @Override public void onHeartRateTest() { getQueue().clear(); - try{ + try { TransactionBuilder builder = performInitialized("HeartRateTest"); builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_HEARTRATE_STATE, HPlusConstants.ARG_HEARTRATE_MEASURE_ON}); //Set Real Time... ? builder.queue(getQueue()); - }catch(Exception e){ + } catch (Exception e) { } } @@ -565,7 +563,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_ALLDAY_HRM, state}); builder.queue(getQueue()); - }catch(Exception e){ + } catch (Exception e) { } } @@ -655,10 +653,53 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { @Override public void onSendWeather(WeatherSpec weatherSpec) { + try { + TransactionBuilder builder = performInitialized("sendWeather"); + int windSpeed = (int) weatherSpec.windSpeed; + + CurrentPosition currentPosition = new CurrentPosition(); + + int altitude = 0; + if (currentPosition.getLastKnownLocation() != null) { + altitude = (int) currentPosition.getLastKnownLocation().getAltitude(); + } + + int weatherCode = HPlusWeatherCode.mapOpenWeatherConditionToHPlusCondition(weatherSpec.currentConditionCode); + + LOG.info("[WEATHER] currentConditionCode={} altitude={} temp={}", weatherCode, altitude, weatherSpec.currentTemp); + + byte[] weatherInfo = new byte[]{(byte) HPlusConstants.CMD_SET_WEATHER_STATE, + (byte) ((weatherCode >> 8) & 255), + (byte) (weatherCode & 255), + (byte) weatherSpec.windDirection, (byte) 0, // weatherSpec.getWinPower(), + (byte) ((windSpeed >> 8) & 255), + (byte) (windSpeed & 255), + (byte) (weatherSpec.currentTemp - 17), + // base temperature information start at 17d celsius + (byte) (weatherSpec.todayMaxTemp - 17), // base temperature information start at 18d celsius + (byte) (weatherSpec.todayMinTemp - 17), // base temperature information start at 18d celsius + (byte) 0, // Life Index always 0 + (byte) 0, // (byte) (weatherSpec.getPressure() & 255), + (byte) 0, // (byte) ((weatherSpec.getPressure() >> 8) & 255), + (byte) 0, // (byte) ((weatherSpec.getPressure() >> 16) & 255), + (byte) 0, // (byte) ((weatherSpec.getPressure() >> 24) & 255), + (byte) (byte) (altitude & 255), + (byte) (byte) ((altitude >> 8) & 255), + (byte) (byte) ((altitude >> 16) & 255), + (byte) (byte) ((altitude >> 24) & 255), + (byte) 0 // (byte) + }; + + builder.write(ctrlCharacteristic, weatherInfo); + builder.queue(getQueue()); + } catch (IOException e) { + GB.toast(getContext(), "Error toggling Send Weather: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, + GB.ERROR); + } } - public void setUnicodeSupport(boolean support){ + public void setUnicodeSupport(boolean support) { HPlusCoordinator.setUnicodeSupport(gbDevice.getAddress(), support); } @@ -673,13 +714,17 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { //Show Call Icon builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_INCOMING_CALL, HPlusConstants.ARG_INCOMING_CALL}); + builder.write(ctrlCharacteristic, + new byte[]{HPlusConstants.CMD_SET_INCOMING_CALL, HPlusConstants.ARG_INCOMING_CALL}); - if(name != null) { + byte space = encodeStringToDevice(" ")[0]; + + if (name != null) { byte[] msg = new byte[13]; - //Show call name + // Show call name for (int i = 0; i < msg.length; i++) - msg[i] = ' '; + msg[i] = space; byte[] nameBytes = encodeStringToDevice(name); for (int i = 0; i < nameBytes.length && i < (msg.length - 1); i++) @@ -692,7 +737,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { builder.write(ctrlCharacteristic, msg); } - if(rawNumber != null) { + if (rawNumber != null) { StringBuilder number = new StringBuilder(); //Clean up number as the device only accepts digits @@ -706,7 +751,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { //Show call number for (int i = 0; i < msg.length; i++) - msg[i] = ' '; + msg[i] = space; for (int i = 0; i < number.length() && i < (msg.length - 1); i++) msg[i + 1] = (byte) number.charAt(i); @@ -731,7 +776,8 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { String message = ""; if (title != null && title.length() > 0) { - message = StringUtils.pad(StringUtils.truncate(title, 16), 16); //Limit title to top row + message += title + " : "; + //message = StringUtils.pad(StringUtils.truncate(title, 16), 16); // Limit title to top row } if (body != null) { @@ -742,22 +788,28 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { int length = messageBytes.length / 17; - length = length > 5 ? 5 : length; + int linesNumbers = HPlusCoordinator.getNotificationLinesNumber(this.gbDevice.getAddress()); + length = length > linesNumbers ? linesNumbers : length; + LOG.info("msglength:" + messageBytes.length + " length:" + length + " linesNumbers:" + linesNumbers); - builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_INCOMING_MESSAGE, HPlusConstants.ARG_INCOMING_MESSAGE}); + if (HPlusCoordinator.getDisplayIncomingMessageIcon(this.gbDevice.getAddress())) + builder.write(ctrlCharacteristic, + new byte[]{HPlusConstants.CMD_SET_INCOMING_MESSAGE, HPlusConstants.ARG_INCOMING_MESSAGE}); int remaining = Math.min(255, (messageBytes.length % 17 > 0) ? length + 1 : length); - byte[] msg = new byte[20]; - msg[0] = HPlusConstants.CMD_ACTION_DISPLAY_TEXT; - msg[1] = (byte) remaining; + byte[] msgSpace = new byte[20]; + byte[] msg; - for (int i = 2; i < msg.length; i++) - msg[i] = ' '; + Arrays.fill(msgSpace, encodeStringToDevice(" ")[0]); + + msgSpace[0] = HPlusConstants.CMD_ACTION_DISPLAY_TEXT; + msgSpace[1] = (byte) remaining; int message_index = 0; int i = 3; + msg = msgSpace.clone(); for (int j = 0; j < messageBytes.length; j++) { msg[i++] = messageBytes[j]; @@ -766,10 +818,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { msg[2] = (byte) message_index; builder.write(ctrlCharacteristic, msg); - msg = msg.clone(); - for (i = 3; i < msg.length; i++) - msg[i] = ' '; - + msg = msgSpace.clone(); if (message_index < remaining) i = 3; else @@ -809,6 +858,16 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { boolean unicode = HPlusCoordinator.getUnicodeSupport(this.gbDevice.getAddress()); LOG.info("Encode String: Unicode=" + unicode); + if (unicode) { + try { + return s.getBytes("Unicode"); + } catch (UnsupportedEncodingException e) { + // Fallback. Result string may be strange, but better than nothing + LOG.error("Could not convert String to Bytes: " + e.getMessage()); + return s.getBytes(); + } + } + for (int i = 0; i < s.length(); i++) { Character c = s.charAt(i); byte[] cs; @@ -817,10 +876,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { cs = HPlusConstants.transliterateMap.get(c); } else { try { - if(unicode) - cs = c.toString().getBytes("Unicode"); - else - cs = c.toString().getBytes("GB2312"); + cs = c.toString().getBytes("GB2312"); } catch (UnsupportedEncodingException e) { //Fallback. Result string may be strange, but better than nothing cs = c.toString().getBytes(); @@ -828,8 +884,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { } } - final int j0 = (unicode && i != 0) ? 2 : 0; - for (int j = j0; j < cs.length; j++) + for (int j = 0; j < cs.length; j++) outBytes.add(cs[j]); } @@ -856,7 +911,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { case HPlusConstants.DATA_STATS: boolean result = syncHelper.processRealtimeStats(data, HPlusCoordinator.getUserAge()); if (result) { - processExtraInfo (data); + processExtraInfo(data); } return result; @@ -878,7 +933,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { } } - private void processExtraInfo (byte[] data) { + private void processExtraInfo(byte[] data) { try { HPlusDataRecordRealtime record = new HPlusDataRecordRealtime(data, HPlusCoordinator.getUserAge()); @@ -912,10 +967,10 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { } private void handleBatteryInfo(byte data) { - if (batteryCmd.level != (short) data) { - batteryCmd.level = (short) data; - handleGBDeviceEvent(batteryCmd); - } + if (batteryCmd.level != (short) data) { + batteryCmd.level = (short) data; + handleGBDeviceEvent(batteryCmd); + } } }