1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-07-03 11:33:19 +02:00

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 <shimokawa@fsfe.org>
Co-authored-by: Memiks <contact@memiks.fr>
Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/2012
This commit is contained in:
Memiks 2020-09-13 19:13:45 +02:00 committed by Andreas Shimokawa
parent 4c55c63a32
commit 70a140f358
6 changed files with 383 additions and 98 deletions

View File

@ -18,8 +18,8 @@
package nodomain.freeyourgadget.gadgetbridge.devices.hplus;
/*
* @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
*/
* @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
*/
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<Character, byte[]> transliterateMap = new HashMap<Character, byte[]>(){
public static final Map<Character, byte[]> transliterateMap = new HashMap<Character, byte[]>() {
{
//These are missing
put('ó', new byte[]{(byte) 111});

View File

@ -18,8 +18,8 @@
package nodomain.freeyourgadget.gadgetbridge.devices.hplus;
/*
* @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
*/
* @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
*/
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 {
}
}

View File

@ -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 <http://www.gnu.org/licenses/>. */
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;
}
}
}

View File

@ -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;
}
}

View File

@ -17,13 +17,15 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus;
/*
* @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
*/
* @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
*/
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<HPlusDataRecordDaySlot> 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<HPlusDataRecordDaySlot> 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<HPlusHealthActivityOverlay> overlayList = new ArrayList<>();
List<HPlusDataRecord.RecordInterval> 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

View File

@ -18,8 +18,8 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus;
/*
* @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
*/
* @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
*/
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);
}
}
}