From 483c435aa500bda69f1b674cbae5da6034abdd92 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 27 Dec 2015 19:44:33 +0100 Subject: [PATCH 01/48] Commit old weather experiment - might be worth continuing --- app/src/main/AndroidManifest.xml | 7 ++++ .../WeatherNotificationReceiver.java | 33 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 73064a6dd..7fc6c6cdf 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -196,6 +196,13 @@ + + + + + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java new file mode 100644 index 000000000..06145c146 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java @@ -0,0 +1,33 @@ +package nodomain.freeyourgadget.gadgetbridge.externalevents; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WeatherNotificationReceiver extends BroadcastReceiver { + + private static final Logger LOG = LoggerFactory.getLogger(WeatherNotificationReceiver.class); + private static final int VERSION = 2; + private final String TAG = this.getClass().getSimpleName(); + + @Override + public void onReceive(Context context, Intent intent) { + if (!intent.getAction().contains("WEATHER_UPDATE_2")) { + LOG.info("Wrong action"); + return; + } + int f = intent.getParcelableExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER"); + // int version = parcel.readInt(); + // if (version != VERSION) { + // LOG.info("Wrong version"); + // return; + // } + + //Bundle bundle = parcel.readBundle(this.getClass().getClassLoader()); + // String location = bundle.getString("weather_location"); + // LOG.info("got location: " + location); + } +} \ No newline at end of file From 7a1a6dbb2b34da1f4471fc2e23ddac6f06dee08c Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 28 Dec 2015 11:33:22 +0100 Subject: [PATCH 02/48] WeatherNotification: Try to dissect the parcelable extra This is useless, since we do not get the extra at all (only weather skins) So... this is a dead end... --- .../WeatherNotificationReceiver.java | 81 ++++++++++++++++--- 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java index 06145c146..dc0caf628 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java @@ -3,15 +3,65 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class WeatherNotificationReceiver extends BroadcastReceiver { +public class WeatherNotificationReceiver extends BroadcastReceiver { private static final Logger LOG = LoggerFactory.getLogger(WeatherNotificationReceiver.class); - private static final int VERSION = 2; - private final String TAG = this.getClass().getSimpleName(); + + static class Weather implements Parcelable { + // getters and setters suck ;) + + public long time = 0; + public long queryTime = 0; + public int version = 0; + public String location = ""; + int currentTemp = 0; + + private Weather(Parcel in) { + int version = in.readInt(); + if (version != 2) { + LOG.info("wrong version" + version); + return; + } + Bundle bundle = in.readBundle(); + location = bundle.getString("weather_location"); + time = bundle.getLong("weather_time"); + queryTime = bundle.getLong("weather_query_time"); + int conditions = bundle.getInt("weather_conditions"); + if (conditions > 0) { + currentTemp = bundle.getInt("weather_current_temp"); + } + } + + public static final Creator CREATOR = new Creator() { + @Override + public Weather createFromParcel(Parcel in) { + return new Weather(in); + } + + @Override + public Weather[] newArray(int size) { + return new Weather[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + // we do not really want to use this at all + } + } + @Override public void onReceive(Context context, Intent intent) { @@ -19,15 +69,22 @@ public class WeatherNotificationReceiver extends BroadcastReceiver { LOG.info("Wrong action"); return; } - int f = intent.getParcelableExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER"); - // int version = parcel.readInt(); - // if (version != VERSION) { - // LOG.info("Wrong version"); - // return; - // } + Bundle bundle = intent.getExtras(); - //Bundle bundle = parcel.readBundle(this.getClass().getClassLoader()); - // String location = bundle.getString("weather_location"); - // LOG.info("got location: " + location); + for (String key : bundle.keySet()) { + Object value = bundle.get(key); + LOG.info(String.format("%s %s (%s)", key, + value.toString(), value.getClass().getName())); + } + + if (!intent.hasExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER")) { + LOG.info("no weather extra"); + return; + } + + Weather weather = intent.getParcelableExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER"); + if (weather != null) { + LOG.info("weather in " + weather.location + " is " + weather.currentTemp); + } } } \ No newline at end of file From aa1014f51cdb904cef7a4cfa2b9ddec25f43c1be Mon Sep 17 00:00:00 2001 From: danielegobbetti Date: Mon, 28 Dec 2015 17:46:16 +0100 Subject: [PATCH 03/48] Added dummy configuration file. This way we get data from the weather notification app. Problem is we probably ned to add it as library, in order to unmarshal the intent. (That's why I commented the offending code in the receiver) --- app/src/main/AndroidManifest.xml | 8 ++++++++ .../externalevents/WeatherNotificationConfig.java | 9 +++++++++ .../externalevents/WeatherNotificationReceiver.java | 5 +++-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationConfig.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7fc6c6cdf..60d091244 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -203,6 +203,14 @@ + + + + + + + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationConfig.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationConfig.java new file mode 100644 index 000000000..a2b325e35 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationConfig.java @@ -0,0 +1,9 @@ +package nodomain.freeyourgadget.gadgetbridge.externalevents; + +import android.app.Activity; + +public class WeatherNotificationConfig extends Activity { + + //TODO: we just need the user to enable us in the weather notification settings. There must be a better way + +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java index dc0caf628..029637c12 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java @@ -1,5 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; +import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -71,7 +72,7 @@ public class WeatherNotificationReceiver extends BroadcastReceiver { } Bundle bundle = intent.getExtras(); - for (String key : bundle.keySet()) { +/* for (String key : bundle.keySet()) { Object value = bundle.get(key); LOG.info(String.format("%s %s (%s)", key, value.toString(), value.getClass().getName())); @@ -85,6 +86,6 @@ public class WeatherNotificationReceiver extends BroadcastReceiver { Weather weather = intent.getParcelableExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER"); if (weather != null) { LOG.info("weather in " + weather.location + " is " + weather.currentTemp); - } + }*/ } } \ No newline at end of file From af9ee90383025ebdce8006096c785dbadf600700 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 28 Dec 2015 20:55:59 +0100 Subject: [PATCH 04/48] actually get weather, seems to be the only way --- .../WeatherNotificationReceiver.java | 76 +++---------------- .../notification/ParcelableWeather2.java | 62 +++++++++++++++ 2 files changed, 72 insertions(+), 66 deletions(-) create mode 100644 app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java index 029637c12..8ba021e59 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java @@ -1,68 +1,18 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; -import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ru.gelin.android.weather.notification.ParcelableWeather2; + public class WeatherNotificationReceiver extends BroadcastReceiver { private static final Logger LOG = LoggerFactory.getLogger(WeatherNotificationReceiver.class); - static class Weather implements Parcelable { - // getters and setters suck ;) - - public long time = 0; - public long queryTime = 0; - public int version = 0; - public String location = ""; - int currentTemp = 0; - - private Weather(Parcel in) { - int version = in.readInt(); - if (version != 2) { - LOG.info("wrong version" + version); - return; - } - Bundle bundle = in.readBundle(); - location = bundle.getString("weather_location"); - time = bundle.getLong("weather_time"); - queryTime = bundle.getLong("weather_query_time"); - int conditions = bundle.getInt("weather_conditions"); - if (conditions > 0) { - currentTemp = bundle.getInt("weather_current_temp"); - } - } - - public static final Creator CREATOR = new Creator() { - @Override - public Weather createFromParcel(Parcel in) { - return new Weather(in); - } - - @Override - public Weather[] newArray(int size) { - return new Weather[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - // we do not really want to use this at all - } - } - @Override public void onReceive(Context context, Intent intent) { @@ -70,22 +20,16 @@ public class WeatherNotificationReceiver extends BroadcastReceiver { LOG.info("Wrong action"); return; } - Bundle bundle = intent.getExtras(); - -/* for (String key : bundle.keySet()) { - Object value = bundle.get(key); - LOG.info(String.format("%s %s (%s)", key, - value.toString(), value.getClass().getName())); + ParcelableWeather2 weather = null; + try { + weather = intent.getParcelableExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER"); + } catch (RuntimeException e) { + e.printStackTrace(); } - if (!intent.hasExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER")) { - LOG.info("no weather extra"); - return; - } - - Weather weather = intent.getParcelableExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER"); if (weather != null) { - LOG.info("weather in " + weather.location + " is " + weather.currentTemp); - }*/ + LOG.info("weather in " + weather.location + " is " + (weather.currentTemp - 273) + "°C"); + } + } } \ No newline at end of file diff --git a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java new file mode 100644 index 000000000..b340898b2 --- /dev/null +++ b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java @@ -0,0 +1,62 @@ +package ru.gelin.android.weather.notification; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ParcelableWeather2 implements Parcelable { + private static final Logger LOG = LoggerFactory.getLogger(ParcelableWeather2.class); + + // getters and setters suck ;) + + public long time = 0; + public long queryTime = 0; + public int version = 0; + public String location = ""; + public int currentTemp = 0; + + private ParcelableWeather2(Parcel in) { + int version = in.readInt(); + if (version != 2) { + return; + } + Bundle bundle = in.readBundle(this.getClass().getClassLoader()); + location = bundle.getString("weather_location"); + time = bundle.getLong("weather_time"); + queryTime = bundle.getLong("weather_query_time"); + bundle.getString("weather_forecast_url"); + int conditions = bundle.getInt("weather_conditions"); + if (conditions > 0) { + Bundle conditionBundle = in.readBundle(this.getClass().getClassLoader()); + conditionBundle.getString("weather_condition_text"); + conditionBundle.getStringArray("weather_condition_types"); + currentTemp = conditionBundle.getInt("weather_current_temp"); + + } + } + + public static final Creator CREATOR = new Creator() { + @Override + public ParcelableWeather2 createFromParcel(Parcel in) { + return new ParcelableWeather2(in); + } + + @Override + public ParcelableWeather2[] newArray(int size) { + return new ParcelableWeather2[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + // we do not really want to use this at all + } +} From e533fdbaa6c955f70a0ae3d3357482b6c12d8d8e Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 29 Dec 2015 22:10:38 +0100 Subject: [PATCH 05/48] Pebble: actually display current whether in WeatherNeat --- .../WeatherNotificationReceiver.java | 12 ++++++++++-- .../pebble/AppMessageHandlerWeatherNeat.java | 19 +++++++++++++------ .../notification/ParcelableWeather2.java | 15 +++++++++++---- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java index 8ba021e59..4a598aefe 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java @@ -3,6 +3,8 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,8 +30,14 @@ public class WeatherNotificationReceiver extends BroadcastReceiver { } if (weather != null) { - LOG.info("weather in " + weather.location + " is " + (weather.currentTemp - 273) + "°C"); - } + LOG.info("weather in " + weather.location + " is " + weather.currentCondition + " (" + (weather.currentTemp - 273) + "°C)"); + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences.Editor edit = sharedPrefs.edit(); + edit.putString("weather_location", weather.location); + edit.putString("weather_current_condition", weather.currentCondition); + edit.putInt("weather_current_temp", weather.currentTemp); + edit.apply(); + } } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerWeatherNeat.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerWeatherNeat.java index c32074d32..ac09bc7a4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerWeatherNeat.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerWeatherNeat.java @@ -1,5 +1,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; import android.util.Pair; import org.slf4j.Logger; @@ -9,6 +11,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.UUID; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; @@ -16,7 +19,7 @@ public class AppMessageHandlerWeatherNeat extends AppMessageHandler { public static final int KEY_REQUEST = 0; public static final int KEY_CITY = 1; - public static final int KEY_TEMPERATUR = 2; + public static final int KEY_TEMPERATURE = 2; public static final int KEY_CONDITION = 3; public static final int KEY_LIGHT_TIME = 5; @@ -28,10 +31,10 @@ public class AppMessageHandlerWeatherNeat extends AppMessageHandler { private byte[] encodeWeatherNeatMessage(String city, String temperature, String condition, int light_time) { ArrayList> pairs = new ArrayList<>(4); - pairs.add(new Pair<>(1, (Object) city)); - pairs.add(new Pair<>(2, (Object) temperature)); - pairs.add(new Pair<>(3, (Object) condition)); - pairs.add(new Pair<>(5, (Object) light_time)); // seconds for backlight on shake + pairs.add(new Pair<>(KEY_CITY, (Object) city)); + pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) temperature)); + pairs.add(new Pair<>(KEY_CONDITION, (Object) condition)); + pairs.add(new Pair<>(KEY_LIGHT_TIME, (Object) light_time)); // seconds for backlight on shake byte[] ackMessage = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); byte[] testMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); @@ -47,8 +50,12 @@ public class AppMessageHandlerWeatherNeat extends AppMessageHandler { @Override public GBDeviceEvent[] handleMessage(ArrayList> pairs) { + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); + String currentTemp = (sharedPrefs.getInt("weather_current_temp", 0) - 273) + "°C"; + String location = sharedPrefs.getString("weather_location", "unknown"); + String condition = sharedPrefs.getString("weather_current_condition", "unknown"); GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); - sendBytes.encodedBytes = encodeWeatherNeatMessage("Berlin", "22 C", "cloudy", 0); + sendBytes.encodedBytes = encodeWeatherNeatMessage(location, currentTemp, condition, 3); return new GBDeviceEvent[]{sendBytes}; } } diff --git a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java index b340898b2..ab04cace9 100644 --- a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java +++ b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java @@ -17,24 +17,31 @@ public class ParcelableWeather2 implements Parcelable { public int version = 0; public String location = ""; public int currentTemp = 0; + public String currentCondition = ""; private ParcelableWeather2(Parcel in) { int version = in.readInt(); if (version != 2) { return; } - Bundle bundle = in.readBundle(this.getClass().getClassLoader()); + Bundle bundle = in.readBundle(); location = bundle.getString("weather_location"); time = bundle.getLong("weather_time"); queryTime = bundle.getLong("weather_query_time"); bundle.getString("weather_forecast_url"); int conditions = bundle.getInt("weather_conditions"); if (conditions > 0) { - Bundle conditionBundle = in.readBundle(this.getClass().getClassLoader()); - conditionBundle.getString("weather_condition_text"); + Bundle conditionBundle = in.readBundle(); + currentCondition = conditionBundle.getString("weather_condition_text"); conditionBundle.getStringArray("weather_condition_types"); currentTemp = conditionBundle.getInt("weather_current_temp"); - + } + // get the rest + while(--conditions > 0) { + Bundle conditionBundle = in.readBundle(); + conditionBundle.getString("weather_condition_text"); + conditionBundle.getStringArray("weather_condition_types"); + conditionBundle.getInt("weather_current_temp"); } } From abb7ed01899f6fe6366d20c164607d704fcab04a Mon Sep 17 00:00:00 2001 From: danielegobbetti Date: Sun, 3 Jan 2016 16:33:48 +0100 Subject: [PATCH 06/48] Manual mapping between openweathermap and yahoo weather conditions. --- .../gadgetbridge/model/Weather.java | 218 ++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java new file mode 100644 index 000000000..b8be5cca8 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java @@ -0,0 +1,218 @@ +package nodomain.freeyourgadget.gadgetbridge.model; + +public class Weather { + + public int mapToYahooCondition(int openWeatherMapCondition) { + // openweathermap.org conditions: + // http://openweathermap.org/weather-conditions + switch (openWeatherMapCondition) { +//Group 2xx: Thunderstorm + case 200: //thunderstorm with light rain: //11d + case 201: //thunderstorm with rain: //11d + case 202: //thunderstorm with heavy rain: //11d + 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 + return 4; + case 212: //heavy thunderstorm: //11d + case 221: //ragged thunderstorm: //11d + return 3; +//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 + return 9; + case 313: //shower rain and drizzle: //09d + case 314: //heavy shower rain and drizzle: //09d + case 321: //shower drizzle: //09d + return 11; +//Group 5xx: Rain + case 500: //light rain: //10d + case 501: //moderate rain: //10d + case 502: //heavy intensity rain: //10d + case 503: //very heavy rain: //10d + case 504: //extreme rain: //10d + case 511: //freezing rain: //13d + return 10; + case 520: //light intensity shower rain: //09d + return 40; + case 521: //shower rain: //09d + case 522: //heavy intensity shower rain: //09d + case 531: //ragged shower rain: //09d + return 12; +//Group 6xx: Snow + case 600: //light snow: //[[file:13d.png]] + return 7; + case 601: //snow: //[[file:13d.png]] + return 16; + case 602: //heavy snow: //[[file:13d.png]] + return 15; + case 611: //sleet: //[[file:13d.png]] + case 612: //shower sleet: //[[file:13d.png]] + return 18; + case 615: //light rain and snow: //[[file:13d.png]] + case 616: //rain and snow: //[[file:13d.png]] + return 5; + case 620: //light shower snow: //[[file:13d.png]] + return 14; + case 621: //shower snow: //[[file:13d.png]] + return 46; + case 622: //heavy shower snow: //[[file:13d.png]] +//Group 7xx: Atmosphere + case 701: //mist: //[[file:50d.png]] + case 711: //smoke: //[[file:50d.png]] + return 22; + case 721: //haze: //[[file:50d.png]] + return 21; + case 731: //sandcase dust whirls: //[[file:50d.png]] + return 3200; + case 741: //fog: //[[file:50d.png]] + return 20; + case 751: //sand: //[[file:50d.png]] + case 761: //dust: //[[file:50d.png]] + return 19; + case 762: //volcanic ash: //[[file:50d.png]] + case 771: //squalls: //[[file:50d.png]] + return 3200; + case 781: //tornado: //[[file:50d.png]] + case 900: //tornado + return 0; +//Group 800: Clear + case 800: //clear sky: //[[file:01d.png]] [[file:01n.png]] + return 32; +//Group 80x: Clouds + case 801: //few clouds: //[[file:02d.png]] [[file:02n.png]] + case 802: //scattered clouds: //[[file:03d.png]] [[file:03d.png]] + return 34; + case 803: //broken clouds: //[[file:04d.png]] [[file:03d.png]] + case 804: //overcast clouds: //[[file:04d.png]] [[file:04d.png]] + return 44; +//Group 90x: Extreme + case 901: //tropical storm + return 1; + case 903: //cold + return 25; + case 904: //hot + return 36; + case 905: //windy + return 24; + case 906: //hail + return 17; +//Group 9xx: Additional + case 951: //calm + case 952: //light breeze + case 953: //gentle breeze + case 954: //moderate breeze + case 955: //fresh breeze + return 34; + case 956: //strong breeze + case 957: //high windcase near gale + return 24; + case 958: //gale + case 959: //severe gale + case 960: //storm + case 961: //violent storm + return 3200; + case 902: //hurricane + case 962: //hurricane + return 2; + default: + return 3200; + + } + } + + + public int mapToOpenWeatherMapCondition(int yahooCondition) { + switch (yahooCondition) { +//yahoo weather conditions: +//https://developer.yahoo.com/weather/documentation.html + case 0: //tornado + return 900; + case 1: //tropical storm + return 901; + case 2: //hurricane + return 962; + case 3: //severe thunderstorms + return 212; + case 4: //thunderstorms + return 211; + case 5: //mixed rain and snow + case 6: //mixed rain and sleet + return 616; + case 7: //mixed snow and sleet + return 600; + case 8: //freezing drizzle + case 9: //drizzle + return 301; + case 10: //freezing rain + return 511; + case 11: //showers + case 12: //showers + return 521; + case 13: //snow flurries + case 14: //light snow showers + return 620; + case 15: //blowing snow + case 41: //heavy snow + case 42: //scattered snow showers + case 43: //heavy snow + case 46: //snow showers + return 602; + case 16: //snow + return 601; + case 17: //hail + case 35: //mixed rain and hail + return 906; + case 18: //sleet + return 611; + case 19: //dust + return 761; + case 20: //foggy + return 741; + case 21: //haze + return 721; + case 22: //smoky + return 711; + case 23: //blustery + case 24: //windy + return 905; + case 25: //cold + return 903; + case 26: //cloudy + case 27: //mostly cloudy (night) + case 28: //mostly cloudy (day) + return 804; + case 29: //partly cloudy (night) + case 30: //partly cloudy (day) + return 801; + case 31: //clear (night) + case 32: //sunny + return 800; + case 33: //fair (night) + case 34: //fair (day) + return 801; + case 36: //hot + return 904; + case 37: //isolated thunderstorms + case 38: //scattered thunderstorms + case 39: //scattered thunderstorms + return 210; + case 40: //scattered showers + return 520; + case 44: //partly cloudy + return 801; + case 45: //thundershowers + case 47: //isolated thundershowers + return 621; + case 3200: //not available + default: + return -1; + } + } +} From c7c723134ea73d88e9dea9382fecd11303268455 Mon Sep 17 00:00:00 2001 From: danielegobbetti Date: Sun, 3 Jan 2016 18:28:32 +0100 Subject: [PATCH 07/48] Add weather singleton (to store the whole data passed by weather notification). Add weather info for TimeStylePebble. Add further fields to the ParcelableWeather class. Add reverse mapping to ParcelableWeather to get back the original OpenWeatherMap API condition codes. --- .../WeatherNotificationReceiver.java | 2 + .../gadgetbridge/model/Weather.java | 8 ++ .../AppMessageHandlerTimeStylePebble.java | 39 +++--- .../notification/ParcelableWeather2.java | 129 +++++++++++++++++- 4 files changed, 159 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java index 4a598aefe..7a8e2aa74 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java @@ -9,6 +9,7 @@ import android.preference.PreferenceManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.model.Weather; import ru.gelin.android.weather.notification.ParcelableWeather2; @@ -30,6 +31,7 @@ public class WeatherNotificationReceiver extends BroadcastReceiver { } if (weather != null) { + Weather.getInstance().setWeather2(weather); LOG.info("weather in " + weather.location + " is " + weather.currentCondition + " (" + (weather.currentTemp - 273) + "°C)"); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java index b8be5cca8..eedb9ac17 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java @@ -1,6 +1,14 @@ package nodomain.freeyourgadget.gadgetbridge.model; +import ru.gelin.android.weather.notification.ParcelableWeather2; + public class Weather { + private ParcelableWeather2 weather2 = null; + public ParcelableWeather2 getWeather2() {return weather2;} + public void setWeather2(ParcelableWeather2 weather2) {this.weather2 = weather2;} + + private static final Weather weather = new Weather(); + public static Weather getInstance() {return weather;} public int mapToYahooCondition(int openWeatherMapCondition) { // openweathermap.org conditions: diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java index 13bf8430d..d0c4d89fa 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java @@ -12,6 +12,8 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; +import nodomain.freeyourgadget.gadgetbridge.model.Weather; +import ru.gelin.android.weather.notification.ParcelableWeather2; public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { public static final int KEY_SETTING_SIDEBAR_LEFT = 9; @@ -59,43 +61,44 @@ public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { pairs.add(new Pair<>(KEY_SETTING_SHOW_LEADING_ZERO, (Object) 1)); pairs.add(new Pair<>(KEY_SETTING_LANGUAGE_ID, (Object) 2)); //2 = Deutsch pairs.add(new Pair<>(KEY_SETTING_USE_METRIC, (Object) 1)); + pairs.add(new Pair<>(KEY_SETTING_SHOW_BATTERY_PCT, (Object) 1)); pairs.add(new Pair<>(KEY_WIDGET_0_ID, (Object) 7)); //7 = current weather pairs.add(new Pair<>(KEY_WIDGET_1_ID, (Object) 2)); //2 = battery pairs.add(new Pair<>(KEY_WIDGET_2_ID, (Object) 4)); //4 = Date -/* - pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) 6)); - pairs.add(new Pair<>(KEY_CONDITION_CODE, (Object) 25)); - pairs.add(new Pair<>(KEY_FORECAST_CONDITION, (Object) 2)); - pairs.add(new Pair<>(KEY_FORECAST_TEMP_HIGH, (Object) 12)); - pairs.add(new Pair<>(KEY_FORECAST_TEMP_LOW, (Object) 0)); -*/ - byte[] ackMessage = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); byte[] testMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); - //byte[] weatherMessage=encodeTimeStylePebbleWeather(); - - ByteBuffer buf = ByteBuffer.allocate(ackMessage.length + testMessage.length ); + byte[] weatherMessage=encodeTimeStylePebbleWeather(); + ByteBuffer buf = ByteBuffer.allocate(ackMessage.length + testMessage.length + weatherMessage.length); // encode ack and put in front of push message (hack for acknowledging the last message) buf.put(ackMessage); buf.put(testMessage); + buf.put(weatherMessage); return buf.array(); } private byte[] encodeTimeStylePebbleWeather() { ArrayList> pairs = new ArrayList<>(); - pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) 6)); - pairs.add(new Pair<>(KEY_CONDITION_CODE, (Object) 1)); - pairs.add(new Pair<>(KEY_FORECAST_CONDITION, (Object) 2)); - pairs.add(new Pair<>(KEY_FORECAST_TEMP_HIGH, (Object) 12)); - pairs.add(new Pair<>(KEY_FORECAST_TEMP_LOW, (Object) 0)); + ParcelableWeather2 weather = Weather.getInstance().getWeather2(); + + if (weather != null) { + //TODO: use the night icons when night + pairs.add(new Pair<>(KEY_USE_NIGHT_ICON, (Object) 0)); + pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) (weather.currentTemp - 273))); + pairs.add(new Pair<>(KEY_CONDITION_CODE, (Object) weather.currentConditionCode)); + pairs.add(new Pair<>(KEY_FORECAST_CONDITION, (Object) weather.forecastConditionCode)); + pairs.add(new Pair<>(KEY_FORECAST_TEMP_HIGH, (Object) (weather.highTemp - 273))); + pairs.add(new Pair<>(KEY_FORECAST_TEMP_LOW, (Object) (weather.lowTemp - 273))); + byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); + return weatherMessage; + } + + return null; - byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); - return weatherMessage; } @Override diff --git a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java index ab04cace9..d7b426748 100644 --- a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java +++ b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java @@ -19,6 +19,14 @@ public class ParcelableWeather2 implements Parcelable { public int currentTemp = 0; public String currentCondition = ""; + String[] currentConditionType = null; + public int currentConditionCode = 3200; + String[] forecastConditionType = null; + public int forecastConditionCode = 3200; + public int lowTemp = 0; + public int highTemp = 0; + + private ParcelableWeather2(Parcel in) { int version = in.readInt(); if (version != 2) { @@ -35,9 +43,20 @@ public class ParcelableWeather2 implements Parcelable { currentCondition = conditionBundle.getString("weather_condition_text"); conditionBundle.getStringArray("weather_condition_types"); currentTemp = conditionBundle.getInt("weather_current_temp"); + + currentConditionType = conditionBundle.getStringArray("weather_condition_types"); + currentConditionCode = weatherConditionTypesToOpenWeatherMapIds(currentConditionType[0]); + lowTemp = conditionBundle.getInt("weather_low_temp"); + highTemp = conditionBundle.getInt("weather_high_temp"); + //fetch immediate next forecast + if (--conditions > 0) { + Bundle forecastBundle = in.readBundle(); + forecastConditionType = forecastBundle.getStringArray("weather_condition_types"); + forecastConditionCode = weatherConditionTypesToOpenWeatherMapIds(currentConditionType[0]); + } } // get the rest - while(--conditions > 0) { + while (--conditions > 0) { Bundle conditionBundle = in.readBundle(); conditionBundle.getString("weather_condition_text"); conditionBundle.getStringArray("weather_condition_types"); @@ -66,4 +85,112 @@ public class ParcelableWeather2 implements Parcelable { public void writeToParcel(Parcel dest, int flags) { // we do not really want to use this at all } + + private int weatherConditionTypesToOpenWeatherMapIds(String weather_condition_type) { + switch (weather_condition_type) { + case "THUNDERSTORM_RAIN_LIGHT": + return 200; + case "THUNDERSTORM_RAIN": + return 201; + case "THUNDERSTORM_RAIN_HEAVY": + return 202; + case "THUNDERSTORM_LIGHT": + return 210; + case "THUNDERSTORM": + return 211; + case "THUNDERSTORM_HEAVY": + return 212; + case "THUNDERSTORM_RAGGED": + return 221; + case "THUNDERSTORM_DRIZZLE_LIGHT": + return 230; + case "THUNDERSTORM_DRIZZLE": + return 231; + case "THUNDERSTORM_DRIZZLE_HEAVY": + return 232; + + case "DRIZZLE_LIGHT": + return 300; + case "DRIZZLE": + return 301; + case "DRIZZLE_HEAVY": + return 302; + case "DRIZZLE_RAIN_LIGHT": + return 310; + case "DRIZZLE_RAIN": + return 311; + case "DRIZZLE_RAIN_HEAVY": + return 312; + case "DRIZZLE_SHOWER": + return 321; + + case "RAIN_LIGHT": + return 500; + case "RAIN": + return 501; + case "RAIN_HEAVY": + return 502; + case "RAIN_VERY_HEAVY": + return 503; + case "RAIN_EXTREME": + return 504; + case "RAIN_FREEZING": + return 511; + case "RAIN_SHOWER_LIGHT": + return 520; + case "RAIN_SHOWER": + return 521; + case "RAIN_SHOWER_HEAVY": + return 522; + + case "SNOW_LIGHT": + return 600; + case "SNOW": + return 601; + case "SNOW_HEAVY": + return 602; + case "SLEET": + return 611; + case "SNOW_SHOWER": + return 621; + + case "MIST": + return 701; + case "SMOKE": + return 711; + case "HAZE": + return 721; + case "SAND_WHIRLS": + return 731; + case "FOG": + return 741; + + case "CLOUDS_CLEAR": + return 800; + case "CLOUDS_FEW": + return 801; + case "CLOUDS_SCATTERED": + return 802; + case "CLOUDS_BROKEN": + return 803; + case "CLOUDS_OVERCAST": + return 804; + + case "TORNADO": + return 900; + case "TROPICAL_STORM": + return 901; + case "HURRICANE": + return 902; + case "COLD": + return 903; + case "HOT": + return 904; + case "WINDY": + return 905; + case "HAIL": + return 906; + } + return 3200; + } } From 092af9f38d04ba6c8d2e3644ebfd6953e824caf8 Mon Sep 17 00:00:00 2001 From: danielegobbetti Date: Tue, 5 Jan 2016 16:03:59 +0100 Subject: [PATCH 08/48] fix forecast condition parsing --- .../gelin/android/weather/notification/ParcelableWeather2.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java index d7b426748..8defe1e05 100644 --- a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java +++ b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java @@ -52,7 +52,7 @@ public class ParcelableWeather2 implements Parcelable { if (--conditions > 0) { Bundle forecastBundle = in.readBundle(); forecastConditionType = forecastBundle.getStringArray("weather_condition_types"); - forecastConditionCode = weatherConditionTypesToOpenWeatherMapIds(currentConditionType[0]); + forecastConditionCode = weatherConditionTypesToOpenWeatherMapIds(forecastConditionType[0]); } } // get the rest From d7f4769f5713758af259c1f1e27b1313ee35a4ae Mon Sep 17 00:00:00 2001 From: danielegobbetti Date: Tue, 5 Jan 2016 16:04:32 +0100 Subject: [PATCH 09/48] make the conversion methods static --- .../nodomain/freeyourgadget/gadgetbridge/model/Weather.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java index eedb9ac17..59981199a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java @@ -10,7 +10,7 @@ public class Weather { private static final Weather weather = new Weather(); public static Weather getInstance() {return weather;} - public int mapToYahooCondition(int openWeatherMapCondition) { + public static int mapToYahooCondition(int openWeatherMapCondition) { // openweathermap.org conditions: // http://openweathermap.org/weather-conditions switch (openWeatherMapCondition) { @@ -135,8 +135,7 @@ public class Weather { } } - - public int mapToOpenWeatherMapCondition(int yahooCondition) { + public static int mapToOpenWeatherMapCondition(int yahooCondition) { switch (yahooCondition) { //yahoo weather conditions: //https://developer.yahoo.com/weather/documentation.html From 3d389f31a329db56f124bbe42f09cc4142fdc566 Mon Sep 17 00:00:00 2001 From: danielegobbetti Date: Tue, 5 Jan 2016 16:05:12 +0100 Subject: [PATCH 10/48] fix force close when weather hasn't been parsed yet, use the yahoo codes for this watchface, as required --- .../pebble/AppMessageHandlerTimeStylePebble.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java index d0c4d89fa..da4fc399e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java @@ -89,15 +89,13 @@ public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { //TODO: use the night icons when night pairs.add(new Pair<>(KEY_USE_NIGHT_ICON, (Object) 0)); pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) (weather.currentTemp - 273))); - pairs.add(new Pair<>(KEY_CONDITION_CODE, (Object) weather.currentConditionCode)); - pairs.add(new Pair<>(KEY_FORECAST_CONDITION, (Object) weather.forecastConditionCode)); + pairs.add(new Pair<>(KEY_CONDITION_CODE, (Object) Weather.mapToYahooCondition(weather.currentConditionCode))); + pairs.add(new Pair<>(KEY_FORECAST_CONDITION, (Object) Weather.mapToYahooCondition(weather.forecastConditionCode))); pairs.add(new Pair<>(KEY_FORECAST_TEMP_HIGH, (Object) (weather.highTemp - 273))); pairs.add(new Pair<>(KEY_FORECAST_TEMP_LOW, (Object) (weather.lowTemp - 273))); - byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); - return weatherMessage; } - - return null; + byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); + return weatherMessage; } From 7ba156da62ec78bf797392b923102aa6ab917334 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 10 Jan 2016 20:12:52 +0100 Subject: [PATCH 11/48] Try to support MarioTime. Does not work :/ --- .../pebble/AppMessageHandlerMarioTime.java | 69 +++++++++++++++++++ .../devices/pebble/PebbleProtocol.java | 3 +- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java new file mode 100644 index 000000000..edfeac41e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java @@ -0,0 +1,69 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; + +import android.util.Pair; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; +import nodomain.freeyourgadget.gadgetbridge.model.Weather; +import ru.gelin.android.weather.notification.ParcelableWeather2; + +public class AppMessageHandlerMarioTime extends AppMessageHandler { + + public static final int KEY_WEATHER_ICON_ID = 10; + public static final int KEY_WEATHER_TEMPERATURE = 11; + public static final int KEY_WEATHER_REQUEST = 12; + + private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerMarioTime.class); + + public AppMessageHandlerMarioTime(UUID uuid, PebbleProtocol pebbleProtocol) { + super(uuid, pebbleProtocol); + } + + private byte[] encodeWeatherMessage(int temperature, int condition) { + ArrayList> pairs = new ArrayList<>(2); + pairs.add(new Pair<>(KEY_WEATHER_ICON_ID, (Object) (byte) condition)); + pairs.add(new Pair<>(KEY_WEATHER_TEMPERATURE, (Object) (byte) temperature)); + byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); + + ByteBuffer buf = ByteBuffer.allocate(weatherMessage.length); + + // encode ack and put in front of push message (hack for acknowledging the last message) + buf.put(weatherMessage); + + return buf.array(); + } + + @Override + public GBDeviceEvent[] handleMessage(ArrayList> pairs) { + boolean weatherRequested = false; + for (Pair pair : pairs) { + switch (pair.first) { + case KEY_WEATHER_REQUEST: + LOG.info("got weather request"); + weatherRequested = true; + break; + default: + LOG.info("unknown key " + pair.first); + } + } + if (!weatherRequested) { + return new GBDeviceEvent[]{null}; + } + ParcelableWeather2 weather = Weather.getInstance().getWeather2(); + + GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); + sendBytes.encodedBytes = encodeWeatherMessage(weather.currentConditionCode, weather.currentTemp - 273); + + GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); + sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); + + return new GBDeviceEvent[]{sendBytesAck, sendBytes}; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index f0373381b..05c9b86ed 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -351,6 +351,7 @@ public class PebbleProtocol extends GBDeviceProtocol { private static final UUID UUID_PEBBLE_HEALTH = UUID.fromString("36d8c6ed-4c83-4fa1-a9e2-8f12dc941f8c"); private static final UUID UUID_PEBBLE_TIMESTYLE = UUID.fromString("4368ffa4-f0fb-4823-90be-f754b076bdaa"); private static final UUID UUID_PEBSTYLE = UUID.fromString("da05e84d-e2a2-4020-a2dc-9cdcf265fcdd"); + private static final UUID UUID_MARIOTIME = UUID.fromString("43caa750-2896-4f46-94dc-1adbd4bc1ff3"); private static final Map mAppMessageHandlers = new HashMap<>(); @@ -361,7 +362,7 @@ public class PebbleProtocol extends GBDeviceProtocol { mAppMessageHandlers.put(UUID_MISFIT, new AppMessageHandlerMisfit(UUID_MISFIT, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_PEBBLE_TIMESTYLE, new AppMessageHandlerTimeStylePebble(UUID_PEBBLE_TIMESTYLE, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_PEBSTYLE, new AppMessageHandlerPebStyle(UUID_PEBSTYLE, PebbleProtocol.this)); - + mAppMessageHandlers.put(UUID_MARIOTIME, new AppMessageHandlerMarioTime(UUID_MARIOTIME, PebbleProtocol.this)); } private static byte[] encodeSimpleMessage(short endpoint, byte command) { From 3d3643ece3531f9b551843767ac549ec929a9b56 Mon Sep 17 00:00:00 2001 From: danielegobbetti Date: Fri, 22 Jan 2016 21:04:01 +0100 Subject: [PATCH 12/48] Add weather to PebStyle as well. --- .../pebble/AppMessageHandlerPebStyle.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java index c29460da9..37468e75c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java @@ -12,6 +12,8 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleColor; +import nodomain.freeyourgadget.gadgetbridge.model.Weather; +import ru.gelin.android.weather.notification.ParcelableWeather2; public class AppMessageHandlerPebStyle extends AppMessageHandler { public static final int KEY_AMPM_TEXT = 21; @@ -57,7 +59,7 @@ public class AppMessageHandlerPebStyle extends AppMessageHandler { pairs.add(new Pair<>(KEY_SECOND_HAND, (Object) 0)); //1 enabled pairs.add(new Pair<>(KEY_BLUETOOTH_ALERT, (Object) 0)); //1 silent, 2 weak, up to 5 pairs.add(new Pair<>(KEY_TEMPERATURE_FORMAT, (Object) 1)); //0 fahrenheit - pairs.add(new Pair<>(KEY_LOCATION_SERVICE, (Object) 2)); //0 uto, 1 manual + //pairs.add(new Pair<>(KEY_LOCATION_SERVICE, (Object) 2)); //0 uto, 1 manual pairs.add(new Pair<>(KEY_SIDEBAR_LOCATION, (Object) 1)); //0 right pairs.add(new Pair<>(KEY_COLOR_SELECTION, (Object) 1)); //1 custom pairs.add(new Pair<>(KEY_MAIN_COLOR, (Object) PebbleColor.Black)); @@ -65,7 +67,7 @@ public class AppMessageHandlerPebStyle extends AppMessageHandler { pairs.add(new Pair<>(KEY_SIDEBAR_BG_COLOR, (Object) PebbleColor.MediumSpringGreen)); //DIGITAL settings - /* + /* pairs.add(new Pair<>(KEY_MAIN_CLOCK, (Object) 1)); //0 analog pairs.add(new Pair<>(KEY_SECONDARY_INFO_TYPE, (Object) 3)); //1 time, 2 location */ @@ -75,12 +77,13 @@ public class AppMessageHandlerPebStyle extends AppMessageHandler { //WEATHER - /* - //comment the same key in the general section above! - pairs.add(new Pair<>(KEY_LOCATION_SERVICE, (Object) 0)); //0 auto, 1 manual - pairs.add(new Pair<>(KEY_WEATHER_CODE, (Object) 3)); - pairs.add(new Pair<>(KEY_WEATHER_TEMP, (Object) 10)); - */ + ParcelableWeather2 weather = Weather.getInstance().getWeather2(); + if (weather != null) { + //comment the same key in the general section above! + pairs.add(new Pair<>(KEY_LOCATION_SERVICE, (Object) 0)); //0 auto, 1 manual + pairs.add(new Pair<>(KEY_WEATHER_CODE, (Object) Weather.mapToYahooCondition(weather.currentConditionCode))); + pairs.add(new Pair<>(KEY_WEATHER_TEMP, (Object) (weather.currentTemp - 273))); + } byte[] testMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); From f9d2fddb7a4c92b3685de89f13576e6554ed7084 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Thu, 28 Jan 2016 11:12:28 +0100 Subject: [PATCH 13/48] Android studio 2 complains about this comparison otherwise --- .../nodomain/freeyourgadget/gadgetbridge/util/LimitedQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LimitedQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LimitedQueue.java index 42bc1566a..c69cc0de7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LimitedQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LimitedQueue.java @@ -23,7 +23,7 @@ public class LimitedQueue { public void remove(int id) { for (Iterator iter = list.iterator(); iter.hasNext(); ) { Pair pair = iter.next(); - if (pair.first == id) { + if (((int)pair.first) == id) { iter.remove(); } } From 088dfda5f49c504cabe5455d17f7e05ee4147790 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 9 Jun 2016 19:55:36 +0200 Subject: [PATCH 14/48] Pebble: implement app reordering in PebbleProtocol Not yet used. --- .../devices/pebble/PebbleProtocol.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index d53de9b1d..3d274cee1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -69,6 +69,7 @@ public class PebbleProtocol extends GBDeviceProtocol { static final short ENDPOINT_RUNKEEPER = 7000; static final short ENDPOINT_SCREENSHOT = 8000; static final short ENDPOINT_NOTIFICATIONACTION = 11440; // 3.x only, TODO: find a better name + static final short ENDPOINT_APPREORDER = (short) 0xabcd; // 3.x only static final short ENDPOINT_BLOBDB = (short) 45531; // 3.x only static final short ENDPOINT_PUTBYTES = (short) 48879; @@ -1282,6 +1283,22 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeSimpleMessage(ENDPOINT_SCREENSHOT, SCREENSHOT_TAKE); } + public byte[] encodeAppReoder(UUID[] uuids) { + int length = 2 + uuids.length * LENGTH_UUID; + ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + length); + buf.order(ByteOrder.BIG_ENDIAN); + buf.putShort((short) length); + buf.putShort(ENDPOINT_APPREORDER); + buf.put((byte) 0x01); + buf.put((byte) uuids.length); + for (UUID uuid : uuids) { + buf.putLong(uuid.getMostSignificantBits()); + buf.putLong(uuid.getLeastSignificantBits()); + } + + return buf.array(); + } + /* pebble specific install methods */ public byte[] encodeUploadStart(byte type, int app_id, int size, String filename) { short length; @@ -1937,6 +1954,16 @@ public class PebbleProtocol extends GBDeviceProtocol { return sendBytes; } + private GBDeviceEvent decodeAppReorder(ByteBuffer buf) { + byte status = buf.get(); + if (status == 1) { + LOG.info("app reordering successful"); + } else { + LOG.info("app reordering returned status " + status); + } + return null; + } + @Override public GBDeviceEvent[] decodeResponse(byte[] responseData) { ByteBuffer buf = ByteBuffer.wrap(responseData); @@ -2187,6 +2214,8 @@ public class PebbleProtocol extends GBDeviceProtocol { case ENDPOINT_BLOBDB: devEvts = new GBDeviceEvent[]{decodeBlobDb(buf)}; break; + case ENDPOINT_APPREORDER: + devEvts = new GBDeviceEvent[]{decodeAppReorder(buf)}; default: break; } From b0fe4b151939039162a41c43e5a7dffa84126830 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 9 Jun 2016 23:39:00 +0200 Subject: [PATCH 15/48] also gather music info from notifications when screen is off --- .../externalevents/NotificationListener.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index 16647ff61..d8e0f0214 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -169,13 +169,6 @@ public class NotificationListener extends NotificationListenerService { return; } - Prefs prefs = GBApplication.getPrefs(); - if (!prefs.getBoolean("notifications_generic_whenscreenon", false)) { - PowerManager powermanager = (PowerManager) getSystemService(POWER_SERVICE); - if (powermanager.isScreenOn()) { - return; - } - } switch (GBApplication.getGrantedInterruptionFilter()) { case NotificationManager.INTERRUPTION_FILTER_ALL: break; @@ -193,6 +186,14 @@ public class NotificationListener extends NotificationListenerService { if (handleMediaSessionNotification(notification)) return; + Prefs prefs = GBApplication.getPrefs(); + if (!prefs.getBoolean("notifications_generic_whenscreenon", false)) { + PowerManager powermanager = (PowerManager) getSystemService(POWER_SERVICE); + if (powermanager.isScreenOn()) { + return; + } + } + if ((notification.flags & Notification.FLAG_ONGOING_EVENT) == Notification.FLAG_ONGOING_EVENT) { return; } From 779699cd955aa5ba40127282c498b1d29a199f11 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Fri, 9 Dec 2016 23:31:32 +0100 Subject: [PATCH 16/48] Pebble: remove configuration stuff from TimeStylePebble handler, update weather keys This is not usable now, just playing around --- .../AppMessageHandlerTimeStylePebble.java | 100 +++++------------- 1 file changed, 25 insertions(+), 75 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java index 9baeb477d..ffb580765 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java @@ -1,48 +1,25 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; -import android.graphics.Color; import android.util.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.model.Weather; - import ru.gelin.android.weather.notification.ParcelableWeather2; public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { - public static final int KEY_SETTING_SIDEBAR_LEFT = 9; - public static final int KEY_CONDITION_CODE = 4; - public static final int KEY_FORECAST_CONDITION = 25; - public static final int KEY_FORECAST_TEMP_HIGH = 26; - public static final int KEY_FORECAST_TEMP_LOW = 27; - public static final int KEY_SETTING_ALTCLOCK_NAME = 28; - public static final int KEY_SETTING_ALTCLOCK_OFFSET = 29; - public static final int KEY_SETTING_BT_VIBE = 11; - public static final int KEY_SETTING_CLOCK_FONT_ID = 18; - public static final int KEY_SETTING_COLOR_BG = 7; - public static final int KEY_SETTING_COLOR_SIDEBAR = 8; - public static final int KEY_SETTING_COLOR_TIME = 6; - public static final int KEY_SETTING_DISABLE_WEATHER = 17; - public static final int KEY_SETTING_HOURLY_VIBE = 19; - public static final int KEY_SETTING_LANGUAGE_ID = 13; - public static final int KEY_SETTING_ONLY_SHOW_BATTERY_WHEN_LOW = 20; - public static final int KEY_SETTING_SHOW_BATTERY_PCT = 16; - public static final int KEY_SETTING_SHOW_LEADING_ZERO = 15; - public static final int KEY_SETTING_SIDEBAR_TEXT_COLOR = 12; - public static final int KEY_SETTING_USE_LARGE_FONTS = 21; - public static final int KEY_SETTING_USE_METRIC = 10; - public static final int KEY_TEMPERATURE = 3; - public static final int KEY_USE_NIGHT_ICON = 5; - public static final int KEY_WIDGET_0_ID = 22; - public static final int KEY_WIDGET_1_ID = 23; - public static final int KEY_WIDGET_2_ID = 24; + private static final int MESSAGE_KEY_WeatherCondition = 10000; + private static final int MESSAGE_KEY_WeatherForecastCondition = 10002; + private static final int MESSAGE_KEY_WeatherForecastHighTemp = 10003; + private static final int MESSAGE_KEY_WeatherForecastLowTemp = 10004; + private static final int MESSAGE_KEY_WeatherTemperature = 10001; + private static final int MESSAGE_KEY_WeatherUseNightIcon = 10025; private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerTimeStylePebble.class); @@ -51,62 +28,35 @@ public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { super(uuid, pebbleProtocol); } - private byte[] encodeTimeStylePebbleConfig() { - ArrayList> pairs = new ArrayList<>(); - //settings that give good legibility on pebble time - pairs.add(new Pair<>(KEY_SETTING_SIDEBAR_LEFT, (Object) 1)); - pairs.add(new Pair<>(KEY_SETTING_CLOCK_FONT_ID, (Object) 1)); - pairs.add(new Pair<>(KEY_SETTING_COLOR_BG, (Object) Color.parseColor("#ffffff"))); - pairs.add(new Pair<>(KEY_SETTING_COLOR_SIDEBAR, (Object) Color.parseColor("#00aaff"))); - pairs.add(new Pair<>(KEY_SETTING_COLOR_TIME, (Object) Color.parseColor("#000000"))); - pairs.add(new Pair<>(KEY_SETTING_SHOW_LEADING_ZERO, (Object) 1)); - pairs.add(new Pair<>(KEY_SETTING_LANGUAGE_ID, (Object) 2)); //2 = Deutsch - pairs.add(new Pair<>(KEY_SETTING_USE_METRIC, (Object) 1)); - pairs.add(new Pair<>(KEY_SETTING_SHOW_BATTERY_PCT, (Object) 1)); - - pairs.add(new Pair<>(KEY_WIDGET_0_ID, (Object) 7)); //7 = current weather - pairs.add(new Pair<>(KEY_WIDGET_1_ID, (Object) 2)); //2 = battery - pairs.add(new Pair<>(KEY_WIDGET_2_ID, (Object) 4)); //4 = Date - - byte[] ackMessage = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); - byte[] testMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); - - byte[] weatherMessage=encodeTimeStylePebbleWeather(); - ByteBuffer buf = ByteBuffer.allocate(ackMessage.length + testMessage.length + weatherMessage.length); - - // encode ack and put in front of push message (hack for acknowledging the last message) - buf.put(ackMessage); - buf.put(testMessage); - buf.put(weatherMessage); - - return buf.array(); - } - private byte[] encodeTimeStylePebbleWeather() { ArrayList> pairs = new ArrayList<>(); ParcelableWeather2 weather = Weather.getInstance().getWeather2(); if (weather != null) { //TODO: use the night icons when night - pairs.add(new Pair<>(KEY_USE_NIGHT_ICON, (Object) 0)); - pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) (weather.currentTemp - 273))); - pairs.add(new Pair<>(KEY_CONDITION_CODE, (Object) Weather.mapToYahooCondition(weather.currentConditionCode))); - pairs.add(new Pair<>(KEY_FORECAST_CONDITION, (Object) Weather.mapToYahooCondition(weather.forecastConditionCode))); - pairs.add(new Pair<>(KEY_FORECAST_TEMP_HIGH, (Object) (weather.highTemp - 273))); - pairs.add(new Pair<>(KEY_FORECAST_TEMP_LOW, (Object) (weather.lowTemp - 273))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherUseNightIcon, (Object) 0)); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherTemperature, (Object) (weather.currentTemp - 273))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherCondition, (Object) Weather.mapToYahooCondition(weather.currentConditionCode))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastCondition, (Object) Weather.mapToYahooCondition(weather.forecastConditionCode))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastHighTemp, (Object) (weather.highTemp - 273))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastLowTemp, (Object) (weather.lowTemp - 273))); } - byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); - return weatherMessage; + return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); } @Override public GBDeviceEvent[] handleMessage(ArrayList> pairs) { - return null; - /* - GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); - sendBytes.encodedBytes = encodeTimeStylePebbleConfig(); - return new GBDeviceEvent[]{sendBytes}; - */ + return pushMessage(); } -} + + @Override + public GBDeviceEvent[] pushMessage() { + GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); + sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); + + GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); + sendBytes.encodedBytes = encodeTimeStylePebbleWeather(); + return new GBDeviceEvent[]{sendBytesAck, sendBytes}; + } +} \ No newline at end of file From a6a2c6d6d66f53892c0bd43addd94ecac76996bc Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Sat, 10 Dec 2016 15:09:22 +0100 Subject: [PATCH 17/48] Pebble: timestyle doesn't use Yahoo anymore. The values do not work anyway, because it's mapping them internally. See https://github.com/freakified/TimeStylePebble/tree/master/src/pkjs for the mappings. --- .../devices/pebble/AppMessageHandlerTimeStylePebble.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java index ffb580765..4d31c4b8d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java @@ -34,10 +34,10 @@ public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { if (weather != null) { //TODO: use the night icons when night - pairs.add(new Pair<>(MESSAGE_KEY_WeatherUseNightIcon, (Object) 0)); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherUseNightIcon, (Object) 1)); pairs.add(new Pair<>(MESSAGE_KEY_WeatherTemperature, (Object) (weather.currentTemp - 273))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherCondition, (Object) Weather.mapToYahooCondition(weather.currentConditionCode))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastCondition, (Object) Weather.mapToYahooCondition(weather.forecastConditionCode))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherCondition, (Object) (weather.currentConditionCode))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastCondition, (Object) (weather.forecastConditionCode))); pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastHighTemp, (Object) (weather.highTemp - 273))); pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastLowTemp, (Object) (weather.lowTemp - 273))); } From f63a7db5f98c453c81449f471761bf62571e25a0 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 11 Dec 2016 00:08:57 +0100 Subject: [PATCH 18/48] Pebble: map owm conditions to TimeStyle icons This is probably not the way we should do it, just experimenting for personal use :P --- .../AppMessageHandlerTimeStylePebble.java | 75 ++++++++++++++++++- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java index 4d31c4b8d..d20aa615e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java @@ -22,22 +22,89 @@ public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { private static final int MESSAGE_KEY_WeatherUseNightIcon = 10025; + private static final int ICON_CLEAR_DAY = 0; + private static final int ICON_CLEAR_NIGHT = 1; + private static final int ICON_CLOUDY_DAY = 2; + private static final int ICON_HEAVY_RAIN = 3; + private static final int ICON_HEAVY_SNOW = 4; + private static final int ICON_LIGHT_RAIN = 5; + private static final int ICON_LIGHT_SNOW = 6; + private static final int ICON_PARTLY_CLOUDY_NIGHT = 7; + private static final int ICON_PARTLY_CLOUDY = 8; + private static final int ICON_RAINING_AND_SNOWING = 9; + private static final int ICON_THUNDERSTORM = 10; + private static final int ICON_WEATHER_GENERIC = 11; + private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerTimeStylePebble.class); public AppMessageHandlerTimeStylePebble(UUID uuid, PebbleProtocol pebbleProtocol) { super(uuid, pebbleProtocol); } + /* + * converted to JAVA from original JS + */ + private int getIconForConditionCode(int conditionCode, boolean isNight) { + int generalCondition = conditionCode / 100; + int iconToLoad; + // determine the correct icon + switch (generalCondition) { + case 2: //thunderstorm + iconToLoad = ICON_THUNDERSTORM; + break; + case 3: //drizzle + iconToLoad = ICON_LIGHT_RAIN; + break; + case 5: //rain + if (conditionCode == 500) { + iconToLoad = ICON_LIGHT_RAIN; + } else if (conditionCode < 505) { + iconToLoad = ICON_HEAVY_RAIN; + } else if (conditionCode == 511) { + iconToLoad = ICON_RAINING_AND_SNOWING; + } else { + iconToLoad = ICON_LIGHT_RAIN; + } + break; + case 6: //snow + if (conditionCode == 600 || conditionCode == 620) { + iconToLoad = ICON_LIGHT_SNOW; + } else if (conditionCode > 610 && conditionCode < 620) { + iconToLoad = ICON_RAINING_AND_SNOWING; + } else { + iconToLoad = ICON_HEAVY_SNOW; + } + break; + case 7: // fog, dust, etc + iconToLoad = ICON_CLOUDY_DAY; + break; + case 8: // clouds + if (conditionCode == 800) { + iconToLoad = (!isNight) ? ICON_CLEAR_DAY : ICON_CLEAR_NIGHT; + } else if (conditionCode < 803) { + iconToLoad = (!isNight) ? ICON_PARTLY_CLOUDY : ICON_PARTLY_CLOUDY_NIGHT; + } else { + iconToLoad = ICON_CLOUDY_DAY; + } + break; + default: + iconToLoad = ICON_WEATHER_GENERIC; + break; + } + + return iconToLoad; + } + private byte[] encodeTimeStylePebbleWeather() { ArrayList> pairs = new ArrayList<>(); ParcelableWeather2 weather = Weather.getInstance().getWeather2(); + boolean isNight = false; //TODO: use the night icons when night if (weather != null) { - //TODO: use the night icons when night - pairs.add(new Pair<>(MESSAGE_KEY_WeatherUseNightIcon, (Object) 1)); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherUseNightIcon, (Object) (isNight ? 1 : 0))); pairs.add(new Pair<>(MESSAGE_KEY_WeatherTemperature, (Object) (weather.currentTemp - 273))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherCondition, (Object) (weather.currentConditionCode))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastCondition, (Object) (weather.forecastConditionCode))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherCondition, (Object) (getIconForConditionCode(weather.currentConditionCode, isNight)))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastCondition, (Object) (getIconForConditionCode(weather.forecastConditionCode, isNight)))); pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastHighTemp, (Object) (weather.highTemp - 273))); pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastLowTemp, (Object) (weather.lowTemp - 273))); } From 9cea2fc3bdc95013bad8fd335006925e05b4fc59 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 28 Dec 2016 22:54:07 +0100 Subject: [PATCH 19/48] Update changelog for 0.16 --- CHANGELOG.md | 10 ++++++---- app/src/main/res/xml/changelog_master.xml | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 949564e43..24985ba3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,12 @@ ###Changelog ####Version 0.16.0 -* New device: ZeBand -* ZeBand: Initial experimental support -* Pebble 2: Fix Pebble Classic FW 3.x app variant being priorized over native Pebble 2 app variant - +* New devices: HPlus (e.g. Zeblaze ZeBand), contributed by João Paulo Barraca +* ZeBand: Initial support: notifications, heart rate, sleep monitoring, user configuration, date+time +* Pebble 2: Fix Pebble Classic FW 3.x app variant being prioritized over native Pebble 2 app variant +* Charts (Live Activity): Fix axis labels color in dark theme +* Mi Band: Fix ginormous step count when using Live Activity +* Mi Band: Improved performance during activity sync ####Version 0.15.2 * Mi Band: Fix crash with unknown notification sources diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 7b1b8cb0a..946923366 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,9 +1,12 @@ - New device: ZeBand - ZeBand: Initial experimental support - Pebble 2: Fix Pebble Classic FW 3.x app variant being priorized over native Pebble 2 app variant + New devices: HPlus (e.g. Zeblaze ZeBand), contributed by João Paulo Barraca + ZeBand: Initial support: notifications, heart rate, sleep monitoring, user configuration, date+time + Pebble 2: Fix Pebble Classic FW 3.x app variant being prioritized over native Pebble 2 app variant + Charts (Live Activity): Fix axis labels color in dark theme + Mi Band: Fix ginormous step count when using Live Activity + Mi Band: Improved performance during activity sync Mi Band: Fix crash with unknown notification sources From 0646eda646c78d01a139adc072cf9096a5d945df Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 29 Dec 2016 01:07:26 +0100 Subject: [PATCH 20/48] Fix file potential handle leaks --- .../gadgetbridge/util/FileUtils.java | 69 +++++++++++++------ 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java index 3898818e2..66de19b56 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -46,14 +47,20 @@ public class FileUtils { } } + /** + * Copies the contents of the given input stream to the destination file. + * @param inputStream the contents to write. Note: the caller has to close the input stream! + * @param destFile the file to write to + * @throws IOException + */ public static void copyStreamToFile(InputStream inputStream, File destFile) throws IOException { - FileOutputStream fout = new FileOutputStream(destFile); - byte[] buf = new byte[4096]; - while (inputStream.available() > 0) { - int bytes = inputStream.read(buf); - fout.write(buf, 0, bytes); + try (FileOutputStream fout = new FileOutputStream(destFile)) { + byte[] buf = new byte[4096]; + while (inputStream.available() > 0) { + int bytes = inputStream.read(buf); + fout.write(buf, 0, bytes); + } } - fout.close(); } public static void copyURItoFile(Context ctx, Uri uri, File destFile) throws IOException { @@ -62,29 +69,47 @@ public class FileUtils { } ContentResolver cr = ctx.getContentResolver(); - InputStream fin; - try { - fin = new BufferedInputStream(cr.openInputStream(uri)); - } catch (FileNotFoundException e) { - e.printStackTrace(); - return; + InputStream in = cr.openInputStream(uri); + if (in == null) { + throw new IOException("unable to open input stream: " + uri); + } + try (InputStream fin = new BufferedInputStream(in)) { + copyStreamToFile(fin, destFile); + fin.close(); } - copyStreamToFile(fin, destFile); - fin.close(); } + /** + * Returns the textual contents of the given file. The contents is expected to be + * in UTF-8 encoding. + * @param file the file to read + * @return the file contents as a newline-delimited string + * @throws IOException + * @see #getStringFromFile(File, String) + */ public static String getStringFromFile(File file) throws IOException { + return getStringFromFile(file, StandardCharsets.UTF_8.name()); + } + + /** + * Returns the textual contents of the given file. The contents will be interpreted using the + * given encoding. + * @param file the file to read + * @return the file contents as a newline-delimited string + * @throws IOException + * @see #getStringFromFile(File) + */ + public static String getStringFromFile(File file, String encoding) throws IOException { FileInputStream fin = new FileInputStream(file); - BufferedReader reader = new BufferedReader(new InputStreamReader(fin)); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - sb.append(line).append("\n"); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(fin, encoding))) { + StringBuilder sb = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + return sb.toString(); } - reader.close(); - fin.close(); - return sb.toString(); } /** From a96a747119ae6762bd84e964cd6b78b20b397162 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 29 Dec 2016 01:29:28 +0100 Subject: [PATCH 21/48] Pebble: fix resource leak on app installation --- .../devices/pebble/PBWInstallHandler.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java index 70ed7f373..7e9bf7e4d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java @@ -60,6 +60,10 @@ public class PBWInstallHandler implements InstallHandler { installActivity.setInfoText("file not found"); installActivity.setInstallEnabled(false); return; + } catch (IOException e) { + installActivity.setInfoText("error reading file"); + installActivity.setInstallEnabled(false); + return; } if (!mPBWReader.isValid()) { @@ -168,18 +172,22 @@ public class PBWInstallHandler implements InstallHandler { } InputStream jsConfigFile = mPBWReader.getInputStreamFile("pebble-js-app.js"); - if (jsConfigFile != null) { - outputFile = new File(destDir, app.getUUID().toString() + "_config.js"); try { + outputFile = new File(destDir, app.getUUID().toString() + "_config.js"); FileUtils.copyStreamToFile(jsConfigFile, outputFile); } catch (IOException e) { LOG.error("Failed to open output file: " + e.getMessage(), e); + } finally { + try { + jsConfigFile.close(); + } catch (IOException e) { + } } } - } + @Override public boolean isValid() { // always pretend it is valid, as we can't know yet about hw/fw version return true; From aadde7d1cad5a2b147b6f909af8e9260b93e4ca4 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 29 Dec 2016 01:41:47 +0100 Subject: [PATCH 22/48] Port to UriHelper, fix potential resource leak --- .../devices/pebble/PBWReader.java | 177 ++++++++---------- .../devices/pebble/PebbleIoThread.java | 5 +- .../gadgetbridge/util/UriHelper.java | 150 +++++++++++++++ 3 files changed, 227 insertions(+), 105 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/UriHelper.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java index 508f3a7f2..50f8ef9d2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java @@ -1,19 +1,14 @@ package nodomain.freeyourgadget.gadgetbridge.devices.pebble; -import android.content.ContentResolver; import android.content.Context; -import android.database.Cursor; import android.net.Uri; -import android.provider.MediaStore; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -28,6 +23,7 @@ import java.util.zip.ZipInputStream; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.PebbleProtocol; +import nodomain.freeyourgadget.gadgetbridge.util.UriHelper; public class PBWReader { private static final Logger LOG = LoggerFactory.getLogger(PBWReader.class); @@ -47,8 +43,7 @@ public class PBWReader { fwFileTypesMap.put("resources", PebbleProtocol.PUTBYTES_TYPE_SYSRESOURCES); } - private final Uri uri; - private final ContentResolver cr; + private final UriHelper uriHelper; private GBDeviceApp app; private ArrayList pebbleInstallables = null; private boolean isFirmware = false; @@ -59,121 +54,48 @@ public class PBWReader { private short mAppVersion; private int mIconId; private int mFlags; - private long fileSize; private JSONObject mAppKeys = null; - public PBWReader(Uri uri, Context context, String platform) throws FileNotFoundException { - this.uri = uri; - cr = context.getContentResolver(); + public PBWReader(Uri uri, Context context, String platform) throws IOException { + uriHelper = UriHelper.get(uri, context); - InputStream fin = new BufferedInputStream(cr.openInputStream(uri)); - - Uri filePathUri = uri; - if (uri.getScheme().toString().compareTo("content") == 0) { - Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); - if (cursor.moveToFirst()) { - int name_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME); - int size_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE); - filePathUri = Uri.parse(cursor.getString(name_index)); - fileSize = cursor.getLong(size_index); - } - } - if (filePathUri.toString().endsWith(".pbl")) { + if (uriHelper.getFileName().endsWith(".pbl")) { STM32CRC stm32crc = new STM32CRC(); - try { + try (InputStream fin = uriHelper.openInputStream()) { byte[] buf = new byte[2000]; while (fin.available() > 0) { int count = fin.read(buf); stm32crc.addData(buf, count); } - fin.close(); - } catch (IOException e) { - e.printStackTrace(); - return; } - int crc = stm32crc.getResult(); // language file app = new GBDeviceApp(UUID.randomUUID(), "Language File", "unknown", "unknown", GBDeviceApp.Type.UNKNOWN); - if (fileSize == 0) { - File f = new File(uri.getPath()); - fileSize = f.length(); - } pebbleInstallables = new ArrayList<>(); - pebbleInstallables.add(new PebbleInstallable("lang", (int) fileSize, crc, PebbleProtocol.PUTBYTES_TYPE_FILE)); + pebbleInstallables.add(new PebbleInstallable("lang", (int) uriHelper.getFileSize(), crc, PebbleProtocol.PUTBYTES_TYPE_FILE)); isValid = true; isLanguage = true; return; } - String platformDir = ""; - - if (!filePathUri.toString().endsWith(".pbz")) { - /* - * for aplite and basalt it is possible to install 2.x apps which have no subfolder - * we still prefer the subfolders if present. - * chalk needs to be its subfolder - */ - String[] platformDirs; - switch (platform) { - case "basalt": - platformDirs = new String[]{"basalt/"}; - break; - case "chalk": - platformDirs = new String[]{"chalk/"}; - break; - case "diorite": - platformDirs = new String[]{"diorite/", "aplite/"}; - break; - case "emery": - platformDirs = new String[]{"emery/", "basalt/"}; - break; - default: - platformDirs = new String[]{"aplite/"}; - } - - for (String dir : platformDirs) { - InputStream afin = new BufferedInputStream(cr.openInputStream(uri)); - - ZipInputStream zis = new ZipInputStream(afin); - ZipEntry ze; - boolean found = false; - try { - while ((ze = zis.getNextEntry()) != null) { - if (ze.getName().startsWith(dir)) { - platformDir = dir; - found = true; - break; - } - } - zis.close(); - } catch (IOException e) { - e.printStackTrace(); - } - if (found) { - break; - } - } - - if (platform.equals("chalk") && platformDir.equals("")) { - return; - } + String platformDir = determinePlatformDir(uriHelper, platform); + if (platform.equals("chalk") && platformDir.equals("")) { + return; } + LOG.info("using platformdir: '" + platformDir + "'"); String appName = null; String appCreator = null; String appVersion = null; UUID appUUID = null; - ZipInputStream zis = new ZipInputStream(fin); ZipEntry ze; pebbleInstallables = new ArrayList<>(); byte[] buffer = new byte[1024]; int count; - - try { + try (ZipInputStream zis = new ZipInputStream(uriHelper.openInputStream())) { while ((ze = zis.getNextEntry()) != null) { String fileName = ze.getName(); if (fileName.equals(platformDir + "manifest.json")) { @@ -269,7 +191,6 @@ public class PBWReader { // more follows but, not interesting for us } } - zis.close(); if (appUUID != null && appName != null && appCreator != null && appVersion != null) { GBDeviceApp.Type appType = GBDeviceApp.Type.APP_GENERIC; @@ -280,11 +201,58 @@ public class PBWReader { } app = new GBDeviceApp(appUUID, appName, appCreator, appVersion, appType); } - } catch (IOException e) { - e.printStackTrace(); } } + /** + * Determines the platform dir to use for the given uri and platform. + * @param uriHelper + * @param platform + * @return the platform dir to use + * @throws IOException + */ + private String determinePlatformDir(UriHelper uriHelper, String platform) throws IOException { + String platformDir = ""; + + if (uriHelper.getFileName().endsWith(".pbz")) { + return platformDir; + } + /* + * for aplite and basalt it is possible to install 2.x apps which have no subfolder + * we still prefer the subfolders if present. + * chalk needs to be its subfolder + */ + String[] platformDirs; + switch (platform) { + case "basalt": + platformDirs = new String[]{"basalt/"}; + break; + case "chalk": + platformDirs = new String[]{"chalk/"}; + break; + case "diorite": + platformDirs = new String[]{"diorite/", "aplite/"}; + break; + case "emery": + platformDirs = new String[]{"emery/", "basalt/"}; + break; + default: + platformDirs = new String[]{"aplite/"}; + } + + for (String dir : platformDirs) { + try (ZipInputStream zis = new ZipInputStream(uriHelper.openInputStream())) { + ZipEntry ze; + while ((ze = zis.getNextEntry()) != null) { + if (ze.getName().startsWith(dir)) { + return dir; + } + } + } + } + return platformDir; + } + public boolean isFirmware() { return isFirmware; } @@ -302,28 +270,29 @@ public class PBWReader { } public InputStream getInputStreamFile(String filename) { - InputStream fin; - try { - fin = new BufferedInputStream(cr.openInputStream(uri)); - if (isLanguage) { - return fin; + if (isLanguage) { + try { + return uriHelper.openInputStream(); + } catch (FileNotFoundException e) { + LOG.warn("file not found: " + e); + return null; } - } catch (FileNotFoundException e) { - e.printStackTrace(); - return null; } - ZipInputStream zis = new ZipInputStream(fin); + ZipInputStream zis = null; ZipEntry ze; try { + zis = new ZipInputStream(uriHelper.openInputStream()); while ((ze = zis.getNextEntry()) != null) { if (ze.getName().equals(filename)) { - return zis; + return zis; // return WITHOUT closing the stream! } } zis.close(); } catch (Throwable e) { try { - zis.close(); + if (zis != null) { + zis.close(); + } } catch (IOException e1) { // ignore } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index bd990d2d6..035fa17b6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -623,7 +623,10 @@ class PebbleIoThread extends GBDeviceIoThread { try { mPBWReader = new PBWReader(uri, getContext(), platformName); } catch (FileNotFoundException e) { - LOG.warn("file not found!"); + LOG.warn("file not found: " + e.getMessage(), e); + return; + } catch (IOException e) { + LOG.warn("unable to read file: " + e.getMessage(), e); return; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/UriHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/UriHelper.java new file mode 100644 index 000000000..9c5d9b674 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/UriHelper.java @@ -0,0 +1,150 @@ +package nodomain.freeyourgadget.gadgetbridge.util; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +public class UriHelper { + @NonNull + private final Uri uri; + @NonNull + private final Context context; + private String fileName; + private long fileSize; + @Nullable + private File file; + + private UriHelper(@NonNull Uri uri, @NonNull Context context) { + this.uri = uri; + this.context = context; + } + + /** + * Returns the uri as passed to #get(Uri, Context) + */ + @NonNull + public Uri getUri() { + return uri; + } + + /** + * Returns the context as passed to #get(Uri, Context) + */ + @NonNull + public Context getContext() { + return context; + } + + /** + * Returns an immutable helper to access the given Uri. In case the uri cannot be read/resolved + * an IOException is thrown. + * @param uri the uri to access + * @param context the context for accessing uris + * @throws IOException + */ + @NonNull + public static UriHelper get(@NonNull Uri uri, @NonNull Context context) throws FileNotFoundException, IOException { + UriHelper helper = new UriHelper(uri, context); + helper.resolveMetadata(); + return helper; + } + + /** + * Opens a stream to read the contents of the uri. + * Note: the caller has to close the stream after usage. + * Every invocation of this method will open a new stream. + * @throws FileNotFoundException + */ + @NonNull + public InputStream openInputStream() throws FileNotFoundException { + ContentResolver cr = context.getContentResolver(); + InputStream inputStream = cr.openInputStream(uri); + if (inputStream != null) { + return new BufferedInputStream(inputStream); + } + throw new FileNotFoundException("Unable to open inputstream for " + uri); + } + + /** + * Returns the content length (file size) in bytes + */ + public long getFileSize() { + return fileSize; + } + + /** + * Returns the name of the file referenced by the Uri. Does not include the path. + */ + @NonNull + public String getFileName() { + return fileName; + } + + /** + * Returns the file behind the uri, or null in case it is not a file:/ Uri. + * @return the file or null + */ + @Nullable + public File getFile() { + return file; + } + + private void resolveMetadata() throws IOException { + String uriScheme = uri.getScheme(); + if (ContentResolver.SCHEME_CONTENT.equals(uriScheme)) { + Cursor cursor = context.getContentResolver().query( + uri, + new String[] { + MediaStore.MediaColumns.DISPLAY_NAME, + MediaStore.MediaColumns.SIZE + }, null, null, null); + if (cursor == null) { + throw new IOException("Unable to query metadata for: " + uri); + } + if (cursor.moveToFirst()) { + int name_index = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME); + if (name_index == -1) { + throw new IOException("Unable to retrieve name for: " + uri); + } + int size_index = cursor.getColumnIndex(MediaStore.MediaColumns.SIZE); + if (size_index == -1) { + throw new IOException("Unable to retrieve size for: " + uri); + } + try { + fileName = cursor.getString(name_index); + if (fileName == null) { + throw new IOException("Unable to retrieve name for: " + uri); + } + fileSize = cursor.getLong(size_index); + if (fileSize < 0) { + throw new IOException("Unable to retrieve size for: " + uri); + } + } catch (Exception ex) { + throw new IOException("Unable to retrieve metadata for: " + uri + ": " + ex.getMessage()); + } + } + } else if (ContentResolver.SCHEME_FILE.equals(uriScheme)) { + file = new File(uri.getPath()); + if (!file.exists()) { + throw new FileNotFoundException("Does not exist: " + file); + } + fileName = file.getName(); + fileSize = file.length(); + } else if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(uriScheme)) { + // we could actually read it, but I don't see how we can determine the file size + throw new IOException("Unsupported scheme for uri: " + uri); + } else { + throw new IOException("Unsupported scheme for uri: " + uri); + } + } +} From df1fe7c5b84bdca0eeeff3208e7a3459142e7d51 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 29 Dec 2016 01:46:00 +0100 Subject: [PATCH 23/48] Port to UriHelper --- .../gadgetbridge/devices/miband/AbstractMiBandFWHelper.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/AbstractMiBandFWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/AbstractMiBandFWHelper.java index b328bafaf..76faf56e1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/AbstractMiBandFWHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/AbstractMiBandFWHelper.java @@ -15,6 +15,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; +import nodomain.freeyourgadget.gadgetbridge.util.UriHelper; /** * Also see Mi1SFirmwareInfo. @@ -26,12 +27,13 @@ public abstract class AbstractMiBandFWHelper { private final byte[] fw; public AbstractMiBandFWHelper(Uri uri, Context context) throws IOException { + UriHelper uriHelper = UriHelper.get(uri, context); String pebblePattern = ".*\\.(pbw|pbz|pbl)"; - if (uri.getPath().matches(pebblePattern)) { + if (uriHelper.getFileName().matches(pebblePattern)) { throw new IOException("Firmware has a filename that looks like a Pebble app/firmware."); } - try (InputStream in = new BufferedInputStream(context.getContentResolver().openInputStream(uri))) { + try (InputStream in = new BufferedInputStream(uriHelper.openInputStream())) { this.fw = FileUtils.readAll(in, 1024 * 1024); // 1 MB determineFirmwareInfo(fw); } catch (IOException ex) { From 5f48b89dc5149d20142a78cd598fc37276b76965 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Thu, 29 Dec 2016 17:12:44 +0100 Subject: [PATCH 24/48] Update changelog --- CHANGELOG.md | 2 ++ app/src/main/res/xml/changelog_master.xml | 1 + 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24985ba3a..6d8858659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ * Charts (Live Activity): Fix axis labels color in dark theme * Mi Band: Fix ginormous step count when using Live Activity * Mi Band: Improved performance during activity sync +* Support sharing firmwares/watchapps/watchfaces to Gadgetbridge + ####Version 0.15.2 * Mi Band: Fix crash with unknown notification sources diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 946923366..669064ea5 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -7,6 +7,7 @@ Charts (Live Activity): Fix axis labels color in dark theme Mi Band: Fix ginormous step count when using Live Activity Mi Band: Improved performance during activity sync + Support sharing firmwares/watchapps/watchfaces to Gadgetbridge Mi Band: Fix crash with unknown notification sources From b1914a140c6b921c9c42b3ec01f92f22199eed7e Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Thu, 29 Dec 2016 17:14:14 +0100 Subject: [PATCH 25/48] Update contributors list and script (so that it only counts contributions to master branch) --- CONTRIBUTORS.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index e6698fda0..ca95966ba 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -2,7 +2,7 @@ names () { echo -e "\n exit;\n**Contributors (sorted by number of commits):**\n"; - git log --all --format='%aN:%aE' | sed 's/@users.github.com/@users.noreply.github.com/g' | awk 'BEGIN{FS=":"}{ct[$2]+=1;if (length($1) > length(e[$2])) {e[$2]=$1}}END{for (i in e) { n[e[i]]=i;c[e[i]]+=ct[i] }; for (a in n) print c[a]"\t* "a" <"n[a]">";}' | sort -n -r | cut -f 2- + git log --format='%aN:%aE' origin/master | sed 's/@users.github.com/@users.noreply.github.com/g' | awk 'BEGIN{FS=":"}{ct[$2]+=1;if (length($1) > length(e[$2])) {e[$2]=$1}}END{for (i in e) { n[e[i]]=i;c[e[i]]+=ct[i] }; for (a in n) print c[a]"\t* "a" <"n[a]">";}' | sort -n -r | cut -f 2- } quine () { @@ -26,15 +26,17 @@ * Carsten Pfeiffer * Daniele Gobbetti * Julien Pivotto +* João Paulo Barraca * Steffen Liebergeld * Lem Dulfo * Sergey Trofimov * JohnnySun * Uwe Hermann -* Gergely Peidl * 0nse <0nse@users.noreply.github.com> +* Gergely Peidl * Christian Fischer * Normano64 +* 6arms1leg * Ⲇⲁⲛⲓ Φi * xzovy * xphnx @@ -56,7 +58,6 @@ * atkyritsis * andre * Alexey Afanasev -* 6arms1leg And all the Transifex translators, which I cannot automatically list, at the moment. From e77c4e7bdb74bca3e101ee5b9e36b7caabbcaa63 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 29 Dec 2016 21:08:52 +0100 Subject: [PATCH 26/48] Mention ZeBand as supported device --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 85dd7da02..53585a88f 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ need to create an account and transmit any of your data to the vendor's servers. * Mi Band 2 * Vibratissimo (experimental) * Liveview +* HPlus Devices (e.g. ZeBand) ## Features (Pebble) From 5d3c45d2c0063782e63b59ff8e28832e9f2b3663 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 29 Dec 2016 23:23:20 +0100 Subject: [PATCH 27/48] Mi2: Remember and use last synced timestamp in preferences (instead of using the last sample's timestamp in the database. The database also contains manual hr measurements and live activity samples, so we would miss activity data before the last manual measurement. Closes #478 --- .../operations/FetchActivityOperation.java | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/FetchActivityOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/FetchActivityOperation.java index 7f32886e9..cc70c4398 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/FetchActivityOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/FetchActivityOperation.java @@ -2,6 +2,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; +import android.content.SharedPreferences; +import android.support.annotation.NonNull; import android.widget.Toast; import org.slf4j.Logger; @@ -23,7 +25,6 @@ import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; -import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2SampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandSampleProvider; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; @@ -73,7 +74,7 @@ public class FetchActivityOperation extends AbstractMiBand2Operation { builder.notify(characteristicFetch, true); BluetoothGattCharacteristic characteristicActivityData = getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_5_ACTIVITY_DATA); - GregorianCalendar sinceWhen = getLastSuccessfulSynchronizedTime(); + GregorianCalendar sinceWhen = getLastSuccessfulSyncTime(); builder.write(characteristicFetch, BLETypeConversions.join(new byte[] { MiBand2Service.COMMAND_ACTIVITY_DATA_START_DATE, 0x01 }, getSupport().getTimeBytes(sinceWhen, TimeUnit.MINUTES))); builder.add(new WaitAction(1000)); // TODO: actually wait for the success-reply builder.notify(characteristicActivityData, true); @@ -81,26 +82,28 @@ public class FetchActivityOperation extends AbstractMiBand2Operation { builder.queue(getQueue()); } - private GregorianCalendar getLastSuccessfulSynchronizedTime() { - try (DBHandler dbHandler = GBApplication.acquireDB()) { - DaoSession session = dbHandler.getDaoSession(); - SampleProvider sampleProvider = new MiBand2SampleProvider(getDevice(), session); - MiBandActivitySample sample = sampleProvider.getLatestActivitySample(); - if (sample != null) { - int timestamp = sample.getTimestamp(); - GregorianCalendar calendar = BLETypeConversions.createCalendar(); - calendar.setTimeInMillis((long) timestamp * 1000); - return calendar; - } - } catch (Exception ex) { - LOG.error("Error querying for latest activity sample, synchronizing the last 10 days", ex); + private GregorianCalendar getLastSuccessfulSyncTime() { + long timeStampMillis = GBApplication.getPrefs().getLong(getLastSyncTimeKey(), 0); + if (timeStampMillis != 0) { + GregorianCalendar calendar = BLETypeConversions.createCalendar(); + calendar.setTimeInMillis(timeStampMillis); + return calendar; } - GregorianCalendar calendar = BLETypeConversions.createCalendar(); calendar.add(Calendar.DAY_OF_MONTH, -10); return calendar; } + private void saveLastSyncTimestamp(@NonNull GregorianCalendar timestamp) { + SharedPreferences.Editor editor = GBApplication.getPrefs().getPreferences().edit(); + editor.putLong(getLastSyncTimeKey(), timestamp.getTimeInMillis()); + editor.apply(); + } + + private String getLastSyncTimeKey() { + return getDevice().getAddress() + "_" + "lastSyncTimeMillis"; + } + @Override public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { @@ -147,6 +150,7 @@ public class FetchActivityOperation extends AbstractMiBand2Operation { } sampleProvider.addGBActivitySamples(samples.toArray(new MiBandActivitySample[0])); + saveLastSyncTimestamp(timestamp); LOG.info("Mi2 activity data: last sample timestamp: " + DateTimeUtils.formatDateTime(timestamp.getTime())); } catch (Exception ex) { From bf777800d2ec8e45bf663d2bc613c3d08f74407a Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 29 Dec 2016 23:27:49 +0100 Subject: [PATCH 28/48] Update changelog for #478 --- CHANGELOG.md | 1 + app/src/main/res/xml/changelog_master.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d8858659..36554d687 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * Charts (Live Activity): Fix axis labels color in dark theme * Mi Band: Fix ginormous step count when using Live Activity * Mi Band: Improved performance during activity sync +* Mi Band 2: Fix activity data missing after doing manual hr measurements or live activity * Support sharing firmwares/watchapps/watchfaces to Gadgetbridge ####Version 0.15.2 diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 669064ea5..41cf05c7a 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -7,6 +7,7 @@ Charts (Live Activity): Fix axis labels color in dark theme Mi Band: Fix ginormous step count when using Live Activity Mi Band: Improved performance during activity sync + Mi Band 2: Fix activity data missing after doing manual hr measurements or live activity Support sharing firmwares/watchapps/watchfaces to Gadgetbridge From cde3b369682569628cf62cb4b2f592f68e76c88b Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 29 Dec 2016 23:30:18 +0100 Subject: [PATCH 29/48] Updated translations from transifex (thanks!) --- app/src/main/res/values-fr/strings.xml | 107 ++++++++++++++----------- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values-ko/strings.xml | 5 +- app/src/main/res/values-pl/strings.xml | 78 +++++++++++++++++- app/src/main/res/values-ru/strings.xml | 5 +- app/src/main/res/values-uk/strings.xml | 5 +- 6 files changed, 144 insertions(+), 58 deletions(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index f634a3405..46d61389c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -6,12 +6,13 @@ Déboguer Quitter Synchroniser - Moniteur de sommeil (ALPHA) - Trouver l\'appareil + Suivi du sommeil (ALPHA) + Retrouver un appareil perdu... Prendre une capture d\'écran Déconnexion - Supprimer l\'appareil - Supprimer %1$s + Supprimer l’appareil + Supprimer %1$s + Ceci va supprimer l’appareil et toutes les données associées ! Déboguer Gestionnaire d\'application @@ -21,8 +22,11 @@ Supprimer Supprimer et effacer du cache Réinstaller + Rechercher dans le magasin d’application Pebble Activer Désactiver + Activer la mesure du rythme cardiaque + Désactiver la mesure du rythme cardiaque Configurer Haut de page @@ -32,7 +36,7 @@ Vous êtes sur le point d\'installer le micrologiciel %s à la place de celui qui est actuellement sur votre Mi Band. Vous êtes sur le point d\'installer les micrologiciels %1$s et %2$s à la place de ceux qui sont actuellement sur votre Mi Band. Ce micrologiciel a été testé et est connu pour être compatible avec Gadgetbridge. - Ce micrologiciel n\'a pas été testé et peut ne pas être compatible avec Gadgetbridge.\n\nIl n\'est pas conseillé de flasher votre Mi Band. + Ce micrologiciel n\'a pas été testé et peut ne pas être compatible avec Gadgetbridge.\n\nIl n\'est pas conseillé de le flasher sur votre Mi Band. Si vous désirez continuer et que tout fonctionne correctement par la suite, SVP informez-en les développeurs de Gadgetbridge pour demander l\'ajout de ce micrologiciel à leur liste: %s Paramètres @@ -51,47 +55,53 @@ Notifications Répétitions Appels téléphoniques - SMS + Textos K9-Mail Messages Pebble Support des applications qui envoient des notification à Pebble par PebbleKit. Support des notifications génériques ... y compris quand l\'écran est allumé Ne Pas Déranger - Arrêter l’envoie des Notification non-désirée en mode Ne Pas Déranger. + Arrêter l’envoi des notifications non-désirées en mode Ne Pas Déranger. toujours quand l\'écran est éteint jamais Applications bloquées Modèles de messages Réponses - Suffixe commun + Suffixe fréquent Raccrocher Mise à jour Pebble Options développeur Adresse Mi Band Paramètres Pebble - Traqueur d\'activité + Traqueurs d\'activité Traqueur d\'activité préféré Synchroniser Pebble Health Synchroniser Misfit Synchroniser Morpheuz - Permettre l\'accès d\'applications tierces Android + Permettre l\'accès aux applications tierces Android Activer le support expérimental pour les applications Android utilisant PebbleKit Lever et coucher de soleil - Envoyer heures de lever et coucher du soleil dans la timeline Pebble en fonction de l\'emplacement + Envoyer les heures de lever et coucher du soleil dans l’historique Pebble en fonction de l\'emplacement Emplacement Obtenir l\'emplacement Latitude Longitude - Garder l\'emplacement à jour - Tenter d\'obtenir la localisation pendant la course à pied, utiliser la localisation enregistré en cas de problème. - Activez la localisation réseau s\'il vous plaît + Garder l’emplacement à jour + Essayer de garder la localisation à jour pendant le fonctionnement, sinon utiliser l’emplacement enregistré. + Veuillez activer la localisation réseau Emplacement obtenu - Protocole des notifications en vigueur + Forcer le protocole de notification Cette option force l\'utilisation du plus récent protocole de notification qui dépend de la version du micrologiciel. ACTIVEZ-LA UNIQUEMENT SI VOUS SAVEZ CE QUE VOUS FAITES! Activer les fonctionnalités non-testées Activer les fonctionnalités non-testées. ACTIVEZ UNIQUEMENT SI VOUS SAVEZ CE QUE VOUS FAITES! + Toujours préférer le BLE + Utiliser le support expérimental du LE pour toutes les Pebble au lieu du Bluetooth classique ; cela requiert l’appairage d\'une \"Pebble LE\" après qu’une non-LE ai déjà été connectée + Limite du GATT MTU de Pebble 2/LE + Si votre Pebble 2/LE ne fonctionne pas correctement, essayez d\'activer cette option pour limiter le MTU (plage valide 20-512) + Activer les logs des Watch App + Ceci permettra à Gadgetbridge de conserver les logs des Watch App (requiert une reconnexion) Tentatives de reconnexion non connecté connexion en cours @@ -106,29 +116,33 @@ Le Bluetooth n\'est pas supporté. Le Bluetooth est désactivé. Cliquez sur l\'appareil pour ouvrir le gestionnaire d\'application - Cliquez sur l\'appareil pour ouvrir l\'activité + Cliquez sur l\'appareil pour ouvrir le gestionnaire d’activité Cliquez sur connecter pour envoyer une vibration Tapotter sur le périphérique pour le connecter. - Connexion impossible. L’adresse Bluetooth est-elle invalide? + Connexion impossible. L’adresse Bluetooth est-elle valide? Gadgetbridge est en fonctionnement - Installation du binaire %1$d/%2$d - échec d\'installation! - Installation réalisé + Installation du fichier %1$d/%2$d + échec de l\'installation ! + Installation réalisée avec succès VOUS TENTEZ D\'INSTALLER UN MICROLOGICIEL, PROCÉDEZ À VOS PROPRES RISQUES.\n\n\nCe micrologiciel est pour la version de matériel: %s Vous êtes sur le point d\'installer l\'application suivante:\n\n\n%1$s Version %2$s par %3$s\n N.D. Initialisé %1$s par %2$s - Découvrir les appareils - Arrêter le balayage - Démarrer le balayage + Scanner les appareils + Arrêter le scan + Démarrer le scan Connecter un nouvel appareil %1$s (%2$s) - Coupler l\'appareil - Utiliser le couplement Bluetooth d\'Android pour coupler l\'appareil - Coupler votre Mi Band - Coupler avec %s... - Aucune adresse mac fournie, ne peut être couplé + Appairer l\'appareil + Utiliser l’appairage Bluetooth d\'Android pour appairer l\'appareil + Appairer votre Mi Band + Appairage avec %s... + Création d’un lien avec %1$s (%2$s) + Impossible se s’appairer avec %1$s (%2$s) + Création du lien en cours : %1$s (%2$s) + Déjà lié avec %1$s (%2$s), connexion... + Aucune adresse MAC fournie, ne peut être appairé Paramètres spécifiques à l\'appareil Paramètres Mi Band Homme @@ -139,7 +153,7 @@ Aucune donnée utilisateur valide fournie, utilisation de données fictives pour le moment Quand votre Mi Band vibre et clignote, appuyez dessus plusieurs fois d\'affilée. Installer - Rendre votre montre découvrable. Pour l\'instant les appareils connectés ne seront probablement pas découvert. Si votre montre n’apparaît pas après 2 minutes, essayer à nouveau après avoir redémarré. + Mettez votre appareil en mode visible. Les appareils déjà connectés ne sont pas visibles. Sur Android 6 ou supérieur, vous devez activer la localisation (ex. GPS). Si votre appareil n\'est pas visible après 2 minutes, réessayez après avoir redémarré votre téléphone. Note: Image de l\'appareil Nom/Pseudo @@ -149,7 +163,7 @@ Initialisation Récupération des données d\'activité De %1$s à %2$s - Côté de port du bracelet + Port main gauche ou droite? Profil de vibration Saccadé Court @@ -159,15 +173,15 @@ Sonnette Réveil Vibration - Notification SMS - Clavardage (Chat) - Navigation - Réseaux sociaux + Essayer + Notification Texto Paramètres des vibrations Notification générique - Notification Pebble - Notification e-mail + Notification des Mails Notification d\'appels entrants + Tchat + Navigation + Réseau social Trouver l\'appareil perdu Annuler pour arrêter les vibrations Votre activité @@ -193,7 +207,7 @@ Impossible de trouver un gestionnaire pour installer ce fichier. Impossible d\'installer le ficher suivant: %1$s Impossible d\'installer le micrologiciel spécifié: il ne correspond pas à la version du matériel de votre Pebble. - S\'il vous plait patientez pendant la détermination de l\'état de l\'installation... + Veuillez patienter pendant la détermination de l\'état de l\'installation... Niveau de batterie faible! %1$s batterie restante: %2$s%% Dernière charge: %s \n @@ -218,7 +232,7 @@ Échec lors de l\'écriture du micrologiciel Pas Activité en direct - Nombre de pas aujourd\'hui, objectif : %1$s + Nombre de pas aujourd\'hui, objectif: %1$s Ne pas confirmer le transfert de données d\'activités Les données d\'activités ne seront pas effacées du bracelet si elles ne sont pas confirmées. Utile si GB est utilisé avec d\'autres applications. Les données d\'activités seront conservées sur le Mi Band après la synchronisation. Utile si GB est utilisé avec d\'autres applications. @@ -241,11 +255,11 @@ Alarmes à réserver pour événements futurs Utiliser le capteur cardiaque pour améliorer la précision du sommeil La compensation de temps en heure (pour détecter le sommeil de travailleurs en rotation, par exemple) - Mi band 2 : format de l\'heure - Heure seule - - Allumer quand le poignet se lève - About to transfer data since %1$s + Mi2 : Format de la date + Heure + + Allumer l\'écran lors d\'un mouvement + Sur le point de transférer des données depuis %1$s en attente de reconnexion A propos de vous Année de naissance @@ -256,7 +270,7 @@ authentification requise ZzZz Ajouter un widget - Durée préférée de sommeil en heures + Préférer le mode heure pendant le sommeil Une alarme a été enregistré pour %1$02d:%2$02d Modèle: %1$s Micrologiciel: %1$s @@ -304,11 +318,14 @@ Si vous avez déjà importé vos données et êtes satisfait du résultat, vous Échec de la destruction de la base de donnée. Voulez vous détruire les anciennes activités de la base ? Voulez vous vraiment détruire entièrement la base de donnée ? Toutes vos données non importé seront perdu. - Les ancienne données d\'activité ont été effacés correctement. + Les anciennes données d\'activité ont été effacées correctement. Échec de la destruction de l\'ancienne base de donnée. Écraser Annuler Supprimer Vibration + + Appairage avec une Pebble + Une fenêtre d’appairage va s’afficher sur votre téléphone. Si cela ne se produit pas, regardez dans vos notifications et acceptez la demande d’appairage. Acceptez ensuite la demande d’appairage sur votre Pebble. diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index fe603a9c5..288bd93d8 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -138,7 +138,6 @@ Dati dell\'utente non inseriti, vengono usati dati d\'esempio. Quando la Mi Band vibra e lampeggia, dalle qualche leggero colpetto. Installa - Imposta il tuo dispositivo perchè sia rilevabile. I dispositivi attualmente connessi non saranno probabilmente rilevati. Se non vedi il tuo dispositivo entro un paio di minuti, riprova dopo avere riavviato il dispositivo Android. Nota: Immagine dispositivo Nome / Soprannome @@ -299,4 +298,5 @@ Si possono importare i dati da Mi Band, Pebble Health e Morpheuz, NON quelli di Cancella Vibrazione + diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 4c993ae85..2f42f669e 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -108,7 +108,6 @@ 올바르지 않은 사용자 정보입니다. 일단 임시 사용자 정보를 사용합니다. Mi Band가 진동하고 깜빡일 때, 연달아 몇 번 두드리세요. 설치 - 기기를 발견 가능하도록 설정하세요. 현재 연결된 기기들은 발견될 수 없습니다. 2분이 지나도 기기가 나타나지 않는다면 재부팅 후 다시 시도해보세요. 알림: 기기 이미지 이름/별명 @@ -131,8 +130,6 @@ SMS 알림 진동 설정 일반 알림 - Pebble 알림 - Mail 알림 걸려오는 전화 알림 잃어버린 기기 찾기 진동을 멈추려면 취소를 선택하세요. @@ -226,4 +223,6 @@ 심박수 삭제 + + diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 885356aa3..2a4484ce2 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -3,17 +3,32 @@ Gadgetbridge Gadgetbridge Ustawienia - Usuń błąd + Debuguj Zakończ Synchronizuj Monitor snu (ALPHA) Odnajdź zagubione urządzenie - Zrób printscreen + Zrób screena Rozłącz + Usuń urządzenie + Usuń %1$s + To usunie urządzenie oraz zgromadzone dane Usuń błąd Zarządzanie aplikacjami + Aplikacje w pamięci + Zainstalowane aplikacje + Zainstalowane tarcze Usuń + Odinstaluj i usuń z pamięci + Zainstaluj ponownie + Szukaj w Pebble Appstore + Aktywuj + Deaktywuj + Aktywuj HRM + Deaktywuj HRM + Konfiguruj + Przejdź do góry Czarna lista powiadomień @@ -26,11 +41,16 @@ Ustawienia Ustawienia ogólne Połącz z urządzeniem gdy Bluetooth jest włączone + Łącz automatycznie Domyślny odtwarzacz muzyki Domyślny Data i godzina Synchronizuj czas Synchronizuj czas urządzenia podczas połączenia gdy czas lub strefa czasowa zmienia się na Androidzie + Motyw + Jasny + Ciemny + Język Powiadomienia Powtórzenia Połączenia @@ -39,19 +59,41 @@ Wiadomości Pebble Obsługa ogólnych powiadomień ... także gdy ekran jest włączony + Nie przeszkadzaj zawsze gdy ekran jest wyłączony nigdy Czarna lista aplikacji + Wiadomości zwrotne + Odpowiedzi + Uaktualnij na Pebble Ustawienia programisty Adres Mi Band Ustawienia Pebble + Monitory aktywności + Preferowany monitor + Synchronizuj Pebble Health + Synchronizuj Misfit + Synchronizuj Morpheuz Zezwól zewnętrznym aplikacjom Android na dostęp Włącz eksperymentalną obsługę aplikacji android przez PebbleKit + Wschód i zachód + Wyślij wschód i zachód do linii czasu Pebble bazując na lokalizacji + Lokalizacja + Otrzymaj lokalizację + Szerokość + Długość + Utrzymuj aktualną lokalizację + Włącz usługę lokalizacji + Lokalizacja otrzymana Wymuś protokół komunikacji Ta opcja wymusza użycie najnowszego protokołu powiadomień w zależności od wersji firmware. WŁĄCZ JEDYNIE JEŚLI WIESZ CO ROBISZ! Włącz nietestowane funkcje Włącz nie testowane funkcje. WŁĄCZ JEDYNIE JEŚLI WIESZ CO ROBISZ! + Preferuj BLE + Pebble 2/LE GATT limit MTU + Jeśli Twój Pebble 2/ Pebble LE nie działa jak należy spróbuj ustawić ten limit MTU (zakres 20-512) + Włącz logowanie aplikacji Próby ponownego połączenia nie połączony łącze @@ -65,6 +107,8 @@ To jest testowe powiadomienie z Gadgetbridge Bluetooth nie jest obsługiwane Bluetooth jest wyłączone + Tapnij urządzenie aby uruchomić menadżer aplikacji + Dotknij urządzenie aby połączyć Nie można połączyć. Adres BT nieprawidłowy? Gadgetbridge działa Instalowanie binarki %1$d/%2$d @@ -116,9 +160,10 @@ Powiadomienie SMS Ustawienia wibracji Ogólne powiadomienia - Powiadomienia Pebble Powiadomienia email Powiadomienia o połaczeniach przychodzących + Nawigacja + Sieć spolecznościowa Odnajdź zagubione urządzenie Anuluj by przerwać wibracje. Twoja aktywność @@ -173,6 +218,7 @@ Nie wysyłaj danych aktywności Gdy dane aktywności nie są przesłane na opaskę, wtedy nie będą usuwane. Przydatne gdy Gadgetbridge jest używany wraz z innymi aplikacjami Dane aktywności będą zachowane na Mi Band nawet po synchronizacji. Przydatne gdy Gadgetbridge jest używany z innymi aplikacjami. + To może pomóc na urządzeniach gdzie uaktualnienie kończy się błędem Historia kroków Aktualnie kroków/min Kroków łącznie @@ -188,12 +234,38 @@ Niekompatybilny firmware Ten firmware nie jest kompatybilny z urządzeniem Alarmy zarezerwowane dla nadchodzących zdarzeń + Użyj czujnika tętna alby poprawić detekcje snu + Mi2: Format daty + Czas oczekiwanie na ponowne połaczenie O tobie Data urodzenia Płeć Wzrost w cm Waga w kg + Dodaj widget + Preferowana długość snu w godzinach + Hardware: %1$s + Firmware: %1$s + Trwa aktualizacja firmware + Puls + Puls + Import bazydanych + Import starszych danych aktywności + Zarządzanie bazą danych + Zarządzanie bazą danych + Importuj / Usuń starą bazę danych + Wyeksportowano do: %1$s + Błąd eksportu bazy: %1$s + Zaimportować? + Naprawdę chcesz napisać bazę? Wszystkie Twoje dane zostaną zastąpione. + Błąd importu bazy: %1$s + Nie znaleziono aktywności, nic do importu. + Nadpisz + Anuluj Usuń + + Wibracje + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 2041edd10..7284db28f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -99,7 +99,6 @@ Сопряжение устройств Для сопряжения устройств используйте диалог Android. Сопряжение вашего Mi Band - Сопряжение с %s… MAC-адрес не был передан, сопряжение не удалось. Настройки устройства Настройки Mi Band @@ -133,8 +132,6 @@ SMS-уведомление Настройки вибро Общие уведомления - Уведомления Pebble - Уведомления почты Уведомления о входящем звонке Найти потерянное устройство Отмените, чтобы остановить вибро @@ -223,4 +220,6 @@ Обновление прошивки в процессе Удалить + + diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 3779ce4aa..1d966d845 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -105,7 +105,6 @@ Створення пари з пристроєм Для створення пари із пристроєм використовуйте діалог Android. Створення пари із вашим Mi—Band - Створення пари із %s… MAC-адресу не було передано, не вдалося створити пару. Параметри пристрою Параметри Mi—Band @@ -138,8 +137,6 @@ SMS-сповіщення Параметри вібро Загальні сповіщення - Сповіщення Pebble - Сповіщення пошти Сповіщення під час вхідного дзвінку Знайти загублений пристрій Скасуйте, аби зупинити вібро @@ -220,4 +217,6 @@ ПЗ: %1$s Вилучити + + From b2d9c357e790dbb06497f64f83bed8f0450a7888 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 29 Dec 2016 23:46:18 +0100 Subject: [PATCH 30/48] Update changelog for Subsonic #474 --- CHANGELOG.md | 1 + app/src/main/res/xml/changelog_master.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36554d687..aa1ae6d9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * Mi Band: Improved performance during activity sync * Mi Band 2: Fix activity data missing after doing manual hr measurements or live activity * Support sharing firmwares/watchapps/watchfaces to Gadgetbridge +* Support for the "Subsonic" music player (#474) ####Version 0.15.2 * Mi Band: Fix crash with unknown notification sources diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 41cf05c7a..d9e4591af 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -9,6 +9,7 @@ Mi Band: Improved performance during activity sync Mi Band 2: Fix activity data missing after doing manual hr measurements or live activity Support sharing firmwares/watchapps/watchfaces to Gadgetbridge + Support for the "Subsonic" music player (#474) Mi Band: Fix crash with unknown notification sources From 240c81ecb4ae8f09c88487a5b29a6faed0d9876d Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Fri, 30 Dec 2016 15:26:44 +0100 Subject: [PATCH 31/48] Pebble: implement weather related protocol encoding this is not yet connected to anything... --- .../devices/pebble/PebbleProtocol.java | 172 +++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 762e7166c..39bd0cee2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -87,8 +87,10 @@ public class PebbleProtocol extends GBDeviceProtocol { static final byte BLOBDB_APP = 2; static final byte BLOBDB_REMINDER = 3; static final byte BLOBDB_NOTIFICATION = 4; + static final byte BLOBDB_WEATHER = 5; static final byte BLOBDB_CANNED_MESSAGES = 6; static final byte BLOBDB_PREFERENCES = 7; + static final byte BLOBDB_APPSETTINGS = 9; static final byte BLOBDB_APPGLANCE = 11; static final byte BLOBDB_SUCCESS = 1; @@ -378,6 +380,8 @@ public class PebbleProtocol extends GBDeviceProtocol { private static final UUID UUID_ZERO = new UUID(0, 0); + private static final UUID UUID_LOCATION = UUID.fromString("2c7e6a86-51e5-4ddd-b606-db43d1e4ad28"); // might be the location of "Berlin" or "Auto" + private final Map mAppMessageHandlers = new HashMap<>(); public PebbleProtocol(GBDevice device) { @@ -534,7 +538,15 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeFindDevice(boolean start) { - return encodeSetCallState("Where are you?", "Gadgetbridge", start ? CallSpec.CALL_INCOMING : CallSpec.CALL_END); + // return encodeSetCallState("Where are you?", "Gadgetbridge", start ? CallSpec.CALL_INCOMING : CallSpec.CALL_END); + int ts = (int) (System.currentTimeMillis() / 1000); + + if (start) { + return encodeActivateWeather(true); + } else { + //return encodeWeatherPin(ts, "Weather", "1°/-1°", "Gadgetbridge is Sunny", "Berlin", 37); + return encodeWeatherForecast(ts, "Berlin", 0, 5, -5, 1, "Sexy", 7, 2, 1); + } } private byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, String[] cannedReplies) { @@ -765,6 +777,21 @@ public class PebbleProtocol extends GBDeviceProtocol { activate ? new byte[]{0x01} : new byte[]{0x00}); } + byte[] encodeActivateWeather(boolean activate) { + if (activate) { + ByteBuffer buf = ByteBuffer.allocate(0x61); + buf.put((byte) 1); + buf.order(ByteOrder.BIG_ENDIAN); + buf.putLong(UUID_LOCATION.getMostSignificantBits()); + buf.putLong(UUID_LOCATION.getLeastSignificantBits()); + // disable remaining 5 possible location + buf.put(new byte[60 - 16]); + return encodeBlobdb("weatherApp", BLOBDB_INSERT, BLOBDB_APPSETTINGS, buf.array()); + } else { + return encodeBlobdb("weatherApp", BLOBDB_DELETE, BLOBDB_APPSETTINGS, null); + } + } + byte[] encodeReportDataLogSessions() { return encodeSimpleMessage(ENDPOINT_DATALOG, DATALOG_REPORTSESSIONS); } @@ -1005,6 +1032,149 @@ public class PebbleProtocol extends GBDeviceProtocol { return buf.array(); } + private byte[] encodeWeatherPin(int timestamp, String title, String subtitle, String body, String location, int iconId) { + final short NOTIFICATION_PIN_LENGTH = 46; + final short ACTION_LENGTH_MIN = 10; + + String[] parts = {title, subtitle, body, location, "test", "test"}; + + // Calculate length first + byte actions_count = 1; + short actions_length; + String remove_string = "Remove"; + actions_length = (short) (ACTION_LENGTH_MIN * actions_count + remove_string.getBytes().length); + + byte attributes_count = 3; + short attributes_length = (short) (21 + actions_length); + if (parts != null) { + for (String s : parts) { + if (s == null || s.equals("")) { + continue; + } + attributes_count++; + attributes_length += (3 + s.getBytes().length); + } + } + + UUID uuid = UUID.fromString("61b22bc8-1e29-460d-a236-3fe409a43901"); + + short pin_length = (short) (NOTIFICATION_PIN_LENGTH + attributes_length); + + ByteBuffer buf = ByteBuffer.allocate(pin_length); + + // pin (46 bytes) + buf.order(ByteOrder.BIG_ENDIAN); + buf.putLong(uuid.getMostSignificantBits()); + buf.putLong(uuid.getLeastSignificantBits()); + buf.putLong(uuid.getMostSignificantBits()); + buf.putLong(uuid.getLeastSignificantBits() | 0xff); + buf.order(ByteOrder.LITTLE_ENDIAN); + buf.putInt(timestamp); // 32-bit timestamp + buf.putShort((short) 0); // duration + buf.put((byte) 0x02); // type (0x02 = pin) + buf.putShort((short) 0x0001); // flags 0x0001 = ? + buf.put((byte) 0x06); // layout (0x06 = weather) + buf.putShort(attributes_length); // total length of all attributes and actions in bytes + buf.put(attributes_count); + buf.put(actions_count); + + byte attribute_id = 0; + // Encode Pascal-Style Strings + if (parts != null) { + for (String s : parts) { + attribute_id++; + if (s == null || s.equals("")) { + continue; + } + + int partlength = s.getBytes().length; + if (partlength > 512) partlength = 512; + if (attribute_id == 4) { + buf.put((byte) 11); + } else if (attribute_id == 5) { + buf.put((byte) 25); + } else if (attribute_id == 6) { + buf.put((byte) 26); + } else { + buf.put(attribute_id); + } + buf.putShort((short) partlength); + buf.put(s.getBytes(), 0, partlength); + } + } + + buf.put((byte) 4); // icon + buf.putShort((short) 4); // length of int + buf.putInt(0x80000000 | iconId); + + buf.put((byte) 6); // icon + buf.putShort((short) 4); // length of int + buf.putInt(0x80000000 | iconId); + + buf.put((byte) 14); // last updated + buf.putShort((short) 4); // length of int + buf.putInt(timestamp); + + // remove action + buf.put((byte) 123); // action id + buf.put((byte) 0x09); // remove + buf.put((byte) 0x01); // number attributes + buf.put((byte) 0x01); // attribute id (title) + buf.putShort((short) remove_string.getBytes().length); + buf.put(remove_string.getBytes()); + + return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array()); + } + + private byte[] encodeWeatherForecast(int timestamp, String location, int tempNow, int tempHighToday, int tempLowToday, int conditionCodeToday, String conditionToday, int tempHighTomorrow, int tempLowTomorrow, int conditionCodeTomorrow) { + final short WEATHER_FORECAST_LENGTH = 20; + + String[] parts = {location, conditionToday}; + + // Calculate length first + short attributes_length = 0; + if (parts != null) { + for (String s : parts) { + if (s == null || s.equals("")) { + continue; + } + attributes_length += (2 + s.getBytes().length); + } + } + + short pin_length = (short) (WEATHER_FORECAST_LENGTH + attributes_length); + + ByteBuffer buf = ByteBuffer.allocate(pin_length); + buf.order(ByteOrder.LITTLE_ENDIAN); + buf.put((byte) 3); // unknown, always 3? + buf.putShort((short) tempNow); + buf.put((byte) 1); + buf.putShort((short) tempHighToday); + buf.putShort((short) tempLowToday); + buf.put((byte) 4); + buf.putShort((short) tempHighTomorrow); + buf.putShort((short) tempLowTomorrow); + buf.putInt(timestamp); + buf.put((byte) 0); // automatic location + buf.putShort(attributes_length); + + // Encode Pascal-Style Strings + if (parts != null) { + for (String s : parts) { + if (s == null || s.equals("")) { + continue; + } + + int partlength = s.getBytes().length; + if (partlength > 512) partlength = 512; + buf.putShort((short) partlength); + buf.put(s.getBytes(), 0, partlength); + } + } + + return encodeBlobdb(UUID_LOCATION, BLOBDB_INSERT, BLOBDB_WEATHER, buf.array()); + } + private byte[] encodeActionResponse(UUID uuid, int iconId, String caption) { short length = (short) (29 + caption.getBytes().length); ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + length); From 0e9ce5d1866d05bb414d048c6a1915ac1101ec5e Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Fri, 30 Dec 2016 19:58:56 +0100 Subject: [PATCH 32/48] Pebble: get min/max temperature also for the forecast --- .../pebble/AppMessageHandlerTimeStylePebble.java | 4 ++-- .../weather/notification/ParcelableWeather2.java | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java index d20aa615e..784603a42 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java @@ -105,8 +105,8 @@ public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { pairs.add(new Pair<>(MESSAGE_KEY_WeatherTemperature, (Object) (weather.currentTemp - 273))); pairs.add(new Pair<>(MESSAGE_KEY_WeatherCondition, (Object) (getIconForConditionCode(weather.currentConditionCode, isNight)))); pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastCondition, (Object) (getIconForConditionCode(weather.forecastConditionCode, isNight)))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastHighTemp, (Object) (weather.highTemp - 273))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastLowTemp, (Object) (weather.lowTemp - 273))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastHighTemp, (Object) (weather.todayHighTemp - 273))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastLowTemp, (Object) (weather.todayLowTemp - 273))); } return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); diff --git a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java index 8defe1e05..0fc34ab2c 100644 --- a/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java +++ b/app/src/main/java/ru/gelin/android/weather/notification/ParcelableWeather2.java @@ -23,8 +23,10 @@ public class ParcelableWeather2 implements Parcelable { public int currentConditionCode = 3200; String[] forecastConditionType = null; public int forecastConditionCode = 3200; - public int lowTemp = 0; - public int highTemp = 0; + public int todayLowTemp = 0; + public int todayHighTemp = 0; + public int forecastLowTemp = 0; + public int forecastHighTemp = 0; private ParcelableWeather2(Parcel in) { @@ -33,6 +35,7 @@ public class ParcelableWeather2 implements Parcelable { return; } Bundle bundle = in.readBundle(); + location = bundle.getString("weather_location"); time = bundle.getLong("weather_time"); queryTime = bundle.getLong("weather_query_time"); @@ -46,13 +49,15 @@ public class ParcelableWeather2 implements Parcelable { currentConditionType = conditionBundle.getStringArray("weather_condition_types"); currentConditionCode = weatherConditionTypesToOpenWeatherMapIds(currentConditionType[0]); - lowTemp = conditionBundle.getInt("weather_low_temp"); - highTemp = conditionBundle.getInt("weather_high_temp"); + todayLowTemp = conditionBundle.getInt("weather_low_temp"); + todayHighTemp = conditionBundle.getInt("weather_high_temp"); //fetch immediate next forecast if (--conditions > 0) { Bundle forecastBundle = in.readBundle(); forecastConditionType = forecastBundle.getStringArray("weather_condition_types"); forecastConditionCode = weatherConditionTypesToOpenWeatherMapIds(forecastConditionType[0]); + forecastLowTemp = forecastBundle.getInt("weather_low_temp"); + forecastHighTemp = forecastBundle.getInt("weather_high_temp"); } } // get the rest From e477d22c88df4bf651f99e60989b974fc5d46259 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Fri, 30 Dec 2016 20:14:13 +0100 Subject: [PATCH 33/48] Pebble: support the system weather app. - enable/disable weather app from the watchapp list - convert weather data to a format that can be displayed by the system app TODO: send the weather data periodically --- .../AbstractAppManagerFragment.java | 7 ++ .../AppManagerFragmentInstalledApps.java | 3 + .../gadgetbridge/model/Weather.java | 111 ++++++++++++++++++ .../devices/pebble/PebbleIoThread.java | 4 + .../devices/pebble/PebbleProtocol.java | 31 ++++- app/src/main/res/menu/appmanager_context.xml | 6 + app/src/main/res/values/strings.xml | 2 + 7 files changed, 161 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java index 3c0de5ae0..50038a9fd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java @@ -199,6 +199,9 @@ public abstract class AbstractAppManagerFragment extends Fragment { if (baseName.equals("3af858c3-16cb-4561-91e7-f1ad2df8725f")) { cachedAppList.add(new GBDeviceApp(UUID.fromString(baseName), "Kickstart (System)", "Pebble Inc.", "", GBDeviceApp.Type.WATCHFACE_SYSTEM)); } + if (baseName.equals(PebbleProtocol.UUID_WEATHER.toString())) { + cachedAppList.add(new GBDeviceApp(PebbleProtocol.UUID_WEATHER, "Weather (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); + } } } if (uuids == null) { @@ -367,8 +370,12 @@ public abstract class AbstractAppManagerFragment extends Fragment { case R.id.appmanager_hrm_activate: GBApplication.deviceService().onInstallApp(Uri.parse("fake://hrm")); return true; + case R.id.appmanager_weather_activate: + GBApplication.deviceService().onInstallApp(Uri.parse("fake://weather")); + return true; case R.id.appmanager_health_deactivate: case R.id.appmanager_hrm_deactivate: + case R.id.appmanager_weather_deactivate: GBApplication.deviceService().onAppDelete(selectedApp.getUUID()); return true; case R.id.appmanager_app_configure: diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AppManagerFragmentInstalledApps.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AppManagerFragmentInstalledApps.java index 6cf8bfbbc..fe53c32ca 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AppManagerFragmentInstalledApps.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AppManagerFragmentInstalledApps.java @@ -28,6 +28,9 @@ public class AppManagerFragmentInstalledApps extends AbstractAppManagerFragment if (PebbleUtils.hasHRM(mGBDevice.getModel())) { systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_WORKOUT, "Workout (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); } + if (PebbleUtils.getFwMajor(mGBDevice.getFirmwareVersion()) >= 4) { + systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_WEATHER, "Weather (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); + } } return systemApps; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java index 59981199a..17c8ebc5e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java @@ -10,6 +10,117 @@ public class Weather { private static final Weather weather = new Weather(); public static Weather getInstance() {return weather;} + public static byte mapToPebbleCondition(int openWeatherMapCondition) { +/* deducted values: + 0 = sun + cloud + 1 = clouds + 2 = some snow + 3 = some rain + 4 = heavy rain + 5 = heavy snow + 6 = sun + cloud + rain (default icon?) + 7 = sun + 8 = rain + snow + 9 = 6 + 10, 11, ... = empty icon + */ + switch (openWeatherMapCondition) { +//Group 2xx: Thunderstorm + case 200: //thunderstorm with light rain: //11d + case 201: //thunderstorm with rain: //11d + case 202: //thunderstorm with heavy rain: //11d + 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 4; +//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 + case 500: //light rain: //10d + case 501: //moderate rain: //10d + return 3; +//Group 5xx: Rain + case 502: //heavy intensity rain: //10d + case 503: //very heavy rain: //10d + case 504: //extreme rain: //10d + case 511: //freezing rain: //13d + case 520: //light intensity shower rain: //09d + case 521: //shower rain: //09d + case 522: //heavy intensity shower rain: //09d + case 531: //ragged shower rain: //09d + return 4; +//Group 6xx: Snow + case 600: //light snow: //[[file:13d.png]] + case 601: //snow: //[[file:13d.png]] + case 620: //light shower snow: //[[file:13d.png]] + return 2; + case 602: //heavy snow: //[[file:13d.png]] + case 611: //sleet: //[[file:13d.png]] + case 612: //shower sleet: //[[file:13d.png]] + case 621: //shower snow: //[[file:13d.png]] + case 622: //heavy shower snow: //[[file:13d.png]] + return 5; + case 615: //light rain and snow: //[[file:13d.png]] + case 616: //rain and snow: //[[file:13d.png]] + return 8; +//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 6; +//Group 800: Clear + case 800: //clear sky: //[[file:01d.png]] [[file:01n.png]] + return 7; +//Group 80x: Clouds + case 801: //few clouds: //[[file:02d.png]] [[file:02n.png]] + case 802: //scattered clouds: //[[file:03d.png]] [[file:03d.png]] + case 803: //broken clouds: //[[file:04d.png]] [[file:03d.png]] + case 804: //overcast clouds: //[[file:04d.png]] [[file:04d.png]] + return 0; +//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 + default: + return 6; + + } + } public static int mapToYahooCondition(int openWeatherMapCondition) { // openweathermap.org conditions: // http://openweathermap.org/weather-conditions diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 035fa17b6..923ee95cc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -613,6 +613,10 @@ class PebbleIoThread extends GBDeviceIoThread { write(mPebbleProtocol.encodeActivateHRM(true)); return; } + if (uri.equals(Uri.parse("fake://weather"))) { + write(mPebbleProtocol.encodeActivateWeather(true)); + return; + } if (mIsInstalling) { return; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 39bd0cee2..ea954c151 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -38,7 +38,9 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; +import nodomain.freeyourgadget.gadgetbridge.model.Weather; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; +import ru.gelin.android.weather.notification.ParcelableWeather2; public class PebbleProtocol extends GBDeviceProtocol { @@ -370,6 +372,7 @@ public class PebbleProtocol extends GBDeviceProtocol { public static final UUID UUID_PEBBLE_HEALTH = UUID.fromString("36d8c6ed-4c83-4fa1-a9e2-8f12dc941f8c"); // FIXME: store somewhere else, this is also accessed by other code public static final UUID UUID_WORKOUT = UUID.fromString("fef82c82-7176-4e22-88de-35a3fc18d43f"); // FIXME: store somewhere else, this is also accessed by other code + public static final UUID UUID_WEATHER = UUID.fromString("61b22bc8-1e29-460d-a236-3fe409a439ff"); // FIXME: store somewhere else, this is also accessed by other code private static final UUID UUID_GBPEBBLE = UUID.fromString("61476764-7465-7262-6469-656775527a6c"); private static final UUID UUID_MORPHEUZ = UUID.fromString("5be44f1d-d262-4ea6-aa30-ddbec1e3cab2"); private static final UUID UUID_WHETHERNEAT = UUID.fromString("3684003b-a685-45f9-a713-abc6364ba051"); @@ -545,7 +548,8 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeActivateWeather(true); } else { //return encodeWeatherPin(ts, "Weather", "1°/-1°", "Gadgetbridge is Sunny", "Berlin", 37); - return encodeWeatherForecast(ts, "Berlin", 0, 5, -5, 1, "Sexy", 7, 2, 1); + //return encodeWeatherForecast(ts, "Berlin", 0, 5, -5, 1, "Sexy", 7, 2, 1); + return encodeWeatherForecast(ts); } } @@ -1126,6 +1130,24 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array()); } + private byte[] encodeWeatherForecast(int timestamp) { + ParcelableWeather2 weather = Weather.getInstance().getWeather2(); + if (weather != null) { + return encodeWeatherForecast(timestamp, + weather.location, + weather.currentTemp - 273, + weather.todayHighTemp - 273, + weather.todayLowTemp - 273, + Weather.mapToPebbleCondition(weather.currentConditionCode), + weather.currentCondition, + weather.forecastHighTemp - 273, + weather.forecastLowTemp - 273, + Weather.mapToPebbleCondition(weather.forecastConditionCode) + ); + } + return null; + } + private byte[] encodeWeatherForecast(int timestamp, String location, int tempNow, int tempHighToday, int tempLowToday, int conditionCodeToday, String conditionToday, int tempHighTomorrow, int tempLowTomorrow, int conditionCodeTomorrow) { final short WEATHER_FORECAST_LENGTH = 20; @@ -1148,10 +1170,10 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.order(ByteOrder.LITTLE_ENDIAN); buf.put((byte) 3); // unknown, always 3? buf.putShort((short) tempNow); - buf.put((byte) 1); + buf.put((byte) conditionCodeToday); buf.putShort((short) tempHighToday); buf.putShort((short) tempLowToday); - buf.put((byte) 4); + buf.put((byte) conditionCodeTomorrow); buf.putShort((short) tempHighTomorrow); buf.putShort((short) tempLowTomorrow); buf.putInt(timestamp); @@ -1392,6 +1414,9 @@ public class PebbleProtocol extends GBDeviceProtocol { if (UUID_WORKOUT.equals(uuid)) { return encodeActivateHRM(false); } + if (UUID_WEATHER.equals(uuid)) { //TODO: probably it wasn't present in firmware 3 + return encodeActivateWeather(false); + } return encodeBlobdb(uuid, BLOBDB_DELETE, BLOBDB_APP, null); } else { ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_REMOVEAPP_2X); diff --git a/app/src/main/res/menu/appmanager_context.xml b/app/src/main/res/menu/appmanager_context.xml index 436454388..766f6c5a2 100644 --- a/app/src/main/res/menu/appmanager_context.xml +++ b/app/src/main/res/menu/appmanager_context.xml @@ -21,6 +21,12 @@ + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a9d2e3e2b..6430085cc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -30,6 +30,8 @@ Deactivate Activate HRM Deactivate HRM + Activate system weather app + Deactivate system weather app Configure Move to top From 3280607cc9a587b8c9e9f07e11db7cd27b1a9fe6 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Sat, 31 Dec 2016 10:15:08 +0100 Subject: [PATCH 34/48] Pebble: hide the weather app menu entries on apps that aren't the weather app. --- .../activities/appmanager/AbstractAppManagerFragment.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java index 50038a9fd..3e68b2dfa 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java @@ -295,6 +295,10 @@ public abstract class AbstractAppManagerFragment extends Fragment { menu.removeItem(R.id.appmanager_hrm_activate); menu.removeItem(R.id.appmanager_hrm_deactivate); } + if (!PebbleProtocol.UUID_WEATHER.equals(selectedApp.getUUID())) { + menu.removeItem(R.id.appmanager_weather_activate); + menu.removeItem(R.id.appmanager_weather_deactivate); + } if (selectedApp.getType() == GBDeviceApp.Type.APP_SYSTEM || selectedApp.getType() == GBDeviceApp.Type.WATCHFACE_SYSTEM) { menu.removeItem(R.id.appmanager_app_delete); } From 4631e5bbafde8628533a552492084593e7cfef06 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 12:15:44 +0100 Subject: [PATCH 35/48] Pebble: restore find lost device feature abused for testing --- .../gadgetbridge/service/devices/pebble/PebbleProtocol.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index ea954c151..b6447b788 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -541,16 +541,16 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeFindDevice(boolean start) { - // return encodeSetCallState("Where are you?", "Gadgetbridge", start ? CallSpec.CALL_INCOMING : CallSpec.CALL_END); + return encodeSetCallState("Where are you?", "Gadgetbridge", start ? CallSpec.CALL_INCOMING : CallSpec.CALL_END); + /* int ts = (int) (System.currentTimeMillis() / 1000); if (start) { - return encodeActivateWeather(true); - } else { //return encodeWeatherPin(ts, "Weather", "1°/-1°", "Gadgetbridge is Sunny", "Berlin", 37); //return encodeWeatherForecast(ts, "Berlin", 0, 5, -5, 1, "Sexy", 7, 2, 1); return encodeWeatherForecast(ts); } + */ } private byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, String[] cannedReplies) { From 95e6d2c74021ea3f643c15d7b818ef6c8908e2c5 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 12:35:40 +0100 Subject: [PATCH 36/48] Pebble: delete WeatherNeat handler, it was only used for testing and the watchface seems outdated --- .../pebble/AppMessageHandlerWeatherNeat.java | 61 ------------------- .../devices/pebble/PebbleProtocol.java | 14 ++--- 2 files changed, 6 insertions(+), 69 deletions(-) delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerWeatherNeat.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerWeatherNeat.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerWeatherNeat.java deleted file mode 100644 index ac09bc7a4..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerWeatherNeat.java +++ /dev/null @@ -1,61 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; - -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.util.Pair; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.UUID; - -import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; -import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; - -public class AppMessageHandlerWeatherNeat extends AppMessageHandler { - - public static final int KEY_REQUEST = 0; - public static final int KEY_CITY = 1; - public static final int KEY_TEMPERATURE = 2; - public static final int KEY_CONDITION = 3; - public static final int KEY_LIGHT_TIME = 5; - - private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerWeatherNeat.class); - - public AppMessageHandlerWeatherNeat(UUID uuid, PebbleProtocol pebbleProtocol) { - super(uuid, pebbleProtocol); - } - - private byte[] encodeWeatherNeatMessage(String city, String temperature, String condition, int light_time) { - ArrayList> pairs = new ArrayList<>(4); - pairs.add(new Pair<>(KEY_CITY, (Object) city)); - pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) temperature)); - pairs.add(new Pair<>(KEY_CONDITION, (Object) condition)); - pairs.add(new Pair<>(KEY_LIGHT_TIME, (Object) light_time)); // seconds for backlight on shake - - byte[] ackMessage = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); - byte[] testMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); - - ByteBuffer buf = ByteBuffer.allocate(ackMessage.length + testMessage.length); - - // encode ack and put in front of push message (hack for acknowledging the last message) - buf.put(ackMessage); - buf.put(testMessage); - - return buf.array(); - } - - @Override - public GBDeviceEvent[] handleMessage(ArrayList> pairs) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); - String currentTemp = (sharedPrefs.getInt("weather_current_temp", 0) - 273) + "°C"; - String location = sharedPrefs.getString("weather_location", "unknown"); - String condition = sharedPrefs.getString("weather_current_condition", "unknown"); - GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); - sendBytes.encodedBytes = encodeWeatherNeatMessage(location, currentTemp, condition, 3); - return new GBDeviceEvent[]{sendBytes}; - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index b6447b788..d656cb9c0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -68,7 +68,7 @@ public class PebbleProtocol extends GBDeviceProtocol { static final short ENDPOINT_FCTREG = 5001; static final short ENDPOINT_APPMANAGER = 6000; static final short ENDPOINT_APPFETCH = 6001; // 3.x only - public static final short ENDPOINT_DATALOG = 6778; + static final short ENDPOINT_DATALOG = 6778; static final short ENDPOINT_RUNKEEPER = 7000; static final short ENDPOINT_SCREENSHOT = 8000; static final short ENDPOINT_AUDIOSTREAM = 10000; @@ -272,18 +272,18 @@ public class PebbleProtocol extends GBDeviceProtocol { private static final Random mRandom = new Random(); int mFwMajor = 3; - boolean mForceProtocol = false; - GBDeviceEventScreenshot mDevEventScreenshot = null; - int mScreenshotRemaining = -1; + private boolean mForceProtocol = false; + private GBDeviceEventScreenshot mDevEventScreenshot = null; + private int mScreenshotRemaining = -1; //monochrome black + white - static final byte[] clut_pebble = { + private static final byte[] clut_pebble = { 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00 }; // linear BGR222 (6 bit, 64 entries) - static final byte[] clut_pebbletime = new byte[]{ + private static final byte[] clut_pebbletime = new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, (byte) 0xaa, 0x00, 0x00, 0x00, @@ -375,7 +375,6 @@ public class PebbleProtocol extends GBDeviceProtocol { public static final UUID UUID_WEATHER = UUID.fromString("61b22bc8-1e29-460d-a236-3fe409a439ff"); // FIXME: store somewhere else, this is also accessed by other code private static final UUID UUID_GBPEBBLE = UUID.fromString("61476764-7465-7262-6469-656775527a6c"); private static final UUID UUID_MORPHEUZ = UUID.fromString("5be44f1d-d262-4ea6-aa30-ddbec1e3cab2"); - private static final UUID UUID_WHETHERNEAT = UUID.fromString("3684003b-a685-45f9-a713-abc6364ba051"); private static final UUID UUID_MISFIT = UUID.fromString("0b73b76a-cd65-4dc2-9585-aaa213320858"); private static final UUID UUID_PEBBLE_TIMESTYLE = UUID.fromString("4368ffa4-f0fb-4823-90be-f754b076bdaa"); private static final UUID UUID_PEBSTYLE = UUID.fromString("da05e84d-e2a2-4020-a2dc-9cdcf265fcdd"); @@ -390,7 +389,6 @@ public class PebbleProtocol extends GBDeviceProtocol { public PebbleProtocol(GBDevice device) { super(device); mAppMessageHandlers.put(UUID_MORPHEUZ, new AppMessageHandlerMorpheuz(UUID_MORPHEUZ, PebbleProtocol.this)); - mAppMessageHandlers.put(UUID_WHETHERNEAT, new AppMessageHandlerWeatherNeat(UUID_WHETHERNEAT, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_MISFIT, new AppMessageHandlerMisfit(UUID_MISFIT, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_PEBBLE_TIMESTYLE, new AppMessageHandlerTimeStylePebble(UUID_PEBBLE_TIMESTYLE, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_PEBSTYLE, new AppMessageHandlerPebStyle(UUID_PEBSTYLE, PebbleProtocol.this)); From f12e7868378876f4a0e1474f7bce31ab0f10a926 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 13:33:50 +0100 Subject: [PATCH 37/48] Pebble: fix mario time appmessage handler (weather condition icon hardcoded to sunny for now) --- .../pebble/AppMessageHandlerMarioTime.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java index edfeac41e..869053a18 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java @@ -14,15 +14,15 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.model.Weather; import ru.gelin.android.weather.notification.ParcelableWeather2; -public class AppMessageHandlerMarioTime extends AppMessageHandler { +class AppMessageHandlerMarioTime extends AppMessageHandler { - public static final int KEY_WEATHER_ICON_ID = 10; - public static final int KEY_WEATHER_TEMPERATURE = 11; - public static final int KEY_WEATHER_REQUEST = 12; + private static final int KEY_WEATHER_ICON_ID = 10; + private static final int KEY_WEATHER_TEMPERATURE = 11; + private static final int KEY_WEATHER_REQUEST = 12; private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerMarioTime.class); - public AppMessageHandlerMarioTime(UUID uuid, PebbleProtocol pebbleProtocol) { + AppMessageHandlerMarioTime(UUID uuid, PebbleProtocol pebbleProtocol) { super(uuid, pebbleProtocol); } @@ -34,7 +34,6 @@ public class AppMessageHandlerMarioTime extends AppMessageHandler { ByteBuffer buf = ByteBuffer.allocate(weatherMessage.length); - // encode ack and put in front of push message (hack for acknowledging the last message) buf.put(weatherMessage); return buf.array(); @@ -56,14 +55,23 @@ public class AppMessageHandlerMarioTime extends AppMessageHandler { if (!weatherRequested) { return new GBDeviceEvent[]{null}; } + return pushMessage(); + } + + @Override + public GBDeviceEvent[] pushMessage() { ParcelableWeather2 weather = Weather.getInstance().getWeather2(); + if (weather == null) { + return new GBDeviceEvent[]{null}; + } GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); - sendBytes.encodedBytes = encodeWeatherMessage(weather.currentConditionCode, weather.currentTemp - 273); + sendBytes.encodedBytes = encodeWeatherMessage(weather.currentTemp - 273, 1); // FIXME: condition code GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); return new GBDeviceEvent[]{sendBytesAck, sendBytes}; + } } From 266c6b8817d32483ac892535a9155153a81ce97d Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 15:56:05 +0100 Subject: [PATCH 38/48] Pebble: send weather to Pebble when we get notified by weather notification --- .../gadgetbridge/devices/EventHandler.java | 3 ++ .../WeatherNotificationReceiver.java | 23 ++++++++----- .../gadgetbridge/impl/GBDeviceService.java | 21 ++++++++++-- .../gadgetbridge/model/DeviceService.java | 13 ++++++++ .../gadgetbridge/model/WeatherSpec.java | 14 ++++++++ .../service/DeviceCommunicationService.java | 27 +++++++++++++++ .../service/ServiceDeviceSupport.java | 9 +++++ .../service/devices/hplus/HPlusSupport.java | 6 ++++ .../service/devices/miband/MiBandSupport.java | 6 ++++ .../devices/miband2/MiBand2Support.java | 6 ++++ .../devices/pebble/PebbleProtocol.java | 33 ++++++++++--------- .../service/devices/pebble/PebbleSupport.java | 8 +++++ .../vibratissimo/VibratissimoSupport.java | 6 ++++ .../serial/AbstractSerialDeviceSupport.java | 15 ++++++--- .../service/serial/GBDeviceProtocol.java | 4 +++ 15 files changed, 163 insertions(+), 31 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index 2e6527884..00374072c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -12,6 +12,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; /** * Specifies all events that Gadgetbridge intends to send to the gadget device. @@ -75,4 +76,6 @@ public interface EventHandler { void onSendConfiguration(String config); void onTestNewFunction(); + + void onSendWeather(WeatherSpec weatherSpec); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java index 7a8e2aa74..a02ac6c71 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java @@ -3,13 +3,13 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.Weather; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import ru.gelin.android.weather.notification.ParcelableWeather2; @@ -34,12 +34,19 @@ public class WeatherNotificationReceiver extends BroadcastReceiver { Weather.getInstance().setWeather2(weather); LOG.info("weather in " + weather.location + " is " + weather.currentCondition + " (" + (weather.currentTemp - 273) + "°C)"); - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); - SharedPreferences.Editor edit = sharedPrefs.edit(); - edit.putString("weather_location", weather.location); - edit.putString("weather_current_condition", weather.currentCondition); - edit.putInt("weather_current_temp", weather.currentTemp); - edit.apply(); + WeatherSpec weatherSpec = new WeatherSpec(); + weatherSpec.timestamp = (int) (weather.queryTime / 1000); + weatherSpec.location = weather.location; + weatherSpec.currentTemp = weather.currentTemp; + weatherSpec.currentCondition = weather.currentCondition; + weatherSpec.currentConditionCode = weather.currentConditionCode; + weatherSpec.todayMaxTemp = weather.todayHighTemp; + weatherSpec.todayMinTemp = weather.todayLowTemp; + weatherSpec.tomorrowConditionCode = weather.forecastConditionCode; + weatherSpec.tomorrowMaxTemp = weather.forecastHighTemp; + weatherSpec.tomorrowMinTemp = weather.forecastLowTemp; + + GBApplication.deviceService().onSendWeather(weatherSpec); } } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java index 8fd47d311..361dbe260 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -17,13 +17,12 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; -//import java.util.UUID; - public class GBDeviceService implements DeviceService { protected final Context mContext; - protected final Class mServiceClass; + private final Class mServiceClass; public GBDeviceService(Context context) { mContext = context; @@ -293,4 +292,20 @@ public class GBDeviceService implements DeviceService { Intent intent = createIntent().setAction(ACTION_TEST_NEW_FUNCTION); invokeService(intent); } + + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + Intent intent = createIntent().setAction(ACTION_SEND_WEATHER) + .putExtra(EXTRA_WEATHER_TIMESTAMP, weatherSpec.timestamp) + .putExtra(EXTRA_WEATHER_LOCATION, weatherSpec.location) + .putExtra(EXTRA_WEATHER_CURRENTTEMP, weatherSpec.currentTemp) + .putExtra(EXTRA_WEATHER_CURRENTCONDITIONCODE, weatherSpec.currentConditionCode) + .putExtra(EXTRA_WEATHER_CURRENTCONDITION, weatherSpec.currentCondition) + .putExtra(EXTRA_WEATHER_TODAYMAXTEMP, weatherSpec.todayMaxTemp) + .putExtra(EXTRA_WEATHER_TODAYMINTEMP, weatherSpec.todayMinTemp) + .putExtra(EXTRA_WEATHER_TOMORROWMAXTEMP, weatherSpec.tomorrowMaxTemp) + .putExtra(EXTRA_WEATHER_TOMORROWMINTEMP, weatherSpec.tomorrowMinTemp) + .putExtra(EXTRA_WEATHER_TOMORROWCONDITIONCODE, weatherSpec.tomorrowConditionCode); + invokeService(intent); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java index c36808e5c..b536fefbc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -44,6 +44,7 @@ public interface DeviceService extends EventHandler { String ACTION_ADD_CALENDAREVENT = PREFIX + ".action.add_calendarevent"; String ACTION_DELETE_CALENDAREVENT = PREFIX + ".action.delete_calendarevent"; String ACTION_SEND_CONFIGURATION = PREFIX + ".action.send_configuration"; + String ACTION_SEND_WEATHER = PREFIX + ".action.send_weather"; String ACTION_TEST_NEW_FUNCTION = PREFIX + ".action.test_new_function"; String EXTRA_DEVICE_ADDRESS = "device_address"; String EXTRA_NOTIFICATION_BODY = "notification_body"; @@ -80,6 +81,18 @@ public interface DeviceService extends EventHandler { String EXTRA_ALARMS = "alarms"; String EXTRA_PERFORM_PAIR = "perform_pair"; String EXTRA_BOOLEAN_ENABLE = "enable_realtime_steps"; + + String EXTRA_WEATHER_TIMESTAMP = "weather_timestamp"; + String EXTRA_WEATHER_LOCATION = "weather_location"; + String EXTRA_WEATHER_CURRENTTEMP = "weather_currenttemp"; + String EXTRA_WEATHER_CURRENTCONDITIONCODE = "weather_currentconditioncode"; + String EXTRA_WEATHER_CURRENTCONDITION = "currentcondition"; + String EXTRA_WEATHER_TODAYMAXTEMP = "weather_todaymaxtemp"; + String EXTRA_WEATHER_TODAYMINTEMP = "weather_todaymintemp"; + String EXTRA_WEATHER_TOMORROWMAXTEMP = "weather_tomorrowmaxtemp"; + String EXTRA_WEATHER_TOMORROWMINTEMP = "weather_tomorrowmintemp"; + String EXTRA_WEATHER_TOMORROWCONDITIONCODE = "weather_tomorrowconditioncode"; + /** * Use EXTRA_REALTIME_SAMPLE instead */ diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java new file mode 100644 index 000000000..cd30af406 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/WeatherSpec.java @@ -0,0 +1,14 @@ +package nodomain.freeyourgadget.gadgetbridge.model; + +public class WeatherSpec { + public int timestamp; + public String location; + public int currentTemp; + public int currentConditionCode; + public String currentCondition; + public int todayMaxTemp; + public int todayMinTemp; + public int tomorrowMaxTemp; + public int tomorrowMinTemp; + public int tomorrowConditionCode; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index 9e90bfea3..f4417fb70 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -47,6 +47,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs; @@ -73,6 +74,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_RE import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_REQUEST_DEVICEINFO; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_REQUEST_SCREENSHOT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SEND_CONFIGURATION; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SEND_WEATHER; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SETCANNEDMESSAGES; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SETMUSICINFO; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SETMUSICSTATE; @@ -123,6 +125,16 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOT import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_PERFORM_PAIR; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_URI; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_VIBRATION_INTENSITY; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_CURRENTCONDITION; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_CURRENTCONDITIONCODE; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_CURRENTTEMP; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_LOCATION; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TIMESTAMP; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TODAYMAXTEMP; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TODAYMINTEMP; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TOMORROWCONDITIONCODE; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TOMORROWMAXTEMP; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TOMORROWMINTEMP; public class DeviceCommunicationService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener { private static final Logger LOG = LoggerFactory.getLogger(DeviceCommunicationService.class); @@ -501,6 +513,21 @@ public class DeviceCommunicationService extends Service implements SharedPrefere mDeviceSupport.onTestNewFunction(); break; } + case ACTION_SEND_WEATHER: { + WeatherSpec weatherSpec = new WeatherSpec(); + weatherSpec.timestamp = intent.getIntExtra(EXTRA_WEATHER_TIMESTAMP, 0); + weatherSpec.location = intent.getStringExtra(EXTRA_WEATHER_LOCATION); + weatherSpec.currentTemp = intent.getIntExtra(EXTRA_WEATHER_CURRENTTEMP, 0); + weatherSpec.currentConditionCode = intent.getIntExtra(EXTRA_WEATHER_CURRENTCONDITIONCODE, 0); + weatherSpec.currentCondition = intent.getStringExtra(EXTRA_WEATHER_CURRENTCONDITION); + weatherSpec.todayMaxTemp = intent.getIntExtra(EXTRA_WEATHER_TODAYMAXTEMP, 0); + weatherSpec.todayMinTemp = intent.getIntExtra(EXTRA_WEATHER_TODAYMINTEMP, 0); + weatherSpec.tomorrowMaxTemp = intent.getIntExtra(EXTRA_WEATHER_TOMORROWMAXTEMP, 0); + weatherSpec.tomorrowMinTemp = intent.getIntExtra(EXTRA_WEATHER_TOMORROWMINTEMP, 0); + weatherSpec.tomorrowConditionCode = intent.getIntExtra(EXTRA_WEATHER_TOMORROWCONDITIONCODE, 0); + mDeviceSupport.onSendWeather(weatherSpec); + break; + } } return START_STICKY; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index a90ee63c5..437bf5c7f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -19,6 +19,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; /** * Wraps another device support instance and supports busy-checking and throttling of events. @@ -335,4 +336,12 @@ public class ServiceDeviceSupport implements DeviceSupport { } delegate.onTestNewFunction(); } + + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + if (checkBusy("send weather event")) { + return; + } + delegate.onSendWeather(weatherSpec); + } } 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 c3704ffec..be083b070 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 @@ -46,6 +46,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; 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.GattCharacteristic; import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService; @@ -637,6 +638,11 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { LOG.debug("Test New Function"); } + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + + } + private void showIncomingCall(String name, String number){ LOG.debug("Show Incoming Call"); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index 23d7bb234..1971c0735 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -50,6 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; 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.BtLEAction; import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic; @@ -1206,6 +1207,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } } + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + + } + private void handleSensorData(byte[] value) { int counter=0, step=0, axis1=0, axis2=0, axis3 =0; if ((value.length - 2) % 6 != 0) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java index a89ff44c4..b89e9e089 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java @@ -57,6 +57,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction; @@ -1246,6 +1247,11 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { public void onTestNewFunction() { } + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + + } + private MiBand2Support setDateDisplay(TransactionBuilder builder) { DateTimeDisplay dateTimeDisplay = MiBand2Coordinator.getDateDisplay(getContext()); LOG.info("Setting date display to " + dateTimeDisplay); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index d656cb9c0..9e23ace4e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -39,8 +39,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.model.Weather; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; -import ru.gelin.android.weather.notification.ParcelableWeather2; public class PebbleProtocol extends GBDeviceProtocol { @@ -1128,22 +1128,23 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array()); } - private byte[] encodeWeatherForecast(int timestamp) { - ParcelableWeather2 weather = Weather.getInstance().getWeather2(); - if (weather != null) { - return encodeWeatherForecast(timestamp, - weather.location, - weather.currentTemp - 273, - weather.todayHighTemp - 273, - weather.todayLowTemp - 273, - Weather.mapToPebbleCondition(weather.currentConditionCode), - weather.currentCondition, - weather.forecastHighTemp - 273, - weather.forecastLowTemp - 273, - Weather.mapToPebbleCondition(weather.forecastConditionCode) - ); + + @Override + public byte[] encodeSendWeather(WeatherSpec weatherSpec) { + if (mFwMajor < 4) { + return null; } - return null; + return encodeWeatherForecast(weatherSpec.timestamp, + weatherSpec.location, + weatherSpec.currentTemp - 273, + weatherSpec.todayMaxTemp - 273, + weatherSpec.todayMinTemp - 273, + Weather.mapToPebbleCondition(weatherSpec.currentConditionCode), + weatherSpec.currentCondition, + weatherSpec.tomorrowMaxTemp - 273, + weatherSpec.tomorrowMinTemp - 273, + Weather.mapToPebbleCondition(weatherSpec.tomorrowConditionCode) + ); } private byte[] encodeWeatherForecast(int timestamp, String location, int tempNow, int tempHighToday, int tempLowToday, int conditionCodeToday, String conditionToday, int tempHighTomorrow, int tempLowTomorrow, int conditionCodeTomorrow) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java index 2b37852a9..f88f5f77e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java @@ -18,6 +18,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; @@ -170,4 +171,11 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { super.onTestNewFunction(); } } + + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + if (reconnect()) { + super.onSendWeather(weatherSpec); + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vibratissimo/VibratissimoSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vibratissimo/VibratissimoSupport.java index c4539a87a..b19b4329d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vibratissimo/VibratissimoSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vibratissimo/VibratissimoSupport.java @@ -25,6 +25,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; 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; @@ -280,4 +281,9 @@ public class VibratissimoSupport extends AbstractBTLEDeviceSupport { public void onTestNewFunction() { } + + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index 9c8add33c..216f2c517 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -11,6 +11,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; /** @@ -27,7 +28,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; * to create the device specific message for the respective events and sends them to the device via {@link #sendToDevice(byte[])}. */ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport { - protected GBDeviceProtocol gbDeviceProtocol; + private GBDeviceProtocol gbDeviceProtocol; protected GBDeviceIoThread gbDeviceIOThread; /** @@ -59,7 +60,7 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport /** * Lazily creates and returns the GBDeviceProtocol instance to be used. */ - public synchronized GBDeviceProtocol getDeviceProtocol() { + protected synchronized GBDeviceProtocol getDeviceProtocol() { if (gbDeviceProtocol == null) { gbDeviceProtocol = createDeviceProtocol(); } @@ -82,13 +83,13 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport * * @param bytes the message to send to the device */ - protected void sendToDevice(byte[] bytes) { + private void sendToDevice(byte[] bytes) { if (bytes != null && gbDeviceIOThread != null) { gbDeviceIOThread.write(bytes); } } - public void handleGBDeviceEvent(GBDeviceEventSendBytes sendBytes) { + private void handleGBDeviceEvent(GBDeviceEventSendBytes sendBytes) { sendToDevice(sendBytes.encodedBytes); } @@ -226,4 +227,10 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport byte[] bytes = gbDeviceProtocol.encodeTestNewFunction(); sendToDevice(bytes); } + + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + byte[] bytes = gbDeviceProtocol.encodeSendWeather(weatherSpec); + sendToDevice(bytes); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index c4fe1e737..77a5bc2e3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -7,6 +7,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; public abstract class GBDeviceProtocol { @@ -108,4 +109,7 @@ public abstract class GBDeviceProtocol { return mDevice; } + public byte[] encodeSendWeather(WeatherSpec weatherSpec) { + return null; + } } From 19c5cbfbb9053338561d80cbc75520b66063a0d0 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 18:13:04 +0100 Subject: [PATCH 39/48] fix tests --- .../gadgetbridge/service/TestDeviceSupport.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java index b4328421e..6d7565de1 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java @@ -15,6 +15,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; public class TestDeviceSupport extends AbstractDeviceSupport { @@ -177,4 +178,9 @@ public class TestDeviceSupport extends AbstractDeviceSupport { public void onTestNewFunction() { } + + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + + } } From 82c0f35c58fcbbcc0cabe38d52f8a8da86c1626e Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 18:56:24 +0100 Subject: [PATCH 40/48] Pebble: add encodeUpadteWeather() to AppMessageHandler for easier watchface support Now in Timestyle weather is in sync with what we get from weather notification --- .../devices/pebble/AppMessageHandler.java | 9 +++- .../AppMessageHandlerTimeStylePebble.java | 43 +++++++++---------- .../devices/pebble/PebbleProtocol.java | 22 +++++++++- .../DeviceCommunicationServiceTestCase.java | 4 +- .../service/TestDeviceService.java | 4 +- .../service/TestDeviceSupport.java | 4 +- 6 files changed, 54 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java index 1944f2d5f..693bf9b1f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java @@ -8,10 +8,11 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; public class AppMessageHandler { - protected final PebbleProtocol mPebbleProtocol; - protected final UUID mUUID; + final PebbleProtocol mPebbleProtocol; + final UUID mUUID; AppMessageHandler(UUID uuid, PebbleProtocol pebbleProtocol) { mUUID = uuid; @@ -34,6 +35,10 @@ public class AppMessageHandler { return null; } + public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) { + return null; + } + protected GBDevice getDevice() { return mPebbleProtocol.getDevice(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java index 784603a42..e5d494027 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java @@ -10,8 +10,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; -import nodomain.freeyourgadget.gadgetbridge.model.Weather; -import ru.gelin.android.weather.notification.ParcelableWeather2; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { private static final int MESSAGE_KEY_WeatherCondition = 10000; @@ -95,35 +94,35 @@ public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { return iconToLoad; } - private byte[] encodeTimeStylePebbleWeather() { - ArrayList> pairs = new ArrayList<>(); - ParcelableWeather2 weather = Weather.getInstance().getWeather2(); + private byte[] encodeTimeStylePebbleWeather(WeatherSpec weatherSpec) { - boolean isNight = false; //TODO: use the night icons when night - if (weather != null) { - pairs.add(new Pair<>(MESSAGE_KEY_WeatherUseNightIcon, (Object) (isNight ? 1 : 0))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherTemperature, (Object) (weather.currentTemp - 273))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherCondition, (Object) (getIconForConditionCode(weather.currentConditionCode, isNight)))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastCondition, (Object) (getIconForConditionCode(weather.forecastConditionCode, isNight)))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastHighTemp, (Object) (weather.todayHighTemp - 273))); - pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastLowTemp, (Object) (weather.todayLowTemp - 273))); + if (weatherSpec == null) { + return null; } - return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); + ArrayList> pairs = new ArrayList<>(); + boolean isNight = false; //TODO: use the night icons when night + pairs.add(new Pair<>(MESSAGE_KEY_WeatherUseNightIcon, (Object) (isNight ? 1 : 0))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherTemperature, (Object) (weatherSpec.currentTemp - 273))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherCondition, (Object) (getIconForConditionCode(weatherSpec.currentConditionCode, isNight)))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastCondition, (Object) (getIconForConditionCode(weatherSpec.tomorrowConditionCode, isNight)))); + pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastHighTemp, (Object) (weatherSpec.todayMaxTemp - 273))); + + pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastLowTemp, (Object) (weatherSpec.todayMinTemp - 273))); + + return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); } @Override public GBDeviceEvent[] handleMessage(ArrayList> pairs) { - return pushMessage(); + GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); + sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); + return new GBDeviceEvent[]{sendBytesAck}; + // TODO: trigger update of weather? } @Override - public GBDeviceEvent[] pushMessage() { - GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); - sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); - - GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); - sendBytes.encodedBytes = encodeTimeStylePebbleWeather(); - return new GBDeviceEvent[]{sendBytesAck, sendBytes}; + public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) { + return encodeTimeStylePebbleWeather(weatherSpec); } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 9e23ace4e..6c4efc21c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -386,6 +386,8 @@ public class PebbleProtocol extends GBDeviceProtocol { private final Map mAppMessageHandlers = new HashMap<>(); + private UUID currentRunningApp = UUID_ZERO; + public PebbleProtocol(GBDevice device) { super(device); mAppMessageHandlers.put(UUID_MORPHEUZ, new AppMessageHandlerMorpheuz(UUID_MORPHEUZ, PebbleProtocol.this)); @@ -1134,7 +1136,8 @@ public class PebbleProtocol extends GBDeviceProtocol { if (mFwMajor < 4) { return null; } - return encodeWeatherForecast(weatherSpec.timestamp, + byte[] watchfaceProtocol = null; + byte[] forecastProtocol = encodeWeatherForecast(weatherSpec.timestamp, weatherSpec.location, weatherSpec.currentTemp - 273, weatherSpec.todayMaxTemp - 273, @@ -1145,6 +1148,19 @@ public class PebbleProtocol extends GBDeviceProtocol { weatherSpec.tomorrowMinTemp - 273, Weather.mapToPebbleCondition(weatherSpec.tomorrowConditionCode) ); + AppMessageHandler handler = mAppMessageHandlers.get(currentRunningApp); + if (handler != null) { + watchfaceProtocol = handler.encodeUpdateWeather(weatherSpec); + } + + if (watchfaceProtocol != null) { + ByteBuffer buf = ByteBuffer.allocate(forecastProtocol.length + watchfaceProtocol.length); + buf.put(forecastProtocol); + buf.put(watchfaceProtocol); + return buf.array(); + } + + return forecastProtocol; } private byte[] encodeWeatherForecast(int timestamp, String location, int tempNow, int tempHighToday, int tempLowToday, int conditionCodeToday, String conditionToday, int tempHighTomorrow, int tempLowTomorrow, int conditionCodeTomorrow) { @@ -2107,7 +2123,7 @@ public class PebbleProtocol extends GBDeviceProtocol { switch (command) { case APPRUNSTATE_START: LOG.info(ENDPOINT_NAME + ": started " + uuid); - + currentRunningApp = uuid; AppMessageHandler handler = mAppMessageHandlers.get(uuid); if (handler != null) { return handler.pushMessage(); @@ -2442,6 +2458,7 @@ public class PebbleProtocol extends GBDeviceProtocol { devEvts = handler.handleMessage(dict); } else { + currentRunningApp = uuid; devEvts = handler.pushMessage(); } } else { @@ -2453,6 +2470,7 @@ public class PebbleProtocol extends GBDeviceProtocol { devEvts = decodeDictToJSONAppMessage(uuid, buf); } else { + currentRunningApp = uuid; GBDeviceEventAppManagement gbDeviceEventAppManagement = new GBDeviceEventAppManagement(); gbDeviceEventAppManagement.uuid = uuid; gbDeviceEventAppManagement.type = GBDeviceEventAppManagement.EventType.START; diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationServiceTestCase.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationServiceTestCase.java index 68af48ad8..58dccd72b 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationServiceTestCase.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationServiceTestCase.java @@ -22,7 +22,7 @@ public class DeviceCommunicationServiceTestCase extends TestBase { * Factory that always returns the mockSupport instance */ private class TestDeviceSupportFactory extends DeviceSupportFactory { - public TestDeviceSupportFactory(Context context) { + TestDeviceSupportFactory(Context context) { super(context); } @@ -53,7 +53,7 @@ public class DeviceCommunicationServiceTestCase extends TestBase { mDeviceService = new TestDeviceService(getContext()); } - protected GBDevice getDevice() { + private GBDevice getDevice() { return realSupport.getDevice(); } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceService.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceService.java index ba798a586..8eff6f79c 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceService.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceService.java @@ -13,11 +13,11 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceService; * Extends GBDeviceServer so that communication with the service works * with Robolectric. */ -public class TestDeviceService extends GBDeviceService { +class TestDeviceService extends GBDeviceService { private final ServiceController serviceController; private final DeviceCommunicationService service; - public TestDeviceService(Context context) throws Exception { + TestDeviceService(Context context) throws Exception { super(context); serviceController = Robolectric.buildService(DeviceCommunicationService.class, createIntent()); diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java index 6d7565de1..160b855b9 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java @@ -17,9 +17,9 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; -public class TestDeviceSupport extends AbstractDeviceSupport { +class TestDeviceSupport extends AbstractDeviceSupport { - public TestDeviceSupport() { + TestDeviceSupport() { } @Override From 4e543d4b3490e26ab0813ebcc0cd7296d7ed88da Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 19:04:05 +0100 Subject: [PATCH 41/48] Pebble: rename pushMessage() to onAppStart() --- .../service/devices/pebble/AppMessageHandler.java | 2 +- .../service/devices/pebble/AppMessageHandlerMarioTime.java | 4 ++-- .../service/devices/pebble/AppMessageHandlerPebStyle.java | 2 +- .../gadgetbridge/service/devices/pebble/PebbleProtocol.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java index 693bf9b1f..c0ddc21ea 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java @@ -31,7 +31,7 @@ public class AppMessageHandler { return null; } - public GBDeviceEvent[] pushMessage() { + public GBDeviceEvent[] onAppStart() { return null; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java index 869053a18..8ef9d7625 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java @@ -55,11 +55,11 @@ class AppMessageHandlerMarioTime extends AppMessageHandler { if (!weatherRequested) { return new GBDeviceEvent[]{null}; } - return pushMessage(); + return onAppStart(); } @Override - public GBDeviceEvent[] pushMessage() { + public GBDeviceEvent[] onAppStart() { ParcelableWeather2 weather = Weather.getInstance().getWeather2(); if (weather == null) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java index 20e6165f6..d6402a1bc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java @@ -110,7 +110,7 @@ public class AppMessageHandlerPebStyle extends AppMessageHandler { } @Override - public GBDeviceEvent[] pushMessage() { + public GBDeviceEvent[] onAppStart() { return null; /* GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 6c4efc21c..342bd1dd0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -2126,7 +2126,7 @@ public class PebbleProtocol extends GBDeviceProtocol { currentRunningApp = uuid; AppMessageHandler handler = mAppMessageHandlers.get(uuid); if (handler != null) { - return handler.pushMessage(); + return handler.onAppStart(); } else { GBDeviceEventAppManagement gbDeviceEventAppManagement = new GBDeviceEventAppManagement(); @@ -2459,7 +2459,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } else { currentRunningApp = uuid; - devEvts = handler.pushMessage(); + devEvts = handler.onAppStart(); } } else { devEvts = new GBDeviceEvent[]{null}; From 984e639e971ec1963061353b06393caed4b7e27e Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 19:17:08 +0100 Subject: [PATCH 42/48] Pebble: push current weather to TimeStylePebble again when watchface gets started --- .../WeatherNotificationReceiver.java | 2 +- .../gadgetbridge/model/Weather.java | 19 +++++++++++++++++-- .../AppMessageHandlerTimeStylePebble.java | 11 ++++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java index a02ac6c71..c6b39afde 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/WeatherNotificationReceiver.java @@ -45,7 +45,7 @@ public class WeatherNotificationReceiver extends BroadcastReceiver { weatherSpec.tomorrowConditionCode = weather.forecastConditionCode; weatherSpec.tomorrowMaxTemp = weather.forecastHighTemp; weatherSpec.tomorrowMinTemp = weather.forecastLowTemp; - + Weather.getInstance().setWeatherSpec(weatherSpec); GBApplication.deviceService().onSendWeather(weatherSpec); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java index 17c8ebc5e..979a6dc69 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Weather.java @@ -4,8 +4,23 @@ import ru.gelin.android.weather.notification.ParcelableWeather2; public class Weather { private ParcelableWeather2 weather2 = null; - public ParcelableWeather2 getWeather2() {return weather2;} - public void setWeather2(ParcelableWeather2 weather2) {this.weather2 = weather2;} + private WeatherSpec weatherSpec = null; + + public ParcelableWeather2 getWeather2() { + return weather2; + } + + public void setWeather2(ParcelableWeather2 weather2) { + this.weather2 = weather2; + } + + public WeatherSpec getWeatherSpec() { + return weatherSpec; + } + + public void setWeatherSpec(WeatherSpec weatherSpec) { + this.weatherSpec = weatherSpec; + } private static final Weather weather = new Weather(); public static Weather getInstance() {return weather;} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java index e5d494027..6651ed619 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java @@ -10,6 +10,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; +import nodomain.freeyourgadget.gadgetbridge.model.Weather; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { @@ -115,10 +116,18 @@ public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { @Override public GBDeviceEvent[] handleMessage(ArrayList> pairs) { + // Just ACK GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); return new GBDeviceEvent[]{sendBytesAck}; - // TODO: trigger update of weather? + } + + @Override + public GBDeviceEvent[] onAppStart() { + WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec(); + GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); + sendBytes.encodedBytes = encodeTimeStylePebbleWeather(weatherSpec); + return new GBDeviceEvent[]{sendBytes}; } @Override From b81124770458116c95a75d3973afaf17a255eabf Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 19:27:21 +0100 Subject: [PATCH 43/48] Pebble: Adapt MarioTime logic --- .../pebble/AppMessageHandlerMarioTime.java | 46 ++++++------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java index 8ef9d7625..be4e9a97b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java @@ -12,13 +12,12 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.model.Weather; -import ru.gelin.android.weather.notification.ParcelableWeather2; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; class AppMessageHandlerMarioTime extends AppMessageHandler { private static final int KEY_WEATHER_ICON_ID = 10; private static final int KEY_WEATHER_TEMPERATURE = 11; - private static final int KEY_WEATHER_REQUEST = 12; private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerMarioTime.class); @@ -26,10 +25,10 @@ class AppMessageHandlerMarioTime extends AppMessageHandler { super(uuid, pebbleProtocol); } - private byte[] encodeWeatherMessage(int temperature, int condition) { + private byte[] encodeMarioWeatherMessage(WeatherSpec weatherSpec) { ArrayList> pairs = new ArrayList<>(2); - pairs.add(new Pair<>(KEY_WEATHER_ICON_ID, (Object) (byte) condition)); - pairs.add(new Pair<>(KEY_WEATHER_TEMPERATURE, (Object) (byte) temperature)); + pairs.add(new Pair<>(KEY_WEATHER_ICON_ID, (Object) (byte) 1)); + pairs.add(new Pair<>(KEY_WEATHER_TEMPERATURE, (Object) (byte) (weatherSpec.currentTemp - 273))); byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); ByteBuffer buf = ByteBuffer.allocate(weatherMessage.length); @@ -41,37 +40,22 @@ class AppMessageHandlerMarioTime extends AppMessageHandler { @Override public GBDeviceEvent[] handleMessage(ArrayList> pairs) { - boolean weatherRequested = false; - for (Pair pair : pairs) { - switch (pair.first) { - case KEY_WEATHER_REQUEST: - LOG.info("got weather request"); - weatherRequested = true; - break; - default: - LOG.info("unknown key " + pair.first); - } - } - if (!weatherRequested) { - return new GBDeviceEvent[]{null}; - } - return onAppStart(); + // Just ACK + GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); + sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); + return new GBDeviceEvent[]{sendBytesAck}; } @Override public GBDeviceEvent[] onAppStart() { - ParcelableWeather2 weather = Weather.getInstance().getWeather2(); - - if (weather == null) { - return new GBDeviceEvent[]{null}; - } + WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec(); GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); - sendBytes.encodedBytes = encodeWeatherMessage(weather.currentTemp - 273, 1); // FIXME: condition code - - GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); - sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); - - return new GBDeviceEvent[]{sendBytesAck, sendBytes}; + sendBytes.encodedBytes = encodeMarioWeatherMessage(weatherSpec); + return new GBDeviceEvent[]{sendBytes}; + } + @Override + public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) { + return encodeMarioWeatherMessage(weatherSpec); } } From 5a83cb1c48e56bf4017271e046c38c468b4a1cff Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 19:29:41 +0100 Subject: [PATCH 44/48] Pebble: fix npe in mario time handler I shout stop for 2016! :D --- .../service/devices/pebble/AppMessageHandlerMarioTime.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java index be4e9a97b..46992628c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java @@ -26,6 +26,10 @@ class AppMessageHandlerMarioTime extends AppMessageHandler { } private byte[] encodeMarioWeatherMessage(WeatherSpec weatherSpec) { + if (weatherSpec == null) { + return null; + } + ArrayList> pairs = new ArrayList<>(2); pairs.add(new Pair<>(KEY_WEATHER_ICON_ID, (Object) (byte) 1)); pairs.add(new Pair<>(KEY_WEATHER_TEMPERATURE, (Object) (byte) (weatherSpec.currentTemp - 273))); From 7930b7da752025eeb81c0a534d332968da528f0b Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 31 Dec 2016 20:08:53 +0100 Subject: [PATCH 45/48] Pebble: Support Healthify Weather --- .../pebble/AppMessageHandlerHealthify.java | 65 +++++++++++++++++++ .../devices/pebble/PebbleProtocol.java | 2 + 2 files changed, 67 insertions(+) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerHealthify.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerHealthify.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerHealthify.java new file mode 100644 index 000000000..41cefd786 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerHealthify.java @@ -0,0 +1,65 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; + +import android.util.Pair; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Objects; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; +import nodomain.freeyourgadget.gadgetbridge.model.Weather; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; + +class AppMessageHandlerHealthify extends AppMessageHandler { + private static final int KEY_TEMPERATURE = 10021; + private static final int KEY_CONDITIONS = 10022; + + private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerHealthify.class); + + AppMessageHandlerHealthify(UUID uuid, PebbleProtocol pebbleProtocol) { + super(uuid, pebbleProtocol); + } + + private byte[] encodeMarioWeatherMessage(WeatherSpec weatherSpec) { + if (weatherSpec == null) { + return null; + } + + ArrayList> pairs = new ArrayList<>(2); + pairs.add(new Pair<>(KEY_CONDITIONS, (Object) weatherSpec.currentCondition)); + pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) (weatherSpec.currentTemp - 273))); + byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); + + ByteBuffer buf = ByteBuffer.allocate(weatherMessage.length); + + buf.put(weatherMessage); + + return buf.array(); + } + + @Override + public GBDeviceEvent[] handleMessage(ArrayList> pairs) { + // Just ACK + GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); + sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); + return new GBDeviceEvent[]{sendBytesAck}; + } + + @Override + public GBDeviceEvent[] onAppStart() { + WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec(); + GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); + sendBytes.encodedBytes = encodeMarioWeatherMessage(weatherSpec); + return new GBDeviceEvent[]{sendBytes}; + } + + @Override + public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) { + return encodeMarioWeatherMessage(weatherSpec); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 342bd1dd0..d82bf5e58 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -379,6 +379,7 @@ public class PebbleProtocol extends GBDeviceProtocol { private static final UUID UUID_PEBBLE_TIMESTYLE = UUID.fromString("4368ffa4-f0fb-4823-90be-f754b076bdaa"); private static final UUID UUID_PEBSTYLE = UUID.fromString("da05e84d-e2a2-4020-a2dc-9cdcf265fcdd"); private static final UUID UUID_MARIOTIME = UUID.fromString("43caa750-2896-4f46-94dc-1adbd4bc1ff3"); + private static final UUID UUID_HELTHIFY = UUID.fromString("7ee97b2c-95e8-4720-b94e-70fccd905d98"); private static final UUID UUID_ZERO = new UUID(0, 0); @@ -395,6 +396,7 @@ public class PebbleProtocol extends GBDeviceProtocol { mAppMessageHandlers.put(UUID_PEBBLE_TIMESTYLE, new AppMessageHandlerTimeStylePebble(UUID_PEBBLE_TIMESTYLE, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_PEBSTYLE, new AppMessageHandlerPebStyle(UUID_PEBSTYLE, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_MARIOTIME, new AppMessageHandlerMarioTime(UUID_MARIOTIME, PebbleProtocol.this)); + mAppMessageHandlers.put(UUID_HELTHIFY, new AppMessageHandlerHealthify(UUID_HELTHIFY, PebbleProtocol.this)); } private final HashMap mDatalogSessions = new HashMap<>(); From 1722a6dc47aeb66fe7f1bb10c5cde931279eabb2 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 1 Jan 2017 13:55:07 +0100 Subject: [PATCH 46/48] Pebble: minor code cleanup --- .../devices/pebble/PebbleProtocol.java | 336 +++++++++--------- 1 file changed, 165 insertions(+), 171 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index d82bf5e58..0dcc36940 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -46,140 +46,137 @@ public class PebbleProtocol extends GBDeviceProtocol { private static final Logger LOG = LoggerFactory.getLogger(PebbleProtocol.class); - static final short ENDPOINT_TIME = 11; - static final short ENDPOINT_FIRMWAREVERSION = 16; - public static final short ENDPOINT_PHONEVERSION = 17; - static final short ENDPOINT_SYSTEMMESSAGE = 18; - static final short ENDPOINT_MUSICCONTROL = 32; - static final short ENDPOINT_PHONECONTROL = 33; + private static final short ENDPOINT_TIME = 11; + private static final short ENDPOINT_FIRMWAREVERSION = 16; + private static final short ENDPOINT_PHONEVERSION = 17; + private static final short ENDPOINT_SYSTEMMESSAGE = 18; + private static final short ENDPOINT_MUSICCONTROL = 32; + private static final short ENDPOINT_PHONECONTROL = 33; static final short ENDPOINT_APPLICATIONMESSAGE = 48; - static final short ENDPOINT_LAUNCHER = 49; - static final short ENDPOINT_APPRUNSTATE = 52; // 3.x only - static final short ENDPOINT_LOGS = 2000; - static final short ENDPOINT_PING = 2001; - static final short ENDPOINT_LOGDUMP = 2002; - static final short ENDPOINT_RESET = 2003; - static final short ENDPOINT_APP = 2004; - static final short ENDPOINT_APPLOGS = 2006; - static final short ENDPOINT_NOTIFICATION = 3000; - static final short ENDPOINT_EXTENSIBLENOTIFS = 3010; - static final short ENDPOINT_RESOURCE = 4000; - static final short ENDPOINT_SYSREG = 5000; - static final short ENDPOINT_FCTREG = 5001; - static final short ENDPOINT_APPMANAGER = 6000; - static final short ENDPOINT_APPFETCH = 6001; // 3.x only - static final short ENDPOINT_DATALOG = 6778; - static final short ENDPOINT_RUNKEEPER = 7000; - static final short ENDPOINT_SCREENSHOT = 8000; - static final short ENDPOINT_AUDIOSTREAM = 10000; - static final short ENDPOINT_VOICECONTROL = 11000; - static final short ENDPOINT_NOTIFICATIONACTION = 11440; // 3.x only, TODO: find a better name - static final short ENDPOINT_APPREORDER = (short) 0xabcd; // 3.x only - static final short ENDPOINT_BLOBDB = (short) 45531; // 3.x only - static final short ENDPOINT_PUTBYTES = (short) 48879; + private static final short ENDPOINT_LAUNCHER = 49; + private static final short ENDPOINT_APPRUNSTATE = 52; // FW >=3.x + private static final short ENDPOINT_LOGS = 2000; + private static final short ENDPOINT_PING = 2001; + private static final short ENDPOINT_LOGDUMP = 2002; + private static final short ENDPOINT_RESET = 2003; + private static final short ENDPOINT_APP = 2004; + private static final short ENDPOINT_APPLOGS = 2006; + private static final short ENDPOINT_NOTIFICATION = 3000; // FW 1.x-2-x + private static final short ENDPOINT_EXTENSIBLENOTIFS = 3010; // FW 2.x + private static final short ENDPOINT_RESOURCE = 4000; + private static final short ENDPOINT_SYSREG = 5000; + private static final short ENDPOINT_FCTREG = 5001; + private static final short ENDPOINT_APPMANAGER = 6000; + private static final short ENDPOINT_APPFETCH = 6001; // FW >=3.x + private static final short ENDPOINT_DATALOG = 6778; + private static final short ENDPOINT_RUNKEEPER = 7000; + private static final short ENDPOINT_SCREENSHOT = 8000; + private static final short ENDPOINT_AUDIOSTREAM = 10000; + private static final short ENDPOINT_VOICECONTROL = 11000; + private static final short ENDPOINT_NOTIFICATIONACTION = 11440; // FW >=3.x, TODO: find a better name + private static final short ENDPOINT_APPREORDER = (short) 0xabcd; // FW >=3.x + private static final short ENDPOINT_BLOBDB = (short) 0xb1db; // FW >=3.x + private static final short ENDPOINT_PUTBYTES = (short) 0xbeef; - static final byte APPRUNSTATE_START = 1; - static final byte APPRUNSTATE_STOP = 2; + private static final byte APPRUNSTATE_START = 1; + private static final byte APPRUNSTATE_STOP = 2; - static final byte BLOBDB_INSERT = 1; - static final byte BLOBDB_DELETE = 4; - static final byte BLOBDB_CLEAR = 5; + private static final byte BLOBDB_INSERT = 1; + private static final byte BLOBDB_DELETE = 4; + private static final byte BLOBDB_CLEAR = 5; - static final byte BLOBDB_PIN = 1; - static final byte BLOBDB_APP = 2; - static final byte BLOBDB_REMINDER = 3; - static final byte BLOBDB_NOTIFICATION = 4; - static final byte BLOBDB_WEATHER = 5; - static final byte BLOBDB_CANNED_MESSAGES = 6; - static final byte BLOBDB_PREFERENCES = 7; - static final byte BLOBDB_APPSETTINGS = 9; - static final byte BLOBDB_APPGLANCE = 11; + private static final byte BLOBDB_PIN = 1; + private static final byte BLOBDB_APP = 2; + private static final byte BLOBDB_REMINDER = 3; + private static final byte BLOBDB_NOTIFICATION = 4; + private static final byte BLOBDB_WEATHER = 5; + private static final byte BLOBDB_CANNED_MESSAGES = 6; + private static final byte BLOBDB_PREFERENCES = 7; + private static final byte BLOBDB_APPSETTINGS = 9; + private static final byte BLOBDB_APPGLANCE = 11; - static final byte BLOBDB_SUCCESS = 1; - static final byte BLOBDB_GENERALFAILURE = 2; - static final byte BLOBDB_INVALIDOPERATION = 3; - static final byte BLOBDB_INVALIDDATABASEID = 4; - static final byte BLOBDB_INVALIDDATA = 5; - static final byte BLOBDB_KEYDOESNOTEXIST = 6; - static final byte BLOBDB_DATABASEFULL = 7; - static final byte BLOBDB_DATASTALE = 8; + private static final byte BLOBDB_SUCCESS = 1; + private static final byte BLOBDB_GENERALFAILURE = 2; + private static final byte BLOBDB_INVALIDOPERATION = 3; + private static final byte BLOBDB_INVALIDDATABASEID = 4; + private static final byte BLOBDB_INVALIDDATA = 5; + private static final byte BLOBDB_KEYDOESNOTEXIST = 6; + private static final byte BLOBDB_DATABASEFULL = 7; + private static final byte BLOBDB_DATASTALE = 8; - // This is not in the Pebble protocol - static final byte NOTIFICATION_UNDEFINED = -1; + private static final byte NOTIFICATION_EMAIL = 0; + private static final byte NOTIFICATION_SMS = 1; + private static final byte NOTIFICATION_TWITTER = 2; + private static final byte NOTIFICATION_FACEBOOK = 3; - static final byte NOTIFICATION_EMAIL = 0; - static final byte NOTIFICATION_SMS = 1; - static final byte NOTIFICATION_TWITTER = 2; - static final byte NOTIFICATION_FACEBOOK = 3; + private static final byte PHONECONTROL_ANSWER = 1; + private static final byte PHONECONTROL_HANGUP = 2; + private static final byte PHONECONTROL_GETSTATE = 3; + private static final byte PHONECONTROL_INCOMINGCALL = 4; + private static final byte PHONECONTROL_OUTGOINGCALL = 5; + private static final byte PHONECONTROL_MISSEDCALL = 6; + private static final byte PHONECONTROL_RING = 7; + private static final byte PHONECONTROL_START = 8; + private static final byte PHONECONTROL_END = 9; - static final byte PHONECONTROL_ANSWER = 1; - static final byte PHONECONTROL_HANGUP = 2; - static final byte PHONECONTROL_GETSTATE = 3; - static final byte PHONECONTROL_INCOMINGCALL = 4; - static final byte PHONECONTROL_OUTGOINGCALL = 5; - static final byte PHONECONTROL_MISSEDCALL = 6; - static final byte PHONECONTROL_RING = 7; - static final byte PHONECONTROL_START = 8; - static final byte PHONECONTROL_END = 9; + private static final byte MUSICCONTROL_SETMUSICINFO = 0x10; + private static final byte MUSICCONTROL_SETPLAYSTATE = 0x11; - static final byte MUSICCONTROL_SETMUSICINFO = 0x10; - static final byte MUSICCONTROL_SETPLAYSTATE = 0x11; + private static final byte MUSICCONTROL_PLAYPAUSE = 1; + private static final byte MUSICCONTROL_PAUSE = 2; + private static final byte MUSICCONTROL_PLAY = 3; + private static final byte MUSICCONTROL_NEXT = 4; + private static final byte MUSICCONTROL_PREVIOUS = 5; + private static final byte MUSICCONTROL_VOLUMEUP = 6; + private static final byte MUSICCONTROL_VOLUMEDOWN = 7; + private static final byte MUSICCONTROL_GETNOWPLAYING = 8; - static final byte MUSICCONTROL_PLAYPAUSE = 1; - static final byte MUSICCONTROL_PAUSE = 2; - static final byte MUSICCONTROL_PLAY = 3; - static final byte MUSICCONTROL_NEXT = 4; - static final byte MUSICCONTROL_PREVIOUS = 5; - static final byte MUSICCONTROL_VOLUMEUP = 6; - static final byte MUSICCONTROL_VOLUMEDOWN = 7; - static final byte MUSICCONTROL_GETNOWPLAYING = 8; + private static final byte MUSICCONTROL_STATE_PAUSED = 0x00; + private static final byte MUSICCONTROL_STATE_PLAYING = 0x01; + private static final byte MUSICCONTROL_STATE_REWINDING = 0x02; + private static final byte MUSICCONTROL_STATE_FASTWORWARDING = 0x03; + private static final byte MUSICCONTROL_STATE_UNKNOWN = 0x04; - static final byte MUSICCONTROL_STATE_PAUSED = 0x00; - static final byte MUSICCONTROL_STATE_PLAYING = 0x01; - static final byte MUSICCONTROL_STATE_REWINDING = 0x02; - static final byte MUSICCONTROL_STATE_FASTWORWARDING = 0x03; - static final byte MUSICCONTROL_STATE_UNKNOWN = 0x04; + private static final byte NOTIFICATIONACTION_ACK = 0; + private static final byte NOTIFICATIONACTION_NACK = 1; + private static final byte NOTIFICATIONACTION_INVOKE = 0x02; + private static final byte NOTIFICATIONACTION_RESPONSE = 0x11; - static final byte NOTIFICATIONACTION_ACK = 0; - static final byte NOTIFICATIONACTION_NACK = 1; - static final byte NOTIFICATIONACTION_INVOKE = 0x02; - static final byte NOTIFICATIONACTION_RESPONSE = 0x11; + private static final byte TIME_GETTIME = 0; + private static final byte TIME_SETTIME = 2; + private static final byte TIME_SETTIME_UTC = 3; - static final byte TIME_GETTIME = 0; - static final byte TIME_SETTIME = 2; - static final byte TIME_SETTIME_UTC = 3; + private static final byte FIRMWAREVERSION_GETVERSION = 0; - static final byte FIRMWAREVERSION_GETVERSION = 0; + private static final byte APPMANAGER_GETAPPBANKSTATUS = 1; + private static final byte APPMANAGER_REMOVEAPP = 2; + private static final byte APPMANAGER_REFRESHAPP = 3; + private static final byte APPMANAGER_GETUUIDS = 5; - static final byte APPMANAGER_GETAPPBANKSTATUS = 1; - static final byte APPMANAGER_REMOVEAPP = 2; - static final byte APPMANAGER_REFRESHAPP = 3; - static final byte APPMANAGER_GETUUIDS = 5; + private static final int APPMANAGER_RES_SUCCESS = 1; - static final int APPMANAGER_RES_SUCCESS = 1; + private static final byte APPLICATIONMESSAGE_PUSH = 1; + private static final byte APPLICATIONMESSAGE_REQUEST = 2; + private static final byte APPLICATIONMESSAGE_ACK = (byte) 0xff; + private static final byte APPLICATIONMESSAGE_NACK = (byte) 0x7f; - static final byte APPLICATIONMESSAGE_PUSH = 1; - static final byte APPLICATIONMESSAGE_REQUEST = 2; - static final byte APPLICATIONMESSAGE_ACK = (byte) 0xff; - static final byte APPLICATIONMESSAGE_NACK = (byte) 0x7f; + private static final byte DATALOG_OPENSESSION = 0x01; + private static final byte DATALOG_SENDDATA = 0x02; + private static final byte DATALOG_CLOSE = 0x03; + private static final byte DATALOG_TIMEOUT = 0x07; + private static final byte DATALOG_REPORTSESSIONS = (byte) 0x84; + private static final byte DATALOG_ACK = (byte) 0x85; + private static final byte DATALOG_NACK = (byte) 0x86; - static final byte DATALOG_OPENSESSION = 0x01; - static final byte DATALOG_SENDDATA = 0x02; - static final byte DATALOG_CLOSE = 0x03; - static final byte DATALOG_TIMEOUT = 0x07; - static final byte DATALOG_REPORTSESSIONS = (byte) 0x84; - static final byte DATALOG_ACK = (byte) 0x85; - static final byte DATALOG_NACK = (byte) 0x86; + private static final byte PING_PING = 0; + private static final byte PING_PONG = 1; - static final byte PING_PING = 0; - static final byte PING_PONG = 1; - - static final byte PUTBYTES_INIT = 1; - static final byte PUTBYTES_SEND = 2; - static final byte PUTBYTES_COMMIT = 3; - static final byte PUTBYTES_ABORT = 4; - static final byte PUTBYTES_COMPLETE = 5; + private static final byte PUTBYTES_INIT = 1; + private static final byte PUTBYTES_SEND = 2; + private static final byte PUTBYTES_COMMIT = 3; + private static final byte PUTBYTES_ABORT = 4; + private static final byte PUTBYTES_COMPLETE = 5; public static final byte PUTBYTES_TYPE_FIRMWARE = 1; public static final byte PUTBYTES_TYPE_RECOVERY = 2; @@ -189,70 +186,54 @@ public class PebbleProtocol extends GBDeviceProtocol { public static final byte PUTBYTES_TYPE_FILE = 6; public static final byte PUTBYTES_TYPE_WORKER = 7; - static final byte RESET_REBOOT = 0; + private static final byte RESET_REBOOT = 0; - static final byte SCREENSHOT_TAKE = 0; + private static final byte SCREENSHOT_TAKE = 0; - static final byte SYSTEMMESSAGE_NEWFIRMWAREAVAILABLE = 0; - static final byte SYSTEMMESSAGE_FIRMWARESTART = 1; - static final byte SYSTEMMESSAGE_FIRMWARECOMPLETE = 2; - static final byte SYSTEMMESSAGE_FIRMWAREFAIL = 3; - static final byte SYSTEMMESSAGE_FIRMWARE_UPTODATE = 4; - static final byte SYSTEMMESSAGE_FIRMWARE_OUTOFDATE = 5; - static final byte SYSTEMMESSAGE_STOPRECONNECTING = 6; - static final byte SYSTEMMESSAGE_STARTRECONNECTING = 7; + private static final byte SYSTEMMESSAGE_NEWFIRMWAREAVAILABLE = 0; + private static final byte SYSTEMMESSAGE_FIRMWARESTART = 1; + private static final byte SYSTEMMESSAGE_FIRMWARECOMPLETE = 2; + private static final byte SYSTEMMESSAGE_FIRMWAREFAIL = 3; + private static final byte SYSTEMMESSAGE_FIRMWARE_UPTODATE = 4; + private static final byte SYSTEMMESSAGE_FIRMWARE_OUTOFDATE = 5; + private static final byte SYSTEMMESSAGE_STOPRECONNECTING = 6; + private static final byte SYSTEMMESSAGE_STARTRECONNECTING = 7; - static final byte PHONEVERSION_REQUEST = 0; - static final byte PHONEVERSION_APPVERSION_MAGIC = 2; // increase this if pebble complains - static final byte PHONEVERSION_APPVERSION_MAJOR = 2; - static final byte PHONEVERSION_APPVERSION_MINOR = 3; - static final byte PHONEVERSION_APPVERSION_PATCH = 0; + private static final byte PHONEVERSION_REQUEST = 0; + private static final byte PHONEVERSION_APPVERSION_MAGIC = 2; // increase this if pebble complains + private static final byte PHONEVERSION_APPVERSION_MAJOR = 2; + private static final byte PHONEVERSION_APPVERSION_MINOR = 3; + private static final byte PHONEVERSION_APPVERSION_PATCH = 0; - static final int PHONEVERSION_SESSION_CAPS_GAMMARAY = 0x80000000; + private static final int PHONEVERSION_SESSION_CAPS_GAMMARAY = 0x80000000; - static final int PHONEVERSION_REMOTE_CAPS_TELEPHONY = 0x00000010; - static final int PHONEVERSION_REMOTE_CAPS_SMS = 0x00000020; - static final int PHONEVERSION_REMOTE_CAPS_GPS = 0x00000040; - static final int PHONEVERSION_REMOTE_CAPS_BTLE = 0x00000080; - static final int PHONEVERSION_REMOTE_CAPS_REARCAMERA = 0x00000100; - static final int PHONEVERSION_REMOTE_CAPS_ACCEL = 0x00000200; - static final int PHONEVERSION_REMOTE_CAPS_GYRO = 0x00000400; - static final int PHONEVERSION_REMOTE_CAPS_COMPASS = 0x00000800; + private static final int PHONEVERSION_REMOTE_CAPS_TELEPHONY = 0x00000010; + private static final int PHONEVERSION_REMOTE_CAPS_SMS = 0x00000020; + private static final int PHONEVERSION_REMOTE_CAPS_GPS = 0x00000040; + private static final int PHONEVERSION_REMOTE_CAPS_BTLE = 0x00000080; + private static final int PHONEVERSION_REMOTE_CAPS_REARCAMERA = 0x00000100; + private static final int PHONEVERSION_REMOTE_CAPS_ACCEL = 0x00000200; + private static final int PHONEVERSION_REMOTE_CAPS_GYRO = 0x00000400; + private static final int PHONEVERSION_REMOTE_CAPS_COMPASS = 0x00000800; - static final byte PHONEVERSION_REMOTE_OS_UNKNOWN = 0; - static final byte PHONEVERSION_REMOTE_OS_IOS = 1; - static final byte PHONEVERSION_REMOTE_OS_ANDROID = 2; - static final byte PHONEVERSION_REMOTE_OS_OSX = 3; - static final byte PHONEVERSION_REMOTE_OS_LINUX = 4; - static final byte PHONEVERSION_REMOTE_OS_WINDOWS = 5; + private static final byte PHONEVERSION_REMOTE_OS_UNKNOWN = 0; + private static final byte PHONEVERSION_REMOTE_OS_IOS = 1; + private static final byte PHONEVERSION_REMOTE_OS_ANDROID = 2; + private static final byte PHONEVERSION_REMOTE_OS_OSX = 3; + private static final byte PHONEVERSION_REMOTE_OS_LINUX = 4; + private static final byte PHONEVERSION_REMOTE_OS_WINDOWS = 5; - static final byte TYPE_BYTEARRAY = 0; - static final byte TYPE_CSTRING = 1; - static final byte TYPE_UINT = 2; - static final byte TYPE_INT = 3; + private static final byte TYPE_BYTEARRAY = 0; + private static final byte TYPE_CSTRING = 1; + private static final byte TYPE_UINT = 2; + private static final byte TYPE_INT = 3; - static final short LENGTH_PREFIX = 4; - static final short LENGTH_SIMPLEMESSAGE = 1; + private final short LENGTH_PREFIX = 4; - static final short LENGTH_APPFETCH = 2; - static final short LENGTH_APPRUNSTATE = 17; - static final short LENGTH_PING = 5; - static final short LENGTH_PHONEVERSION = 17; - static final short LENGTH_REMOVEAPP_2X = 17; - static final short LENGTH_REFRESHAPP = 5; - static final short LENGTH_SETTIME = 5; - static final short LENGTH_SYSTEMMESSAGE = 2; - static final short LENGTH_UPLOADSTART_2X = 7; - static final short LENGTH_UPLOADSTART_3X = 10; - static final short LENGTH_UPLOADCHUNK = 9; - static final short LENGTH_UPLOADCOMMIT = 9; - static final short LENGTH_UPLOADCOMPLETE = 5; - static final short LENGTH_UPLOADCANCEL = 5; + private static final byte LENGTH_UUID = 16; - static final byte LENGTH_UUID = 16; - - static final long GB_UUID_MASK = 0x4767744272646700L; + private static final long GB_UUID_MASK = 0x4767744272646700L; // base is -8 private static final String[] hwRevisions = { @@ -402,6 +383,7 @@ public class PebbleProtocol extends GBDeviceProtocol { private final HashMap mDatalogSessions = new HashMap<>(); private byte[] encodeSimpleMessage(short endpoint, byte command) { + final short LENGTH_SIMPLEMESSAGE = 1; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_SIMPLEMESSAGE); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_SIMPLEMESSAGE); @@ -514,6 +496,7 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeSetTime() { + final short LENGTH_SETTIME = 5; long ts = System.currentTimeMillis(); long ts_offset = (SimpleTimeZone.getDefault().getOffset(ts)); ByteBuffer buf; @@ -791,7 +774,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.putLong(UUID_LOCATION.getMostSignificantBits()); buf.putLong(UUID_LOCATION.getLeastSignificantBits()); // disable remaining 5 possible location - buf.put(new byte[60 - 16]); + buf.put(new byte[60 - LENGTH_UUID]); return encodeBlobdb("weatherApp", BLOBDB_INSERT, BLOBDB_APPSETTINGS, buf.array()); } else { return encodeBlobdb("weatherApp", BLOBDB_DELETE, BLOBDB_APPSETTINGS, null); @@ -1257,7 +1240,8 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_APP, buf.array()); } - public byte[] encodeAppFetchAck() { + byte[] encodeAppFetchAck() { + final short LENGTH_APPFETCH = 2; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_APPFETCH); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_APPFETCH); @@ -1406,6 +1390,7 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeAppStart(UUID uuid, boolean start) { if (mFwMajor >= 3) { + final short LENGTH_APPRUNSTATE = 17; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_APPRUNSTATE); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_APPRUNSTATE); @@ -1436,6 +1421,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } return encodeBlobdb(uuid, BLOBDB_DELETE, BLOBDB_APP, null); } else { + final short LENGTH_REMOVEAPP_2X = 17; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_REMOVEAPP_2X); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_REMOVEAPP_2X); @@ -1448,6 +1434,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } private byte[] encodePhoneVersion2x(byte os) { + final short LENGTH_PHONEVERSION = 17; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_PHONEVERSION); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_PHONEVERSION); @@ -1574,10 +1561,10 @@ public class PebbleProtocol extends GBDeviceProtocol { byte[] encodeUploadStart(byte type, int app_id, int size, String filename) { short length; if (mFwMajor >= 3 && (type != PUTBYTES_TYPE_FILE)) { - length = LENGTH_UPLOADSTART_3X; + length = (short) 10; type |= 0b10000000; } else { - length = LENGTH_UPLOADSTART_2X; + length = (short) 7; } if (type == PUTBYTES_TYPE_FILE && filename != null) { @@ -1608,6 +1595,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } byte[] encodeUploadChunk(int token, byte[] buffer, int size) { + final short LENGTH_UPLOADCHUNK = 9; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_UPLOADCHUNK + size); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort((short) (LENGTH_UPLOADCHUNK + size)); @@ -1620,6 +1608,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } byte[] encodeUploadCommit(int token, int crc) { + final short LENGTH_UPLOADCOMMIT = 9; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_UPLOADCOMMIT); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_UPLOADCOMMIT); @@ -1631,6 +1620,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } byte[] encodeUploadComplete(int token) { + final short LENGTH_UPLOADCOMPLETE = 5; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_UPLOADCOMPLETE); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_UPLOADCOMPLETE); @@ -1641,6 +1631,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } byte[] encodeUploadCancel(int token) { + final short LENGTH_UPLOADCANCEL = 5; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_UPLOADCANCEL); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_UPLOADCANCEL); @@ -1651,6 +1642,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } private byte[] encodeSystemMessage(byte systemMessage) { + final short LENGTH_SYSTEMMESSAGE = 2; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_SYSTEMMESSAGE); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_SYSTEMMESSAGE); @@ -1675,6 +1667,7 @@ public class PebbleProtocol extends GBDeviceProtocol { byte[] encodeAppRefresh(int index) { + final short LENGTH_REFRESHAPP = 5; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_REFRESHAPP); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_REFRESHAPP); @@ -1711,6 +1704,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } private byte[] encodePing(byte command, int cookie) { + final short LENGTH_PING = 5; ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_PING); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_PING); From 8b551106794c5aef6e8cceef3792bf17906c9a1d Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 1 Jan 2017 14:19:35 +0100 Subject: [PATCH 47/48] Pebble: allow weather to be send to watchfaces on fw < 4.x --- .../devices/pebble/PebbleProtocol.java | 56 +++++++++---------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 0dcc36940..9ba9c6cc5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -532,8 +532,6 @@ public class PebbleProtocol extends GBDeviceProtocol { if (start) { //return encodeWeatherPin(ts, "Weather", "1°/-1°", "Gadgetbridge is Sunny", "Berlin", 37); - //return encodeWeatherForecast(ts, "Berlin", 0, 5, -5, 1, "Sexy", 7, 2, 1); - return encodeWeatherForecast(ts); } */ } @@ -1118,40 +1116,36 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeSendWeather(WeatherSpec weatherSpec) { - if (mFwMajor < 4) { - return null; - } + byte[] forecastProtocol = null; byte[] watchfaceProtocol = null; - byte[] forecastProtocol = encodeWeatherForecast(weatherSpec.timestamp, - weatherSpec.location, - weatherSpec.currentTemp - 273, - weatherSpec.todayMaxTemp - 273, - weatherSpec.todayMinTemp - 273, - Weather.mapToPebbleCondition(weatherSpec.currentConditionCode), - weatherSpec.currentCondition, - weatherSpec.tomorrowMaxTemp - 273, - weatherSpec.tomorrowMinTemp - 273, - Weather.mapToPebbleCondition(weatherSpec.tomorrowConditionCode) - ); + int length = 0; + if (mFwMajor >= 4) { + forecastProtocol = encodeWeatherForecast(weatherSpec); + length += forecastProtocol.length; + } AppMessageHandler handler = mAppMessageHandlers.get(currentRunningApp); if (handler != null) { watchfaceProtocol = handler.encodeUpdateWeather(weatherSpec); + if (watchfaceProtocol != null) { + length += watchfaceProtocol.length; + } } + ByteBuffer buf = ByteBuffer.allocate(length); - if (watchfaceProtocol != null) { - ByteBuffer buf = ByteBuffer.allocate(forecastProtocol.length + watchfaceProtocol.length); + if (forecastProtocol != null) { buf.put(forecastProtocol); + } + if (watchfaceProtocol != null) { buf.put(watchfaceProtocol); - return buf.array(); } - return forecastProtocol; + return buf.array(); } - private byte[] encodeWeatherForecast(int timestamp, String location, int tempNow, int tempHighToday, int tempLowToday, int conditionCodeToday, String conditionToday, int tempHighTomorrow, int tempLowTomorrow, int conditionCodeTomorrow) { + private byte[] encodeWeatherForecast(WeatherSpec weatherSpec) { final short WEATHER_FORECAST_LENGTH = 20; - String[] parts = {location, conditionToday}; + String[] parts = {weatherSpec.location, weatherSpec.currentCondition}; // Calculate length first short attributes_length = 0; @@ -1169,15 +1163,15 @@ public class PebbleProtocol extends GBDeviceProtocol { ByteBuffer buf = ByteBuffer.allocate(pin_length); buf.order(ByteOrder.LITTLE_ENDIAN); buf.put((byte) 3); // unknown, always 3? - buf.putShort((short) tempNow); - buf.put((byte) conditionCodeToday); - buf.putShort((short) tempHighToday); - buf.putShort((short) tempLowToday); - buf.put((byte) conditionCodeTomorrow); - buf.putShort((short) tempHighTomorrow); - buf.putShort((short) tempLowTomorrow); - buf.putInt(timestamp); - buf.put((byte) 0); // automatic location + buf.putShort((short) (weatherSpec.currentTemp - 273)); + buf.put((byte) Weather.mapToPebbleCondition(weatherSpec.currentConditionCode)); + buf.putShort((short) (weatherSpec.todayMaxTemp - 273)); + buf.putShort((short) (weatherSpec.todayMinTemp - 273)); + buf.put((byte) Weather.mapToPebbleCondition(weatherSpec.tomorrowConditionCode)); + buf.putShort((short) (weatherSpec.tomorrowMaxTemp - 273)); + buf.putShort((short) (weatherSpec.tomorrowMinTemp - 273)); + buf.putInt(weatherSpec.timestamp); + buf.put((byte) 0); // automatic location 0=manual 1=auto buf.putShort(attributes_length); // Encode Pascal-Style Strings From f25605f5a177c641f355230606ddc16406d93afd Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 1 Jan 2017 16:24:46 +0100 Subject: [PATCH 48/48] Pebble: First shot at TrekVolle support Also some cleanups --- .../devices/pebble/AppMessageHandler.java | 2 +- .../pebble/AppMessageHandlerHealthify.java | 9 +- .../pebble/AppMessageHandlerMarioTime.java | 8 +- .../pebble/AppMessageHandlerMisfit.java | 22 ++--- .../pebble/AppMessageHandlerMorpheuz.java | 58 ++++++------- .../pebble/AppMessageHandlerPebStyle.java | 2 +- .../AppMessageHandlerTimeStylePebble.java | 12 ++- .../pebble/AppMessageHandlerTrekVolle.java | 85 +++++++++++++++++++ .../pebble/DatalogSessionHealthSteps.java | 2 +- .../devices/pebble/PebbleProtocol.java | 8 +- 10 files changed, 144 insertions(+), 64 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTrekVolle.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java index c0ddc21ea..042c7e509 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java @@ -10,7 +10,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; -public class AppMessageHandler { +class AppMessageHandler { final PebbleProtocol mPebbleProtocol; final UUID mUUID; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerHealthify.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerHealthify.java index 41cefd786..178b499ed 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerHealthify.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerHealthify.java @@ -2,12 +2,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; import android.util.Pair; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Objects; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; @@ -19,8 +15,6 @@ class AppMessageHandlerHealthify extends AppMessageHandler { private static final int KEY_TEMPERATURE = 10021; private static final int KEY_CONDITIONS = 10022; - private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerHealthify.class); - AppMessageHandlerHealthify(UUID uuid, PebbleProtocol pebbleProtocol) { super(uuid, pebbleProtocol); } @@ -53,6 +47,9 @@ class AppMessageHandlerHealthify extends AppMessageHandler { @Override public GBDeviceEvent[] onAppStart() { WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec(); + if (weatherSpec == null) { + return new GBDeviceEvent[]{null}; + } GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); sendBytes.encodedBytes = encodeMarioWeatherMessage(weatherSpec); return new GBDeviceEvent[]{sendBytes}; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java index 46992628c..91b105e48 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMarioTime.java @@ -2,9 +2,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; import android.util.Pair; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.UUID; @@ -19,8 +16,6 @@ class AppMessageHandlerMarioTime extends AppMessageHandler { private static final int KEY_WEATHER_ICON_ID = 10; private static final int KEY_WEATHER_TEMPERATURE = 11; - private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerMarioTime.class); - AppMessageHandlerMarioTime(UUID uuid, PebbleProtocol pebbleProtocol) { super(uuid, pebbleProtocol); } @@ -53,6 +48,9 @@ class AppMessageHandlerMarioTime extends AppMessageHandler { @Override public GBDeviceEvent[] onAppStart() { WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec(); + if (weatherSpec == null) { + return new GBDeviceEvent[]{null}; + } GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); sendBytes.encodedBytes = encodeMarioWeatherMessage(weatherSpec); return new GBDeviceEvent[]{sendBytes}; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java index 1bb51991b..381743a32 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java @@ -22,21 +22,21 @@ import nodomain.freeyourgadget.gadgetbridge.entities.PebbleMisfitSample; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; -public class AppMessageHandlerMisfit extends AppMessageHandler { +class AppMessageHandlerMisfit extends AppMessageHandler { - public static final int KEY_SLEEPGOAL = 1; - public static final int KEY_STEP_ROGRESS = 2; - public static final int KEY_SLEEP_PROGRESS = 3; - public static final int KEY_VERSION = 4; - public static final int KEY_SYNC = 5; - public static final int KEY_INCOMING_DATA_BEGIN = 6; - public static final int KEY_INCOMING_DATA = 7; - public static final int KEY_INCOMING_DATA_END = 8; - public static final int KEY_SYNC_RESULT = 9; + private static final int KEY_SLEEPGOAL = 1; + private static final int KEY_STEP_ROGRESS = 2; + private static final int KEY_SLEEP_PROGRESS = 3; + private static final int KEY_VERSION = 4; + private static final int KEY_SYNC = 5; + private static final int KEY_INCOMING_DATA_BEGIN = 6; + private static final int KEY_INCOMING_DATA = 7; + private static final int KEY_INCOMING_DATA_END = 8; + private static final int KEY_SYNC_RESULT = 9; private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerMisfit.class); - public AppMessageHandlerMisfit(UUID uuid, PebbleProtocol pebbleProtocol) { + AppMessageHandlerMisfit(UUID uuid, PebbleProtocol pebbleProtocol) { super(uuid, pebbleProtocol); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java index 4f7a14a87..4b152289a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java @@ -20,37 +20,37 @@ import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleMorpheuzSampleP import nodomain.freeyourgadget.gadgetbridge.entities.PebbleMorpheuzSample; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; -public class AppMessageHandlerMorpheuz extends AppMessageHandler { +class AppMessageHandlerMorpheuz extends AppMessageHandler { - public static final int KEY_POINT = 1; - public static final int KEY_POINT_46 = 10000; - public static final int KEY_CTRL = 2; - public static final int KEY_CTRL_46 = 10001; - public static final int KEY_FROM = 3; - public static final int KEY_FROM_46 = 10002; - public static final int KEY_TO = 4; - public static final int KEY_TO_46 = 10003; - public static final int KEY_BASE = 5; - public static final int KEY_BASE_46 = 10004; - public static final int KEY_VERSION = 6; - public static final int KEY_VERSION_46 = 10005; - public static final int KEY_GONEOFF = 7; - public static final int KEY_GONEOFF_46 = 10006; - public static final int KEY_TRANSMIT = 8; - public static final int KEY_TRANSMIT_46 = 10007; - public static final int KEY_AUTO_RESET = 9; - public static final int KEY_AUTO_RESET_46 = 10008; - public static final int KEY_SNOOZES = 10; - public static final int KEY_SNOOZES_46 = 10009; - public static final int KEY_FAULT_46 = 10010; + private static final int KEY_POINT = 1; + private static final int KEY_POINT_46 = 10000; + private static final int KEY_CTRL = 2; + private static final int KEY_CTRL_46 = 10001; + private static final int KEY_FROM = 3; + private static final int KEY_FROM_46 = 10002; + private static final int KEY_TO = 4; + private static final int KEY_TO_46 = 10003; + private static final int KEY_BASE = 5; + private static final int KEY_BASE_46 = 10004; + private static final int KEY_VERSION = 6; + private static final int KEY_VERSION_46 = 10005; + private static final int KEY_GONEOFF = 7; + private static final int KEY_GONEOFF_46 = 10006; + private static final int KEY_TRANSMIT = 8; + private static final int KEY_TRANSMIT_46 = 10007; + private static final int KEY_AUTO_RESET = 9; + private static final int KEY_AUTO_RESET_46 = 10008; + private static final int KEY_SNOOZES = 10; + private static final int KEY_SNOOZES_46 = 10009; + private static final int KEY_FAULT_46 = 10010; - public static final int CTRL_TRANSMIT_DONE = 1; - public static final int CTRL_VERSION_DONE = 2; - public static final int CTRL_GONEOFF_DONE = 4; - public static final int CTRL_DO_NEXT = 8; - public static final int CTRL_SET_LAST_SENT = 16; - public static final int CTRL_LAZARUS = 32; - public static final int CTRL_SNOOZES_DONE = 64; + private static final int CTRL_TRANSMIT_DONE = 1; + private static final int CTRL_VERSION_DONE = 2; + private static final int CTRL_GONEOFF_DONE = 4; + private static final int CTRL_DO_NEXT = 8; + private static final int CTRL_SET_LAST_SENT = 16; + private static final int CTRL_LAZARUS = 32; + private static final int CTRL_SNOOZES_DONE = 64; // data received from Morpheuz in native format private int version = 0; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java index d6402a1bc..8e916c105 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerPebStyle.java @@ -14,7 +14,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleColor; import nodomain.freeyourgadget.gadgetbridge.model.Weather; import ru.gelin.android.weather.notification.ParcelableWeather2; -public class AppMessageHandlerPebStyle extends AppMessageHandler { +class AppMessageHandlerPebStyle extends AppMessageHandler { public static final int KEY_AMPM_TEXT = 21; public static final int KEY_BLUETOOTH_ALERT = 2; public static final int KEY_BLUETOOTH_ICON = 20; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java index 6651ed619..16c96afc7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTimeStylePebble.java @@ -2,9 +2,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; import android.util.Pair; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.ArrayList; import java.util.UUID; @@ -13,7 +10,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.model.Weather; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; -public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { +class AppMessageHandlerTimeStylePebble extends AppMessageHandler { private static final int MESSAGE_KEY_WeatherCondition = 10000; private static final int MESSAGE_KEY_WeatherForecastCondition = 10002; private static final int MESSAGE_KEY_WeatherForecastHighTemp = 10003; @@ -35,9 +32,7 @@ public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { private static final int ICON_THUNDERSTORM = 10; private static final int ICON_WEATHER_GENERIC = 11; - private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerTimeStylePebble.class); - - public AppMessageHandlerTimeStylePebble(UUID uuid, PebbleProtocol pebbleProtocol) { + AppMessageHandlerTimeStylePebble(UUID uuid, PebbleProtocol pebbleProtocol) { super(uuid, pebbleProtocol); } @@ -125,6 +120,9 @@ public class AppMessageHandlerTimeStylePebble extends AppMessageHandler { @Override public GBDeviceEvent[] onAppStart() { WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec(); + if (weatherSpec == null) { + return new GBDeviceEvent[]{null}; + } GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); sendBytes.encodedBytes = encodeTimeStylePebbleWeather(weatherSpec); return new GBDeviceEvent[]{sendBytes}; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTrekVolle.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTrekVolle.java new file mode 100644 index 000000000..b3cfce66e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerTrekVolle.java @@ -0,0 +1,85 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; + +import android.util.Pair; + +import java.util.ArrayList; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; +import nodomain.freeyourgadget.gadgetbridge.model.Weather; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; + +class AppMessageHandlerTrekVolle extends AppMessageHandler { + private static final int MESSAGE_KEY_WEATHER_TEMPERATURE = 10000; + private static final int MESSAGE_KEY_WEATHER_CONDITIONS = 10001; + private static final int MESSAGE_KEY_WEATHER_ICON = 10002; + private static final int MESSAGE_KEY_WEATHER_TEMPERATURE_MIN = 10024; + private static final int MESSAGE_KEY_WEATHER_TEMPERATURE_MAX = 10025; + private static final int MESSAGE_KEY_WEATHER_LOCATION = 10030; + + AppMessageHandlerTrekVolle(UUID uuid, PebbleProtocol pebbleProtocol) { + super(uuid, pebbleProtocol); + } + + private int getIconForConditionCode(int conditionCode, boolean isNight) { + /* + case 1: return RESOURCE_ID_IMAGE_WEATHER_CLEARNIGHT; + case 2: return RESOURCE_ID_IMAGE_WEATHER_CLEAR; + case 3: return RESOURCE_ID_IMAGE_WEATHER_CLOUDYNIGHT; + case 4: return RESOURCE_ID_IMAGE_WEATHER_CLOUDY; + case 5: return RESOURCE_ID_IMAGE_WEATHER_CLOUDS; + case 6: return RESOURCE_ID_IMAGE_WEATHER_THICKCLOUDS; + case 7: return RESOURCE_ID_IMAGE_WEATHER_RAIN; + case 8: return RESOURCE_ID_IMAGE_WEATHER_RAINYNIGHT; + case 9: return RESOURCE_ID_IMAGE_WEATHER_RAINY; + case 10: return RESOURCE_ID_IMAGE_WEATHER_LIGHTNING; + case 11: return RESOURCE_ID_IMAGE_WEATHER_SNOW; + case 12: return RESOURCE_ID_IMAGE_WEATHER_MIST; + */ + return 2; + } + + private byte[] encodeTrekVolleWeather(WeatherSpec weatherSpec) { + + if (weatherSpec == null) { + return null; + } + + boolean isNight = false; // FIXME + ArrayList> pairs = new ArrayList<>(); + pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_TEMPERATURE, (Object) (weatherSpec.currentTemp - 273))); + pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_CONDITIONS, (Object) (weatherSpec.currentCondition))); + pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_ICON, (Object) (getIconForConditionCode(weatherSpec.currentConditionCode, isNight)))); + pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_TEMPERATURE_MAX, (Object) (weatherSpec.todayMaxTemp - 273))); + pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_TEMPERATURE_MIN, (Object) (weatherSpec.todayMinTemp - 273))); + pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_LOCATION, (Object) weatherSpec.location)); + + + return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); + } + + @Override + public GBDeviceEvent[] handleMessage(ArrayList> pairs) { + // Just ACK + GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); + sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id); + return new GBDeviceEvent[]{sendBytesAck}; + } + + @Override + public GBDeviceEvent[] onAppStart() { + WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec(); + if (weatherSpec == null) { + return new GBDeviceEvent[]{null}; + } + GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); + sendBytes.encodedBytes = encodeTrekVolleWeather(weatherSpec); + return new GBDeviceEvent[]{sendBytes}; + } + + @Override + public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) { + return encodeTrekVolleWeather(weatherSpec); + } +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java index 4bcc6ae55..1f69dcd1c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java @@ -16,7 +16,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.PebbleHealthActivitySample; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.GB; -public class DatalogSessionHealthSteps extends DatalogSessionPebbleHealth { +class DatalogSessionHealthSteps extends DatalogSessionPebbleHealth { private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthSteps.class); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 9ba9c6cc5..625cc7340 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -361,6 +361,7 @@ public class PebbleProtocol extends GBDeviceProtocol { private static final UUID UUID_PEBSTYLE = UUID.fromString("da05e84d-e2a2-4020-a2dc-9cdcf265fcdd"); private static final UUID UUID_MARIOTIME = UUID.fromString("43caa750-2896-4f46-94dc-1adbd4bc1ff3"); private static final UUID UUID_HELTHIFY = UUID.fromString("7ee97b2c-95e8-4720-b94e-70fccd905d98"); + private static final UUID UUID_TREKVOLLE = UUID.fromString("2da02267-7a19-4e49-9ed1-439d25db14e4"); private static final UUID UUID_ZERO = new UUID(0, 0); @@ -375,9 +376,10 @@ public class PebbleProtocol extends GBDeviceProtocol { mAppMessageHandlers.put(UUID_MORPHEUZ, new AppMessageHandlerMorpheuz(UUID_MORPHEUZ, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_MISFIT, new AppMessageHandlerMisfit(UUID_MISFIT, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_PEBBLE_TIMESTYLE, new AppMessageHandlerTimeStylePebble(UUID_PEBBLE_TIMESTYLE, PebbleProtocol.this)); - mAppMessageHandlers.put(UUID_PEBSTYLE, new AppMessageHandlerPebStyle(UUID_PEBSTYLE, PebbleProtocol.this)); + //mAppMessageHandlers.put(UUID_PEBSTYLE, new AppMessageHandlerPebStyle(UUID_PEBSTYLE, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_MARIOTIME, new AppMessageHandlerMarioTime(UUID_MARIOTIME, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_HELTHIFY, new AppMessageHandlerHealthify(UUID_HELTHIFY, PebbleProtocol.this)); + mAppMessageHandlers.put(UUID_TREKVOLLE, new AppMessageHandlerTrekVolle(UUID_TREKVOLLE, PebbleProtocol.this)); } private final HashMap mDatalogSessions = new HashMap<>(); @@ -1164,10 +1166,10 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.order(ByteOrder.LITTLE_ENDIAN); buf.put((byte) 3); // unknown, always 3? buf.putShort((short) (weatherSpec.currentTemp - 273)); - buf.put((byte) Weather.mapToPebbleCondition(weatherSpec.currentConditionCode)); + buf.put(Weather.mapToPebbleCondition(weatherSpec.currentConditionCode)); buf.putShort((short) (weatherSpec.todayMaxTemp - 273)); buf.putShort((short) (weatherSpec.todayMinTemp - 273)); - buf.put((byte) Weather.mapToPebbleCondition(weatherSpec.tomorrowConditionCode)); + buf.put(Weather.mapToPebbleCondition(weatherSpec.tomorrowConditionCode)); buf.putShort((short) (weatherSpec.tomorrowMaxTemp - 273)); buf.putShort((short) (weatherSpec.tomorrowMinTemp - 273)); buf.putInt(weatherSpec.timestamp);