mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 12:56:49 +01:00
Merge branch 'master' into background-javascript
This commit is contained in:
commit
f4e11c8cb3
@ -1,6 +1,10 @@
|
|||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
#### Version 0.20.0 (next)
|
#### Version 0.20.1
|
||||||
|
* Amazfit Bip: Support icons and text body for notifications
|
||||||
|
* Mi Band: Fix setting smart alarms
|
||||||
|
|
||||||
|
#### Version 0.20.0
|
||||||
* Inital Amazfit Bip support (WIP)
|
* Inital Amazfit Bip support (WIP)
|
||||||
* Various theming fixes
|
* Various theming fixes
|
||||||
* Add workaround for blacklist not properly persisting
|
* Add workaround for blacklist not properly persisting
|
||||||
@ -8,7 +12,7 @@
|
|||||||
* Pebble: Pass booleans from Javascript Appmessage correctly
|
* Pebble: Pass booleans from Javascript Appmessage correctly
|
||||||
* Pebble: Make local configuration pages work on most recent webview implementation
|
* Pebble: Make local configuration pages work on most recent webview implementation
|
||||||
* Pebble: Allow to blacklist calendars
|
* Pebble: Allow to blacklist calendars
|
||||||
* Add greek transliteration support
|
* Add Greek and German transliteration support
|
||||||
* Various visual improvements to charts
|
* Various visual improvements to charts
|
||||||
|
|
||||||
#### Version 0.19.4
|
#### Version 0.19.4
|
||||||
|
@ -22,3 +22,6 @@ Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0):
|
|||||||
|
|
||||||
Creative Commons Attribution 3.0 Unported license (CC BY-3.0):
|
Creative Commons Attribution 3.0 Unported license (CC BY-3.0):
|
||||||
ic_notification_battery_low.png by Picol.org. Source: https://commons.wikimedia.org/wiki/File:Battery_1_Picol_icon.svg
|
ic_notification_battery_low.png by Picol.org. Source: https://commons.wikimedia.org/wiki/File:Battery_1_Picol_icon.svg
|
||||||
|
|
||||||
|
Creative Commons Attribution 3.0 United States (CC BY-3.0 US):
|
||||||
|
ic_donate by Peter van Driel https://thenounproject.com/term/donate/239009/
|
||||||
|
@ -2,8 +2,8 @@ Gadgetbridge
|
|||||||
============
|
============
|
||||||
|
|
||||||
Gadgetbridge is an Android (4.4+) application which will allow you to use your
|
Gadgetbridge is an Android (4.4+) application which will allow you to use your
|
||||||
Pebble or Mi Band or HPlus device without the vendor's closed source application
|
Pebble, Mi Band, Amazfit Bit and HPlus device (and more) without the vendor's closed source application
|
||||||
and without the need to create an account and transmit any of your data to the
|
and without the need to create an account and transmit any of your data to the
|
||||||
vendor's servers.
|
vendor's servers.
|
||||||
|
|
||||||
[Homepage](https://gadgetbridge.org)
|
[Homepage](https://gadgetbridge.org)
|
||||||
@ -23,6 +23,7 @@ vendor's servers.
|
|||||||
* Pebble 2 (add the device from within Gadgetbridge!) [Wiki section about pebble](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Pebble), most parts apply to Pebble 2 as well
|
* Pebble 2 (add the device from within Gadgetbridge!) [Wiki section about pebble](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Pebble), most parts apply to Pebble 2 as well
|
||||||
* Mi Band, Mi Band 1A, Mi Band 1S [Wiki section about this device](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Mi-Band)
|
* Mi Band, Mi Band 1A, Mi Band 1S [Wiki section about this device](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Mi-Band)
|
||||||
* Mi Band 2 [Wiki section about mi band](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Mi-Band), some parts apply to mi band 2 as well
|
* Mi Band 2 [Wiki section about mi band](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Mi-Band), some parts apply to mi band 2 as well
|
||||||
|
* Amazfit Bip (WIP) [Wiki section about the Amazfit Bip](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Amazfit-Bip)
|
||||||
* HPlus Devices (e.g. ZeBand) [Wiki section about this device](https://github.com/Freeyourgadget/Gadgetbridge/wiki/HPlus)
|
* HPlus Devices (e.g. ZeBand) [Wiki section about this device](https://github.com/Freeyourgadget/Gadgetbridge/wiki/HPlus)
|
||||||
* Liveview
|
* Liveview
|
||||||
* Vibratissimo (experimental)
|
* Vibratissimo (experimental)
|
||||||
|
@ -26,8 +26,8 @@ android {
|
|||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
|
|
||||||
// note: always bump BOTH versionCode and versionName!
|
// note: always bump BOTH versionCode and versionName!
|
||||||
versionName "0.20.0"
|
versionName "0.20.1"
|
||||||
versionCode 98
|
versionCode 99
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
@ -25,6 +25,7 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@ -61,8 +62,6 @@ import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
import static de.cketti.library.changelog.ChangeLog.DEFAULT_CSS;
|
|
||||||
|
|
||||||
//TODO: extend GBActivity, but it requires actionbar that is not available
|
//TODO: extend GBActivity, but it requires actionbar that is not available
|
||||||
public class ControlCenterv2 extends AppCompatActivity
|
public class ControlCenterv2 extends AppCompatActivity
|
||||||
implements NavigationView.OnNavigationItemSelectedListener {
|
implements NavigationView.OnNavigationItemSelectedListener {
|
||||||
@ -250,6 +249,11 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
case R.id.action_quit:
|
case R.id.action_quit:
|
||||||
GBApplication.quit();
|
GBApplication.quit();
|
||||||
return true;
|
return true;
|
||||||
|
case R.id.donation_link:
|
||||||
|
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("https://liberapay.com/Gadgetbridge")); //TODO: centralize if ever used somewhere else
|
||||||
|
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
startActivity(i);
|
||||||
|
return true;
|
||||||
case R.id.external_changelog:
|
case R.id.external_changelog:
|
||||||
ChangeLog cl = createChangeLog();
|
ChangeLog cl = createChangeLog();
|
||||||
cl.getFullLogDialog().show();
|
cl.getFullLogDialog().show();
|
||||||
|
@ -189,6 +189,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent startIntent;
|
Intent startIntent;
|
||||||
startIntent = new Intent(context, ConfigureAlarms.class);
|
startIntent = new Intent(context, ConfigureAlarms.class);
|
||||||
|
startIntent.putExtra(GBDevice.EXTRA_DEVICE, device);
|
||||||
context.startActivity(startIntent);
|
context.startActivity(startIntent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
/* Copyright (C) 2017 Andreas Shimokawa
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip;
|
||||||
|
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||||
|
|
||||||
|
public class AmazfitBipIcon {
|
||||||
|
// icons which are unsure which app they are for are suffixed with _NN
|
||||||
|
public static final int CHAT = 0;
|
||||||
|
public static final int PENGUIN_1 = 1;
|
||||||
|
public static final int MI_CHAT_2 = 2;
|
||||||
|
public static final int FACEBOOK = 3;
|
||||||
|
public static final int TWITTER = 4;
|
||||||
|
public static final int MI_APP_5 = 5;
|
||||||
|
public static final int SNAPCHAT = 6;
|
||||||
|
public static final int WHATSAPP = 7;
|
||||||
|
public static final int RED_WHITE_FIRE_8 = 8;
|
||||||
|
public static final int CHINESE_9 = 9;
|
||||||
|
public static final int ALARM_CLOCK = 10;
|
||||||
|
public static final int APP_11 = 11;
|
||||||
|
public static final int CAMERA_12 = 12;
|
||||||
|
public static final int CHAT_BLUE_13 = 13;
|
||||||
|
public static final int COW_14 = 14;
|
||||||
|
public static final int CHINESE_15 = 15;
|
||||||
|
public static final int CHINESE_16 = 16;
|
||||||
|
public static final int STAR_17 = 17;
|
||||||
|
public static final int APP_18 = 18;
|
||||||
|
public static final int CHINESE_19 = 19;
|
||||||
|
public static final int CHINESE_20 = 20;
|
||||||
|
public static final int CALENDAR = 21;
|
||||||
|
public static final int FACEBOOK_MESSENGER = 22;
|
||||||
|
public static final int WHATSAPP_CALL_23 = 23;
|
||||||
|
public static final int LINE = 24;
|
||||||
|
public static final int TELEGRAM = 25;
|
||||||
|
public static final int KAKAOTALK = 26;
|
||||||
|
public static final int SKYPE = 27;
|
||||||
|
public static final int VKONTAKTE = 28;
|
||||||
|
public static final int POKEMONGO = 29;
|
||||||
|
public static final int HANGOUTS = 30;
|
||||||
|
public static final int MI_31 = 31;
|
||||||
|
public static final int CHINESE_32 = 32;
|
||||||
|
public static final int CHINESE_33 = 33;
|
||||||
|
public static final int EMAIL = 34;
|
||||||
|
public static final int WEATHER = 35;
|
||||||
|
public static final int HR_WARNING_36 = 36;
|
||||||
|
|
||||||
|
|
||||||
|
public static int mapToIconId(NotificationType type) {
|
||||||
|
switch (type) {
|
||||||
|
case UNKNOWN:
|
||||||
|
return APP_11;
|
||||||
|
case CONVERSATIONS:
|
||||||
|
return CHAT;
|
||||||
|
case GENERIC_EMAIL:
|
||||||
|
return EMAIL;
|
||||||
|
case GENERIC_NAVIGATION:
|
||||||
|
return APP_11;
|
||||||
|
case GENERIC_SMS:
|
||||||
|
return CHAT;
|
||||||
|
case GENERIC_CALENDAR:
|
||||||
|
return CALENDAR;
|
||||||
|
case FACEBOOK:
|
||||||
|
return FACEBOOK;
|
||||||
|
case FACEBOOK_MESSENGER:
|
||||||
|
return FACEBOOK_MESSENGER;
|
||||||
|
case RIOT:
|
||||||
|
return CHAT;
|
||||||
|
case SIGNAL:
|
||||||
|
return CHAT_BLUE_13;
|
||||||
|
case TWITTER:
|
||||||
|
return TWITTER;
|
||||||
|
case TELEGRAM:
|
||||||
|
return TELEGRAM;
|
||||||
|
case WHATSAPP:
|
||||||
|
return WHATSAPP;
|
||||||
|
case GENERIC_ALARM_CLOCK:
|
||||||
|
return ALARM_CLOCK;
|
||||||
|
}
|
||||||
|
return APP_11;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/* Copyright (C) 2017 Andreas Shimokawa
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class AmazfitBipService {
|
||||||
|
public static final UUID UUID_CHARACTERISTIC_WEATHER = UUID.fromString("0000000e-0000-3512-2118-0009af100700");
|
||||||
|
}
|
@ -0,0 +1,189 @@
|
|||||||
|
/* Copyright (C) 2017 Andreas Shimokawa
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip;
|
||||||
|
|
||||||
|
|
||||||
|
public class AmazfitBipWeatherConditions {
|
||||||
|
public static final byte CLEAR_SKY = 0;
|
||||||
|
public static final byte SCATTERED_CLOUDS = 1;
|
||||||
|
public static final byte CLOUDY = 2;
|
||||||
|
public static final byte RAIN_WITH_SUN = 3;
|
||||||
|
public static final byte THUNDERSTORM = 4;
|
||||||
|
public static final byte HAIL = 5;
|
||||||
|
public static final byte RAIN_AND_SNOW = 6;
|
||||||
|
public static final byte LIGHT_RAIN = 7;
|
||||||
|
public static final byte MEDIUM_RAIN = 8;
|
||||||
|
public static final byte HEAVY_RAIN = 9;
|
||||||
|
public static final byte EXTREME_RAIN = 10;
|
||||||
|
public static final byte SUPER_EXTREME_RAIN = 11;
|
||||||
|
public static final byte TORRENTIAL_RAIN = 12;
|
||||||
|
public static final byte SNOW_AND_SUN = 13;
|
||||||
|
public static final byte LIGHT_SNOW = 14;
|
||||||
|
public static final byte MEDIUM_SNOW = 15;
|
||||||
|
public static final byte HEAVY_SNOW = 16;
|
||||||
|
public static final byte EXTREME_SNOW = 17;
|
||||||
|
public static final byte MIST = 18;
|
||||||
|
public static final byte DRIZZLE = 19;
|
||||||
|
public static final byte WIND_AND_RAIN = 20;
|
||||||
|
// 21- various types of rain
|
||||||
|
|
||||||
|
public static byte mapToAmazfitBipWeatherCode(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
|
||||||
|
case 212: //heavy thunderstorm: //11d
|
||||||
|
case 221: //ragged thunderstorm: //11d
|
||||||
|
return THUNDERSTORM;
|
||||||
|
//Group 3xx: Drizzle
|
||||||
|
case 300: //light intensity drizzle: //09d
|
||||||
|
case 301: //drizzle: //09d
|
||||||
|
case 302: //heavy intensity drizzle: //09d
|
||||||
|
case 310: //light intensity drizzle rain: //09d
|
||||||
|
case 311: //drizzle rain: //09d
|
||||||
|
case 312: //heavy intensity drizzle rain: //09d
|
||||||
|
case 313: //shower rain and drizzle: //09d
|
||||||
|
case 314: //heavy shower rain and drizzle: //09d
|
||||||
|
case 321: //shower drizzle: //09d
|
||||||
|
return DRIZZLE;
|
||||||
|
//Group 5xx: Rain
|
||||||
|
case 500: //light rain: //10d
|
||||||
|
return LIGHT_RAIN;
|
||||||
|
case 501: //moderate rain: //10d
|
||||||
|
return MEDIUM_RAIN;
|
||||||
|
case 502: //heavy intensity rain: //10d
|
||||||
|
return HEAVY_RAIN;
|
||||||
|
case 503: //very heavy rain: //10d
|
||||||
|
return EXTREME_RAIN;
|
||||||
|
case 504: //extreme rain: //10d
|
||||||
|
return TORRENTIAL_RAIN;
|
||||||
|
case 511: //freezing rain: //13d
|
||||||
|
return MEDIUM_RAIN;
|
||||||
|
case 520: //light intensity shower rain: //09d
|
||||||
|
return LIGHT_RAIN;
|
||||||
|
case 521: //shower rain: //09d
|
||||||
|
return MEDIUM_RAIN;
|
||||||
|
case 522: //heavy intensity shower rain: //09d
|
||||||
|
return HEAVY_RAIN;
|
||||||
|
case 531: //ragged shower rain: //09d
|
||||||
|
return MEDIUM_RAIN;
|
||||||
|
//Group 6xx: Snow
|
||||||
|
case 600: //light snow: //[[file:13d.png]]
|
||||||
|
return LIGHT_SNOW;
|
||||||
|
case 601: //snow: //[[file:13d.png]]
|
||||||
|
return MEDIUM_SNOW;
|
||||||
|
case 602: //heavy snow: //[[file:13d.png]]
|
||||||
|
return HEAVY_SNOW;
|
||||||
|
case 611: //sleet: //[[file:13d.png]]
|
||||||
|
case 612: //shower sleet: //[[file:13d.png]]
|
||||||
|
case 615: //light rain and snow: //[[file:13d.png]]
|
||||||
|
case 616: //rain and snow: //[[file:13d.png]]
|
||||||
|
case 620: //light shower snow: //[[file:13d.png]]
|
||||||
|
case 621: //shower snow: //[[file:13d.png]]
|
||||||
|
case 622: //heavy shower snow: //[[file:13d.png]]
|
||||||
|
return RAIN_AND_SNOW;
|
||||||
|
|
||||||
|
//Group 7xx: Atmosphere
|
||||||
|
case 701: //mist: //[[file:50d.png]]
|
||||||
|
case 711: //smoke: //[[file:50d.png]]
|
||||||
|
case 721: //haze: //[[file:50d.png]]
|
||||||
|
case 731: //sandcase dust whirls: //[[file:50d.png]]
|
||||||
|
case 741: //fog: //[[file:50d.png]]
|
||||||
|
case 751: //sand: //[[file:50d.png]]
|
||||||
|
case 761: //dust: //[[file:50d.png]]
|
||||||
|
case 762: //volcanic ash: //[[file:50d.png]]
|
||||||
|
case 771: //squalls: //[[file:50d.png]]
|
||||||
|
return MIST;
|
||||||
|
case 781: //tornado: //[[file:50d.png]]
|
||||||
|
case 900: //tornado
|
||||||
|
return WIND_AND_RAIN;
|
||||||
|
//Group 800: Clear
|
||||||
|
case 800: //clear sky: //[[file:01d.png]] [[file:01n.png]]
|
||||||
|
return CLEAR_SKY;
|
||||||
|
//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]]
|
||||||
|
return SCATTERED_CLOUDS;
|
||||||
|
case 804: //overcast clouds: //[[file:04d.png]] [[file:04d.png]]
|
||||||
|
return CLOUDY;
|
||||||
|
//Group 90x: Extreme
|
||||||
|
case 901: //tropical storm
|
||||||
|
return WIND_AND_RAIN;
|
||||||
|
case 903: //cold
|
||||||
|
case 904: //hot
|
||||||
|
case 905: //windy
|
||||||
|
return 0;
|
||||||
|
case 906: //hail
|
||||||
|
return 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 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String mapToOpenWeatherMapIcon(int openWeatherMapCondition) {
|
||||||
|
//see https://openweathermap.org/weather-conditions
|
||||||
|
String condition = "02d"; //generic "variable" icon
|
||||||
|
|
||||||
|
if (openWeatherMapCondition >= 200 && openWeatherMapCondition < 300) {
|
||||||
|
condition = "11d";
|
||||||
|
} else if (openWeatherMapCondition >= 300 && openWeatherMapCondition < 500) {
|
||||||
|
condition = "09d";
|
||||||
|
} else if (openWeatherMapCondition >= 500 && openWeatherMapCondition < 510) {
|
||||||
|
condition = "10d";
|
||||||
|
} else if (openWeatherMapCondition >= 511 && openWeatherMapCondition < 600) {
|
||||||
|
condition = "09d";
|
||||||
|
} else if (openWeatherMapCondition >= 600 && openWeatherMapCondition < 700) {
|
||||||
|
condition = "13d";
|
||||||
|
} else if (openWeatherMapCondition >= 700 && openWeatherMapCondition < 800) {
|
||||||
|
condition = "50d";
|
||||||
|
} else if (openWeatherMapCondition == 800) {
|
||||||
|
condition = "01d"; //TODO: night?
|
||||||
|
} else if (openWeatherMapCondition == 801) {
|
||||||
|
condition = "02d"; //TODO: night?
|
||||||
|
} else if (openWeatherMapCondition == 802) {
|
||||||
|
condition = "03d"; //TODO: night?
|
||||||
|
} else if (openWeatherMapCondition == 803 || openWeatherMapCondition == 804) {
|
||||||
|
condition = "04d"; //TODO: night?
|
||||||
|
}
|
||||||
|
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,8 @@ import android.content.Intent;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.SimpleTimeZone;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
@ -51,7 +53,7 @@ public class WeatherNotificationReceiver extends BroadcastReceiver {
|
|||||||
LOG.info("weather in " + weather.location + " is " + weather.currentCondition + " (" + (weather.currentTemp - 273) + "°C)");
|
LOG.info("weather in " + weather.location + " is " + weather.currentCondition + " (" + (weather.currentTemp - 273) + "°C)");
|
||||||
|
|
||||||
WeatherSpec weatherSpec = new WeatherSpec();
|
WeatherSpec weatherSpec = new WeatherSpec();
|
||||||
weatherSpec.timestamp = (int) (weather.queryTime / 1000);
|
weatherSpec.timestamp = (int) ((weather.queryTime - SimpleTimeZone.getDefault().getOffset(weather.queryTime)) / 1000);
|
||||||
weatherSpec.location = weather.location;
|
weatherSpec.location = weather.location;
|
||||||
weatherSpec.currentTemp = weather.currentTemp;
|
weatherSpec.currentTemp = weather.currentTemp;
|
||||||
weatherSpec.currentCondition = weather.currentCondition;
|
weatherSpec.currentCondition = weather.currentCondition;
|
||||||
|
@ -37,7 +37,8 @@ public enum AlertCategory {
|
|||||||
// 10-250 reserved for future use
|
// 10-250 reserved for future use
|
||||||
// 251-255 defined by service specification
|
// 251-255 defined by service specification
|
||||||
Any(255),
|
Any(255),
|
||||||
Custom(-1);
|
Custom(-1),
|
||||||
|
CustomAmazfitBip(-6);
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
|
|
||||||
|
@ -33,12 +33,16 @@ import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
|||||||
|
|
||||||
public class AlertNotificationProfile<T extends AbstractBTLEDeviceSupport> extends AbstractBleProfile<T> {
|
public class AlertNotificationProfile<T extends AbstractBTLEDeviceSupport> extends AbstractBleProfile<T> {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(AlertNotificationProfile.class);
|
private static final Logger LOG = LoggerFactory.getLogger(AlertNotificationProfile.class);
|
||||||
private static final int MAX_MSG_LENGTH = 18;
|
private int maxLength = 18; // Mi2-ism?
|
||||||
|
|
||||||
public AlertNotificationProfile(T support) {
|
public AlertNotificationProfile(T support) {
|
||||||
super(support);
|
super(support);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaxLength(int maxLength) {
|
||||||
|
this.maxLength = maxLength;
|
||||||
|
}
|
||||||
|
|
||||||
public void configure(TransactionBuilder builder, AlertNotificationControl control) {
|
public void configure(TransactionBuilder builder, AlertNotificationControl control) {
|
||||||
BluetoothGattCharacteristic characteristic = getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_NOTIFICATION_CONTROL_POINT);
|
BluetoothGattCharacteristic characteristic = getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_NOTIFICATION_CONTROL_POINT);
|
||||||
if (characteristic != null) {
|
if (characteristic != null) {
|
||||||
@ -57,21 +61,21 @@ public class AlertNotificationProfile<T extends AbstractBTLEDeviceSupport> exten
|
|||||||
BluetoothGattCharacteristic characteristic = getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_NEW_ALERT);
|
BluetoothGattCharacteristic characteristic = getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_NEW_ALERT);
|
||||||
if (characteristic != null) {
|
if (characteristic != null) {
|
||||||
String message = StringUtils.ensureNotNull(alert.getMessage());
|
String message = StringUtils.ensureNotNull(alert.getMessage());
|
||||||
if (message.length() > MAX_MSG_LENGTH && strategy == OverflowStrategy.TRUNCATE) {
|
if (message.length() > maxLength && strategy == OverflowStrategy.TRUNCATE) {
|
||||||
message = StringUtils.truncate(message, MAX_MSG_LENGTH);
|
message = StringUtils.truncate(message, maxLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
int numChunks = message.length() / MAX_MSG_LENGTH;
|
int numChunks = message.length() / maxLength;
|
||||||
if (message.length() % MAX_MSG_LENGTH > 0) {
|
if (message.length() % maxLength > 0) {
|
||||||
numChunks++;
|
numChunks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boolean hasAlerted = false;
|
boolean hasAlerted = false;
|
||||||
for (int i = 0; i < numChunks; i++) {
|
for (int i = 0; i < numChunks; i++) {
|
||||||
int offset = i * MAX_MSG_LENGTH;
|
int offset = i * maxLength;
|
||||||
int restLength = message.length() - offset;
|
int restLength = message.length() - offset;
|
||||||
message = message.substring(offset, offset + Math.min(MAX_MSG_LENGTH, restLength));
|
message = message.substring(offset, offset + Math.min(maxLength, restLength));
|
||||||
if (hasAlerted && message.length() == 0) {
|
if (hasAlerted && message.length() == 0) {
|
||||||
// no need to do it again when there is no text content
|
// no need to do it again when there is no text content
|
||||||
break;
|
break;
|
||||||
@ -91,10 +95,17 @@ public class AlertNotificationProfile<T extends AbstractBTLEDeviceSupport> exten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void newAlert(TransactionBuilder builder, NewAlert alert) {
|
||||||
|
newAlert(builder, alert, OverflowStrategy.TRUNCATE);
|
||||||
|
}
|
||||||
|
|
||||||
protected byte[] getAlertMessage(NewAlert alert, String message, int chunk) throws IOException {
|
protected byte[] getAlertMessage(NewAlert alert, String message, int chunk) throws IOException {
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream(100);
|
ByteArrayOutputStream stream = new ByteArrayOutputStream(100);
|
||||||
stream.write(BLETypeConversions.fromUint8(alert.getCategory().getId()));
|
stream.write(BLETypeConversions.fromUint8(alert.getCategory().getId()));
|
||||||
stream.write(BLETypeConversions.fromUint8(alert.getNumAlerts()));
|
stream.write(BLETypeConversions.fromUint8(alert.getNumAlerts()));
|
||||||
|
if (alert.getCategory() == AlertCategory.CustomAmazfitBip) {
|
||||||
|
stream.write(BLETypeConversions.fromUint8(alert.getCustomIcon()));
|
||||||
|
}
|
||||||
|
|
||||||
if (message.length() > 0) {
|
if (message.length() > 0) {
|
||||||
stream.write(BLETypeConversions.toUtf8s(message));
|
stream.write(BLETypeConversions.toUtf8s(message));
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification;
|
package nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification;
|
||||||
|
|
||||||
|
import android.icu.util.IslamicCalendar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.new_alert.xml&u=org.bluetooth.characteristic.new_alert.xml
|
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.new_alert.xml&u=org.bluetooth.characteristic.new_alert.xml
|
||||||
*
|
*
|
||||||
@ -47,6 +49,7 @@ public class NewAlert {
|
|||||||
private final AlertCategory category;
|
private final AlertCategory category;
|
||||||
private final int numAlerts;
|
private final int numAlerts;
|
||||||
private final String message;
|
private final String message;
|
||||||
|
private int customIcon = -1;
|
||||||
|
|
||||||
public NewAlert(AlertCategory category, int /*uint8*/ numAlerts, String /*utf8s*/ message) {
|
public NewAlert(AlertCategory category, int /*uint8*/ numAlerts, String /*utf8s*/ message) {
|
||||||
this.category = category;
|
this.category = category;
|
||||||
@ -54,6 +57,13 @@ public class NewAlert {
|
|||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NewAlert(AlertCategory category, int /*uint8*/ numAlerts, String /*utf8s*/ message, int customIcon) {
|
||||||
|
this.category = category;
|
||||||
|
this.numAlerts = numAlerts;
|
||||||
|
this.message = message;
|
||||||
|
this.customIcon = customIcon;
|
||||||
|
}
|
||||||
|
|
||||||
public AlertCategory getCategory() {
|
public AlertCategory getCategory() {
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
@ -65,4 +75,8 @@ public class NewAlert {
|
|||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCustomIcon() {
|
||||||
|
return customIcon;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,17 +16,77 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip;
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip.AmazfitBipIcon;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip.AmazfitBipService;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip.AmazfitBipWeatherConditions;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.NewAlert;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||||
|
|
||||||
public class AmazfitBipSupport extends MiBand2Support {
|
public class AmazfitBipSupport extends MiBand2Support {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(AmazfitBipSupport.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NotificationStrategy getNotificationStrategy() {
|
public NotificationStrategy getNotificationStrategy() {
|
||||||
return new AmazfitBipTextNotificationStrategy(this);
|
return new AmazfitBipTextNotificationStrategy(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotification(NotificationSpec notificationSpec) {
|
||||||
|
if (notificationSpec.type == NotificationType.GENERIC_ALARM_CLOCK) {
|
||||||
|
onAlarmClock(notificationSpec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String senderOrTiltle = StringUtils.getFirstOf(notificationSpec.sender, notificationSpec.title);
|
||||||
|
|
||||||
|
String message = StringUtils.truncate(senderOrTiltle, 32) + "\0";
|
||||||
|
if (notificationSpec.subject != null) {
|
||||||
|
message += StringUtils.truncate(notificationSpec.subject, 128) + "\n\n";
|
||||||
|
}
|
||||||
|
if (notificationSpec.body != null) {
|
||||||
|
message += StringUtils.truncate(notificationSpec.body, 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
TransactionBuilder builder = performInitialized("new notification");
|
||||||
|
AlertNotificationProfile<?> profile = new AlertNotificationProfile(this);
|
||||||
|
profile.setMaxLength(255); // TODO: find out real limit, certainly it is more than 18 which is default
|
||||||
|
|
||||||
|
int customIconId = AmazfitBipIcon.mapToIconId(notificationSpec.type);
|
||||||
|
|
||||||
|
AlertCategory alertCategory = AlertCategory.CustomAmazfitBip;
|
||||||
|
|
||||||
|
// The SMS icon for AlertCategory.SMS is unique and not available as iconId
|
||||||
|
if (notificationSpec.type == NotificationType.GENERIC_SMS) {
|
||||||
|
alertCategory = AlertCategory.SMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewAlert alert = new NewAlert(alertCategory, 1, message, customIconId);
|
||||||
|
profile.newAlert(builder, alert);
|
||||||
|
builder.queue(getQueue());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.error("Unable to send notification to Amazfit Bip", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFindDevice(boolean start) {
|
public void onFindDevice(boolean start) {
|
||||||
CallSpec callSpec = new CallSpec();
|
CallSpec callSpec = new CallSpec();
|
||||||
@ -51,4 +111,36 @@ public class AmazfitBipSupport extends MiBand2Support {
|
|||||||
}
|
}
|
||||||
evaluateGBDeviceEvent(callCmd);
|
evaluateGBDeviceEvent(callCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||||
|
try {
|
||||||
|
TransactionBuilder builder = performInitialized("Sending weather forecast");
|
||||||
|
final byte NR_DAYS = 2;
|
||||||
|
ByteBuffer buf = ByteBuffer.allocate(7 + 4 * NR_DAYS);
|
||||||
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
buf.put((byte) 1);
|
||||||
|
buf.putInt(weatherSpec.timestamp);
|
||||||
|
buf.put((byte) 0);
|
||||||
|
|
||||||
|
buf.put(NR_DAYS);
|
||||||
|
|
||||||
|
byte condition = AmazfitBipWeatherConditions.mapToAmazfitBipWeatherCode(weatherSpec.currentConditionCode);
|
||||||
|
buf.put(condition);
|
||||||
|
buf.put(condition);
|
||||||
|
buf.put((byte) (weatherSpec.todayMaxTemp - 273));
|
||||||
|
buf.put((byte) (weatherSpec.todayMinTemp - 273));
|
||||||
|
|
||||||
|
condition = AmazfitBipWeatherConditions.mapToAmazfitBipWeatherCode(weatherSpec.tomorrowConditionCode);
|
||||||
|
|
||||||
|
buf.put(condition);
|
||||||
|
buf.put(condition);
|
||||||
|
buf.put((byte) (weatherSpec.tomorrowMaxTemp - 273));
|
||||||
|
buf.put((byte) (weatherSpec.tomorrowMinTemp - 273));
|
||||||
|
|
||||||
|
builder.write(getCharacteristic(AmazfitBipService.UUID_CHARACTERISTIC_WEATHER), buf.array());
|
||||||
|
builder.queue(getQueue());
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -16,15 +16,22 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip;
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.NewAlert;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.OverflowStrategy;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.Mi2TextNotificationStrategy;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.Mi2TextNotificationStrategy;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
|
// This class in no longer in use except for incoming calls
|
||||||
class AmazfitBipTextNotificationStrategy extends Mi2TextNotificationStrategy {
|
class AmazfitBipTextNotificationStrategy extends Mi2TextNotificationStrategy {
|
||||||
|
|
||||||
AmazfitBipTextNotificationStrategy(MiBand2Support support) {
|
AmazfitBipTextNotificationStrategy(MiBand2Support support) {
|
||||||
@ -33,14 +40,28 @@ class AmazfitBipTextNotificationStrategy extends Mi2TextNotificationStrategy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, BtLEAction extraAction, TransactionBuilder builder) {
|
protected void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, BtLEAction extraAction, TransactionBuilder builder) {
|
||||||
if (simpleNotification != null && simpleNotification.getAlertCategory() == AlertCategory.IncomingCall) {
|
|
||||||
// incoming calls are notified solely via NewAlert including caller ID
|
|
||||||
sendAlert(simpleNotification, builder);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (simpleNotification != null && !StringUtils.isEmpty(simpleNotification.getMessage())) {
|
if (simpleNotification != null && !StringUtils.isEmpty(simpleNotification.getMessage())) {
|
||||||
sendAlert(simpleNotification, builder);
|
sendAlert(simpleNotification, builder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void sendAlert(@NonNull SimpleNotification simpleNotification, TransactionBuilder builder) {
|
||||||
|
AlertNotificationProfile<?> profile = new AlertNotificationProfile<>(getSupport());
|
||||||
|
profile.setMaxLength(255); // TODO: find out real limit, certainly it is more than 18 which is default
|
||||||
|
|
||||||
|
AlertCategory category = simpleNotification.getAlertCategory();
|
||||||
|
switch (simpleNotification.getAlertCategory()) {
|
||||||
|
// only these are confirmed working so far on Amazfit Bip
|
||||||
|
case Email:
|
||||||
|
case IncomingCall:
|
||||||
|
case SMS:
|
||||||
|
break;
|
||||||
|
// default to SMS for non working categories
|
||||||
|
default:
|
||||||
|
category = AlertCategory.SMS;
|
||||||
|
}
|
||||||
|
NewAlert alert = new NewAlert(category, 1, simpleNotification.getMessage());
|
||||||
|
profile.newAlert(builder, alert, OverflowStrategy.TRUNCATE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,7 +435,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performPreferredNotification(String task, String notificationOrigin, SimpleNotification simpleNotification, int alertLevel, BtLEAction extraAction) {
|
protected void performPreferredNotification(String task, String notificationOrigin, SimpleNotification simpleNotification, int alertLevel, BtLEAction extraAction) {
|
||||||
try {
|
try {
|
||||||
TransactionBuilder builder = performInitialized(task);
|
TransactionBuilder builder = performInitialized(task);
|
||||||
Prefs prefs = GBApplication.getPrefs();
|
Prefs prefs = GBApplication.getPrefs();
|
||||||
@ -529,7 +529,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
|||||||
performPreferredNotification(origin + " received", origin, simpleNotification, alertLevel, null);
|
performPreferredNotification(origin + " received", origin, simpleNotification, alertLevel, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAlarmClock(NotificationSpec notificationSpec) {
|
protected void onAlarmClock(NotificationSpec notificationSpec) {
|
||||||
alarmClockRinging = true;
|
alarmClockRinging = true;
|
||||||
AbortTransactionAction abortAction = new StopNotificationAction(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL)) {
|
AbortTransactionAction abortAction = new StopNotificationAction(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL)) {
|
||||||
@Override
|
@Override
|
||||||
|
43
app/src/main/res/drawable/ic_donate.xml
Normal file
43
app/src/main/res/drawable/ic_donate.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="48dp"
|
||||||
|
android:height="48dp"
|
||||||
|
android:viewportWidth="48"
|
||||||
|
android:viewportHeight="48">
|
||||||
|
|
||||||
|
<group android:scaleY="-1">
|
||||||
|
<group android:translateY="-48">
|
||||||
|
<path
|
||||||
|
android:fillColor="#000000"
|
||||||
|
android:strokeWidth="0.75"
|
||||||
|
android:strokeMiterLimit="79.8403193612775"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M 17.266,14.156 C 17.266,16.557 18.748,18.614 20.847,19.466 L 20.749,19.461 C
|
||||||
|
18.032,21.925 18.249,23.288 18.202,24.301 L 18.202,24.812 C 13.398,21.976
|
||||||
|
8.006,18.283 6.316,19.973 L 5.892,20.99 C 11.546,24.893 17.202,28.796
|
||||||
|
21.852,32.704 C 22.249,33.138 22.902,33.403 23.974,33.385 C 28.907,33.336
|
||||||
|
33.583,32.949 38.07,32.451 L 43.588,34.829 L 43.417,27.782 C 38.887,23.557
|
||||||
|
32.161,21.394 27.091,18.166 C 28.105,17.132 28.732,15.715 28.732,14.156 C
|
||||||
|
28.732,10.992 26.164,8.423 22.998,8.423 C 19.835,8.423 17.266,10.992
|
||||||
|
17.266,14.156 Z M 27.246,14.156 C 27.246,16.496 25.341,18.399 22.998,18.399 C
|
||||||
|
20.655,18.399 18.752,16.496 18.752,14.156 C 18.752,11.813 20.655,9.911
|
||||||
|
22.998,9.911 C 25.341,9.911 27.246,11.813 27.246,14.156 Z M 21.197,11.848 C
|
||||||
|
20.842,12.223 20.608,12.689 20.497,13.249 L 19.885,13.249 L 20.018,13.888 L
|
||||||
|
20.423,13.888 C 20.42,13.954 20.415,14.027 20.415,14.101 C 20.415,14.229
|
||||||
|
20.42,14.338 20.426,14.434 L 19.885,14.434 L 20.018,15.075 L 20.509,15.075 C
|
||||||
|
20.625,15.625 20.854,16.084 21.198,16.452 C 21.721,17.009 22.403,17.285
|
||||||
|
23.253,17.285 C 23.716,17.285 24.118,17.202 24.458,17.036 L 24.216,15.889 C
|
||||||
|
23.98,16.124 23.64,16.24 23.19,16.24 C 22.74,16.24 22.378,16.079 22.101,15.756 C
|
||||||
|
21.943,15.576 21.832,15.347 21.766,15.075 L 24.04,15.075 L 23.905,14.434 L
|
||||||
|
21.683,14.434 C 21.68,14.373 21.679,14.291 21.679,14.192 C 21.679,14.096
|
||||||
|
21.68,13.994 21.686,13.888 L 23.791,13.888 L 23.659,13.249 L 21.772,13.249 C
|
||||||
|
21.842,12.953 21.946,12.721 22.093,12.556 C 22.367,12.23 22.728,12.067
|
||||||
|
23.166,12.067 C 23.694,12.067 24.117,12.23 24.431,12.556 L 24.431,11.29 C
|
||||||
|
24.073,11.11 23.656,11.021 23.179,11.021 C 22.375,11.021 21.713,11.298
|
||||||
|
21.197,11.848 Z M 29.494,23.708 C 30.203,25.42 30.088,27.919 24.739,26.679 C
|
||||||
|
21.778,25.437 21.126,24.068 22.192,22.603 C 22.787,21.692 23.124,20.787
|
||||||
|
23.329,19.878 C 23.931,19.843 24.507,19.716 25.047,19.508 C 26.476,21.08
|
||||||
|
28.884,22.241 29.494,23.708 Z" />
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</vector>
|
@ -21,6 +21,10 @@
|
|||||||
<group
|
<group
|
||||||
android:checkableBehavior="single"
|
android:checkableBehavior="single"
|
||||||
android:id="@+id/further_options">
|
android:id="@+id/further_options">
|
||||||
|
<item
|
||||||
|
android:id="@+id/donation_link"
|
||||||
|
android:title="@string/action_donate"
|
||||||
|
android:icon="@drawable/ic_donate" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/external_changelog"
|
android:id="@+id/external_changelog"
|
||||||
android:title="@string/changelog_full_title" />
|
android:title="@string/changelog_full_title" />
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<string name="action_settings">Settings</string>
|
<string name="action_settings">Settings</string>
|
||||||
<string name="action_debug">Debug</string>
|
<string name="action_debug">Debug</string>
|
||||||
<string name="action_quit">Quit</string>
|
<string name="action_quit">Quit</string>
|
||||||
|
<string name="action_donate">Donate</string>
|
||||||
<string name="controlcenter_fetch_activity_data">Synchronize</string>
|
<string name="controlcenter_fetch_activity_data">Synchronize</string>
|
||||||
<string name="controlcenter_start_sleepmonitor">Sleep Monitor (ALPHA)</string>
|
<string name="controlcenter_start_sleepmonitor">Sleep Monitor (ALPHA)</string>
|
||||||
<string name="controlcenter_find_device">Find lost Device…</string>
|
<string name="controlcenter_find_device">Find lost Device…</string>
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<changelog>
|
<changelog>
|
||||||
<release
|
<release version="0.20.1" versioncode="99">
|
||||||
version="0.20.0"
|
<change>Amazfit Bip: Support icons and text body for notifications</change>
|
||||||
versioncode="98">
|
<change>Mi Band: Fix setting smart alarms</change>
|
||||||
|
</release>
|
||||||
|
<release version="0.20.0" versioncode="98">
|
||||||
<change>Inital Amazfit Bip support (WIP)</change>
|
<change>Inital Amazfit Bip support (WIP)</change>
|
||||||
<change>Various theming fixes</change>
|
<change>Various theming fixes</change>
|
||||||
<change>Add workaround for blacklist not properly persisting</change>
|
<change>Add workaround for blacklist not properly persisting</change>
|
||||||
@ -10,7 +12,7 @@
|
|||||||
<change>Pebble: Pass booleans from Javascript Appmessage correctly</change>
|
<change>Pebble: Pass booleans from Javascript Appmessage correctly</change>
|
||||||
<change>Pebble: Make local configuration pages work on most recent webview implementation</change>
|
<change>Pebble: Make local configuration pages work on most recent webview implementation</change>
|
||||||
<change>Pebble: Allow to blacklist calendars</change>
|
<change>Pebble: Allow to blacklist calendars</change>
|
||||||
<change>Add greek transliteration support</change>
|
<change>Add Greek and German transliteration support</change>
|
||||||
<change>Various visual improvements to charts</change>
|
<change>Various visual improvements to charts</change>
|
||||||
</release>
|
</release>
|
||||||
<release version="0.19.4" versioncode="97">
|
<release version="0.19.4" versioncode="97">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Nutze deine Pebble/Mi Band/Hplus, ohne die proprietäre App des Herstellers, ohne ein Benutzerkonto zu erstellen, und ohne irgendwelche Daten an die Server des Herstellers zu senden.
|
Nutze deine Pebble/Mi Band/Amazfit Bip/Hplus, ohne die proprietäre App des Herstellers, ohne ein Benutzerkonto zu erstellen, und ohne irgendwelche Daten an die Server des Herstellers zu senden.
|
||||||
|
|
||||||
Du kannst Benachrichtigungen an deinem Handgelenk erhalten, sowie (je nach Gerät):
|
Du kannst Benachrichtigungen an deinem Handgelenk erhalten, sowie (je nach Gerät):
|
||||||
- Daten der Gerätesensoren sammeln
|
- Daten der Gerätesensoren sammeln
|
||||||
|
2
fastlane/metadata/android/de-DE/short_description.txt
Normal file
2
fastlane/metadata/android/de-DE/short_description.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Nutze deine Pebble/Mi Band/Amazfit Bip/Hplus, ohne die proprietäre App des Herstellers, ohne ein Benutzerkonto zu erstellen, und ohne irgendwelche Daten an die Server des Herstellers zu senden.
|
||||||
|
|
9
fastlane/metadata/android/en-US/changelogs/98.txt
Normal file
9
fastlane/metadata/android/en-US/changelogs/98.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
* Inital Amazfit Bip support (WIP)
|
||||||
|
* Various theming fixes
|
||||||
|
* Add workaround for blacklist not properly persisting
|
||||||
|
* Handle resetting language to default properly
|
||||||
|
* Pebble: Pass booleans from Javascript Appmessage correctly
|
||||||
|
* Pebble: Make local configuration pages work on most recent webview implementation
|
||||||
|
* Pebble: Allow to blacklist calendars
|
||||||
|
* Add Greek and German transliteration support
|
||||||
|
* Various visual improvements to charts
|
2
fastlane/metadata/android/en-US/changelogs/99.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/99.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
* Amazfit Bip: Support icons and text body for notifications
|
||||||
|
* Mi Band: Fix setting smart alarms
|
@ -1,6 +1,7 @@
|
|||||||
Use your Pebble/Mi Band/Hplus device without the vendor's closed source application and without the need to create an account and transmit any of your data to the vendor's servers.
|
Use your Pebble/Mi Band/Amazfit Bip/Hplus device without the vendor's closed source application and without the need to create an account and transmit any of your data to the vendor's servers.
|
||||||
|
|
||||||
You can get notifications on your wrist and (depending on the device):
|
You can get notifications on your wrist and (depending on the device):
|
||||||
|
|
||||||
- collect data from the device sensors
|
- collect data from the device sensors
|
||||||
- control music playing on your android device
|
- control music playing on your android device
|
||||||
- see the weather
|
- see the weather
|
||||||
|
@ -1 +1 @@
|
|||||||
Use your Pebble/Mi Band/Hplus device without the vendor's closed source application and without the need to create an account and transmit any of your data to the vendor's servers.
|
Use your Pebble/Mi Band/Amazfit Bip/Hplus device without the vendor's closed source application and without the need to create an account and transmit any of your data to the vendor's servers.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Utilizza il tuo dispositivo Pebble/Mi Band/Hplus senza dipendere dall'applicazione proprietaria del vendor e senza bisogno di creare accounts e trasferire i tuoi dati altrove.
|
Utilizza il tuo dispositivo Pebble/Mi Band/Amazfit Bip/Hplus senza dipendere dall'applicazione proprietaria del vendor e senza bisogno di creare accounts e trasferire i tuoi dati altrove.
|
||||||
|
|
||||||
Vedi le notifiche direttamente sul tuo polso, e inoltre (a seconda del dispositivo):
|
Vedi le notifiche direttamente sul tuo polso, e inoltre (a seconda del dispositivo):
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Utilizza il tuo dispositivo Pebble/Mi Band/Hplus senza dipendere dall'applicazione proprietaria del vendor e senza bisogno di creare accounts e trasferire i tuoi dati altrove.
|
Utilizza il tuo dispositivo Pebble/Mi Band/Amazfit Bip/Hplus senza dipendere dall'applicazione proprietaria del vendor e senza bisogno di creare accounts e trasferire i tuoi dati altrove.
|
||||||
|
Loading…
Reference in New Issue
Block a user