diff --git a/CHANGELOG.md b/CHANGELOG.md
index 82201e061..12a2b1a32 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,10 +6,15 @@
* Add Czech translation
* Add Hebrew translation and transliteration
* Consistently display device specific icons already during discovery
-* Add sleep chart diplaying the last week of sleep
+* Add sleep chart displaying the last week of sleep
* Huge speedup for weekly charts when changing days
-* Drop support for pre Gadgetbride 0.12.0 database
-* Pebble: allow configuration webpages (clay) to access device location
+* Drop support for importing pre Gadgetbridge 0.12.0 database
+* Pebble: allow configuration web pages (clay) to access device location
+* Mi2: Initial support for text notifications, caller ID, and icons (requires font installation) (#560)
+* Mi2: Support for flashing Mili_pro.ft* font files
+* Mi2: Improved firmware/font updated
+* Mi2: Set 12h/24h time format, following the Android configuration (#573)
+* Improved BLE discovery and connectivity
####Version 0.17.5
* Automatically start the service on boot (can be turned off)
diff --git a/app/build.gradle b/app/build.gradle
index 40c95594f..90de6d715 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -80,7 +80,6 @@ dependencies {
compile 'org.apache.commons:commons-lang3:3.4'
// compile project(":DaoCore")
- compile 'com.android.support.constraint:constraint-layout:1.0.2'
}
preBuild.dependsOn(":GBDaoGenerator:genSources")
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java
index cfd4ed154..33d18fdbd 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java
@@ -1,3 +1,20 @@
+/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
+ Gobbetti
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.activities;
import android.Manifest;
@@ -10,6 +27,7 @@ import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.os.Build;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.v4.app.ActivityCompat;
@@ -196,7 +214,7 @@ public class ControlCenterv2 extends AppCompatActivity
}
@Override
- public boolean onNavigationItemSelected(MenuItem item) {
+ public boolean onNavigationItemSelected(@NonNull MenuItem item) {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
@@ -274,8 +292,6 @@ public class ControlCenterv2 extends AppCompatActivity
wantedPermissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.READ_CALENDAR);
- if (ContextCompat.checkSelfPermission(this, "com.fsck.k9.permission.READ_MESSAGES") == PackageManager.PERMISSION_DENIED)
- wantedPermissions.add("com.fsck.k9.permission.READ_MESSAGES");
if (!wantedPermissions.isEmpty())
ActivityCompat.requestPermissions(this, wantedPermissions.toArray(new String[wantedPermissions.size()]), 0);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java
index 0ebabb11a..1abd25a34 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java
@@ -224,6 +224,11 @@ public class FwAppInstallerActivity extends GBActivity implements InstallActivit
fwAppInstallTextView.setText(text);
}
+ @Override
+ public CharSequence getInfoText() {
+ return fwAppInstallTextView.getText();
+ }
+
@Override
public void setInstallEnabled(boolean enable) {
boolean enabled = device != null && device.isConnected() && enable;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/InstallActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/InstallActivity.java
index b00c1dfdb..4af5405e6 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/InstallActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/InstallActivity.java
@@ -19,6 +19,8 @@ package nodomain.freeyourgadget.gadgetbridge.activities;
import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
public interface InstallActivity {
+ CharSequence getInfoText();
+
void setInfoText(String text);
void setInstallEnabled(boolean enable);
@@ -26,4 +28,5 @@ public interface InstallActivity {
void clearInstallItems();
void setInstallItem(ItemWithDetails item);
+
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java
index c92d63348..27e64d649 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java
@@ -1,3 +1,20 @@
+/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
+ Gobbetti, Lem Dulfo
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.adapter;
import android.app.Activity;
@@ -27,11 +44,13 @@ import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
+import nodomain.freeyourgadget.gadgetbridge.activities.VibrationActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
+import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@@ -61,7 +80,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter();
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java
index 44ae13039..998e94b31 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java
@@ -21,6 +21,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
+import nodomain.freeyourgadget.gadgetbridge.util.Version;
public final class MiBandConst {
private static final Logger LOG = LoggerFactory.getLogger(MiBandConst.class);
@@ -35,6 +36,7 @@ public final class MiBandConst {
public static final String PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS = "mi_device_time_offset_hours";
public static final String PREF_MI2_DATEFORMAT = "mi2_dateformat";
public static final String PREF_MI2_ACTIVATE_DISPLAY_ON_LIFT = "mi2_activate_display_on_lift_wrist";
+ public static final String PREF_MI2_ENABLE_TEXT_NOTIFICATIONS = "mi2_enable_text_notifications";
public static final String PREF_MIBAND_SETUP_BT_PAIRING = "mi_setup_bt_pairing";
@@ -48,6 +50,9 @@ public final class MiBandConst {
public static final String MI_AMAZFIT = "Amazfit";
public static final String MI_PRO = "2";
+ public static final Version MI2_FW_VERSION_MIN_TEXT_NOTIFICATIONS = new Version("1.0.1.28");
+ public static final Version MI2_FW_VERSION_INTERMEDIATE_UPGRADE_53 = new Version("1.0.0.53");
+
public static int getNotificationPrefIntValue(String pref, String origin, Prefs prefs, int defaultValue) {
String key = getNotificationPrefKey(pref, origin);
return prefs.getInt(key, defaultValue);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java
index 5e5a33f33..deed2c2e0 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java
@@ -1,4 +1,5 @@
-/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
+/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
+ Gobbetti
This file is part of Gadgetbridge.
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java
index f9cb2439d..a7916376f 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java
@@ -39,6 +39,7 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.OR
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_INCOMING_CALL;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_ACTIVATE_DISPLAY_ON_LIFT;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DATEFORMAT;
+import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_ENABLE_TEXT_NOTIFICATIONS;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_ADDRESS;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR;
@@ -163,6 +164,7 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity {
prefKeys.add(ActivityUser.PREF_USER_STEPS_GOAL);
prefKeys.add(PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR);
prefKeys.add(PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS);
+ prefKeys.add(PREF_MI2_ENABLE_TEXT_NOTIFICATIONS);
prefKeys.add(getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_ALARM_CLOCK));
prefKeys.add(getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_INCOMING_CALL));
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband2/MiBand2FWInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband2/MiBand2FWInstallHandler.java
index af1336aad..d0ecec252 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband2/MiBand2FWInstallHandler.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband2/MiBand2FWInstallHandler.java
@@ -24,10 +24,15 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
+import nodomain.freeyourgadget.gadgetbridge.R;
+import nodomain.freeyourgadget.gadgetbridge.activities.InstallActivity;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.AbstractMiBandFWHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.AbstractMiBandFWInstallHandler;
+import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.FirmwareType;
+import nodomain.freeyourgadget.gadgetbridge.util.Version;
public class MiBand2FWInstallHandler extends AbstractMiBandFWInstallHandler {
private static final Logger LOG = LoggerFactory.getLogger(MiBand2FWInstallHandler.class);
@@ -36,6 +41,64 @@ public class MiBand2FWInstallHandler extends AbstractMiBandFWInstallHandler {
super(uri, context);
}
+ @Override
+ public void validateInstallation(InstallActivity installActivity, GBDevice device) {
+ super.validateInstallation(installActivity, device);
+ maybeAddFw53Hint(installActivity, device);
+ maybeAddFontHint(installActivity);
+ }
+
+ private void maybeAddFontHint(InstallActivity installActivity) {
+ FirmwareType type = getFirmwareType();
+ if (type == FirmwareType.FIRMWARE) {
+ String newInfoText = installActivity.getInfoText() + "\n\n" + "Note: you may install Mili_pro.ft or Mili_pro.ft.en to enable text notifications.";
+ installActivity.setInfoText(newInfoText);
+ }
+ }
+
+ private void maybeAddFw53Hint(InstallActivity installActivity, GBDevice device) {
+ FirmwareType type = getFirmwareType();
+ if (type != FirmwareType.FIRMWARE) {
+ return;
+ }
+
+ Version deviceVersion = getFirmwareVersionOf(device);
+ if (deviceVersion != null) {
+ Version v53 = MiBandConst.MI2_FW_VERSION_INTERMEDIATE_UPGRADE_53;
+ if (deviceVersion.compareTo(v53) < 0) {
+ String vInstall = getHelper().format(getHelper().getFirmwareVersion());
+ if (vInstall == null || new Version(vInstall).compareTo(v53) > 0) {
+ String newInfoText = getContext().getString(R.string.mi2_fw_installhandler_fw53_hint, v53.get()) + "\n\n" + installActivity.getInfoText();
+ installActivity.setInfoText(newInfoText);
+ }
+ }
+ }
+ }
+
+ private Version getFirmwareVersionOf(GBDevice device) {
+ String version = device.getFirmwareVersion();
+ if (version == null || version.length() == 0) {
+ return null;
+ }
+ if (version.charAt(0) == 'V') {
+ version = version.substring(1);
+ }
+ try {
+ return new Version(version);
+ } catch (Exception ex) {
+ LOG.error("Unable to parse version: " + version);
+ return null;
+ }
+ }
+
+ private FirmwareType getFirmwareType() {
+ AbstractMiBandFWHelper helper = getHelper();
+ if (helper instanceof MiBand2FWHelper) {
+ return ((MiBand2FWHelper) helper).getFirmwareInfo().getFirmwareType();
+ }
+ return FirmwareType.INVALID;
+ }
+
@Override
protected AbstractMiBandFWHelper createHelper(Uri uri, Context context) throws IOException {
return new MiBand2FWHelper(uri, context);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebblePairingActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebblePairingActivity.java
index 017a60504..f7823a01e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebblePairingActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebblePairingActivity.java
@@ -1,4 +1,5 @@
-/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
+/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
+ Gobbetti
This file is part of Gadgetbridge.
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 d7b70c3ec..4aec1b566 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java
@@ -265,7 +265,7 @@ public class NotificationListener extends NotificationListenerService {
notificationSpec.type = AppNotificationType.getInstance().get(source);
- if (source.equals("com.fsck.k9")) {
+ if (source.startsWith("com.fsck.k9")) {
// we dont want group summaries at all for k9
if ((notification.flags & Notification.FLAG_GROUP_SUMMARY) == Notification.FLAG_GROUP_SUMMARY) {
return;
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 ea2537e29..7d3428a1c 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java
@@ -1,5 +1,5 @@
-/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, ivanovlev,
- Julien Pivotto, Kasha, Steffen Liebergeld
+/* Copyright (C) 2015-2017 Alberto, Andreas Shimokawa, Carsten Pfeiffer,
+ ivanovlev, Julien Pivotto, Kasha, Steffen Liebergeld
This file is part of Gadgetbridge.
@@ -73,9 +73,9 @@ public class GBDeviceService implements DeviceService {
}
protected void invokeService(Intent intent) {
- if(LanguageUtils.transliterate()){
- for (String extra: transliterationExtras) {
- if (intent.hasExtra(extra)){
+ if (LanguageUtils.transliterate()) {
+ for (String extra : transliterationExtras) {
+ if (intent.hasExtra(extra)) {
intent.putExtra(extra, LanguageUtils.transliterate(intent.getStringExtra(extra)));
}
}
@@ -172,12 +172,15 @@ public class GBDeviceService implements DeviceService {
String currentPrivacyMode = GBApplication.getPrefs().getString("pref_call_privacy_mode", GBApplication.getContext().getString(R.string.p_call_privacy_mode_off));
if (context.getString(R.string.p_call_privacy_mode_name).equals(currentPrivacyMode)) {
callSpec.name = callSpec.number;
- }
- else if (context.getString(R.string.p_call_privacy_mode_complete).equals(currentPrivacyMode)) {
+ } else if (context.getString(R.string.p_call_privacy_mode_complete).equals(currentPrivacyMode)) {
callSpec.number = null;
callSpec.name = null;
- }
- else {
+ } else if (context.getString(R.string.pref_call_privacy_mode_number).equals(currentPrivacyMode)) {
+ callSpec.name = coalesce(callSpec.name, getContactDisplayNameByNumber(callSpec.number));
+ if (callSpec.name != null && !callSpec.name.equals(callSpec.number)) {
+ callSpec.number = null;
+ }
+ } else {
callSpec.name = coalesce(callSpec.name, getContactDisplayNameByNumber(callSpec.number));
}
@@ -372,6 +375,7 @@ public class GBDeviceService implements DeviceService {
/**
* Returns contact DisplayName by call number
+ *
* @param number contact number
* @return contact DisplayName, if found it
*/
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/AppNotificationType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/AppNotificationType.java
index 7f78dc80e..29b2f2b6f 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/AppNotificationType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/AppNotificationType.java
@@ -33,6 +33,7 @@ public class AppNotificationType extends HashMap {
private AppNotificationType() {
// Generic Email
put("com.fsck.k9", NotificationType.GENERIC_EMAIL);
+ put("com.fsck.k9.material", NotificationType.GENERIC_EMAIL);
put("com.imaeses.squeaky", NotificationType.GENERIC_EMAIL);
put("com.android.email", NotificationType.GENERIC_EMAIL);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertCategory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertCategory.java
index cb5ed147c..3c7e6ae4d 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertCategory.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertCategory.java
@@ -33,9 +33,11 @@ public enum AlertCategory {
VoiceMail(6),
Schedule(7),
HighPriorityAlert(8),
- InstantMessage(9);
+ InstantMessage(9),
// 10-250 reserved for future use
// 251-255 defined by service specification
+ Any(255),
+ Custom(-1);
private final int id;
@@ -91,5 +93,4 @@ public enum AlertCategory {
return null;
}
-
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertNotificationControl.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertNotificationControl.java
index c470905c2..ebb111ae1 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertNotificationControl.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertNotificationControl.java
@@ -16,9 +16,39 @@
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
+
/**
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.alert_notification_control_point.xml
*/
public class AlertNotificationControl {
+ private AlertCategory category;
+ private Command command;
+ public void setCategory(AlertCategory category) {
+ this.category = category;
+ }
+
+ public void setCommand(Command command) {
+ this.command = command;
+ }
+
+ public AlertCategory getCategory() {
+ return category;
+ }
+
+ public Command getCommand() {
+ return command;
+ }
+
+ /**
+ * Returns the formatted message to be written to the alert notification control point
+ * characteristic
+ */
+ public byte[] getControlMessage() {
+ return new byte[] {
+ BLETypeConversions.fromUint8(command.getId()),
+ BLETypeConversions.fromUint8(category.getId())
+ };
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertNotificationProfile.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertNotificationProfile.java
index 751f3d47f..48b115524 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertNotificationProfile.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/AlertNotificationProfile.java
@@ -39,10 +39,24 @@ public class AlertNotificationProfile exten
super(support);
}
+ public void configure(TransactionBuilder builder, AlertNotificationControl control) {
+ BluetoothGattCharacteristic characteristic = getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_NOTIFICATION_CONTROL_POINT);
+ if (characteristic != null) {
+ builder.write(characteristic, control.getControlMessage());
+ }
+ }
+
+ public void updateAlertLevel(TransactionBuilder builder, AlertLevel level) {
+ BluetoothGattCharacteristic characteristic = getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL);
+ if (characteristic != null) {
+ builder.write(characteristic, new byte[] {BLETypeConversions.fromUint8(level.getId())});
+ }
+ }
+
public void newAlert(TransactionBuilder builder, NewAlert alert, OverflowStrategy strategy) {
BluetoothGattCharacteristic characteristic = getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_NEW_ALERT);
if (characteristic != null) {
- String message = alert.getMessage();
+ String message = StringUtils.ensureNotNull(alert.getMessage());
if (message.length() > MAX_MSG_LENGTH && strategy == OverflowStrategy.TRUNCATE) {
message = StringUtils.truncate(message, MAX_MSG_LENGTH);
}
@@ -52,31 +66,42 @@ public class AlertNotificationProfile exten
numChunks++;
}
- for (int i = 0; i < numChunks; i++) {
- int offset = i * MAX_MSG_LENGTH;
- int restLength = message.length() - offset;
- message = message.substring(offset, offset + Math.min(MAX_MSG_LENGTH, restLength));
- if (message.length() == 0) {
- break;
+ try {
+ boolean hasAlerted = false;
+ for (int i = 0; i < numChunks; i++) {
+ int offset = i * MAX_MSG_LENGTH;
+ int restLength = message.length() - offset;
+ message = message.substring(offset, offset + Math.min(MAX_MSG_LENGTH, restLength));
+ if (hasAlerted && message.length() == 0) {
+ // no need to do it again when there is no text content
+ break;
+ }
+ builder.write(characteristic, getAlertMessage(alert, message, 1));
+ hasAlerted = true;
}
- writeAlertMessage(builder, characteristic, alert, message, i);
+ if (!hasAlerted) {
+ builder.write(characteristic, getAlertMessage(alert, "", 1));
+ }
+ } catch (IOException ex) {
+ // ain't gonna happen
+ LOG.error("Error writing alert message to ByteArrayOutputStream");
}
} else {
LOG.warn("NEW_ALERT characteristic not available");
}
}
- protected void writeAlertMessage(TransactionBuilder builder, BluetoothGattCharacteristic characteristic, NewAlert alert, String message, int chunk) {
- try {
- ByteArrayOutputStream stream = new ByteArrayOutputStream(100);
- stream.write(alert.getCategory().getId());
- stream.write(alert.getNumAlerts());
- stream.write(BLETypeConversions.toUtf8s(message));
+ protected byte[] getAlertMessage(NewAlert alert, String message, int chunk) throws IOException {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream(100);
+ stream.write(BLETypeConversions.fromUint8(alert.getCategory().getId()));
+ stream.write(BLETypeConversions.fromUint8(alert.getNumAlerts()));
- builder.write(characteristic, stream.toByteArray());
- } catch (IOException ex) {
- // aint gonna happen
- LOG.error("Error writing alert message to ByteArrayOutputStream");
+ if (message.length() > 0) {
+ stream.write(BLETypeConversions.toUtf8s(message));
+ } else {
+ // some write a null byte instead of leaving out this optional value
+// stream.write(new byte[] {0});
}
+ return stream.toByteArray();
}
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/Command.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/Command.java
new file mode 100644
index 000000000..e7d4021db
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/alertnotification/Command.java
@@ -0,0 +1,40 @@
+/* Copyright (C) 2017 Carsten Pfeiffer
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification;
+
+/**
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.alert_notification_control_point.xml
+ */
+public enum Command {
+ EnableNewIncomingAlertNotification(0),
+ EnableUnreadCategoryStatusNotification(1),
+ DisableNewIncomingAlertNotification(2),
+ DisbleUnreadCategoryStatusNotification(3),
+ NotifyNewIncomingAlertImmediately(4),
+ NotifyUnreadCategoryStatusImmediately(5),;
+ // 6-255 reserved for future use
+
+ private final int id;
+
+ Command(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+}
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 2ed1dbf6d..96f42311e 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
@@ -1,4 +1,5 @@
-/* Copyright (C) 2016-2017 Andreas Shimokawa, ivanovlev, João Paulo Barraca
+/* Copyright (C) 2016-2017 Alberto, Andreas Shimokawa, ivanovlev, João
+ Paulo Barraca
This file is part of Gadgetbridge.
@@ -669,18 +670,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
byte[] msg = new byte[13];
- //Show call number
- for (int i = 0; i < msg.length; i++)
- msg[i] = ' ';
-
- for (int i = 0; i < number.length() && i < (msg.length - 1); i++)
- msg[i + 1] = (byte) number.charAt(i);
-
- msg[0] = HPlusConstants.CMD_SET_INCOMING_CALL_NUMBER;
-
- builder.write(ctrlCharacteristic, msg);
- builder.wait(200);
- msg = msg.clone();
//Show call name
@@ -697,6 +686,20 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
msg[0] = HPlusConstants.CMD_ACTION_DISPLAY_TEXT_NAME_CN;
builder.write(ctrlCharacteristic, msg);
+ builder.wait(200);
+ msg = msg.clone();
+
+ //Show call number
+ for (int i = 0; i < msg.length; i++)
+ msg[i] = ' ';
+
+ for (int i = 0; i < number.length() && i < (msg.length - 1); i++)
+ msg[i + 1] = (byte) number.charAt(i);
+
+ msg[0] = HPlusConstants.CMD_SET_INCOMING_CALL_NUMBER;
+
+ builder.write(ctrlCharacteristic, msg);
+
builder.queue(getQueue());
} catch (IOException e) {
GB.toast(getContext(), "Error showing incoming call: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
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 fcb5e0092..2df2fee52 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
@@ -22,6 +22,7 @@ import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Intent;
import android.net.Uri;
+import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.widget.Toast;
@@ -72,7 +73,6 @@ 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;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
@@ -248,7 +248,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
* @param extraAction an extra action to be executed after every vibration and flash sequence. Allows to abort the repetition, for example.
* @param builder
*/
- private MiBandSupport sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
+ private MiBandSupport sendCustomNotification(VibrationProfile vibrationProfile, @Nullable SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
getNotificationStrategy().sendCustomNotification(vibrationProfile, simpleNotification, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
LOG.info("Sending notification to MiBand");
return this;
@@ -487,7 +487,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
}
}
- private void performPreferredNotification(String task, SimpleNotification simpleNotification, String notificationOrigin, BtLEAction extraAction) {
+ private void performPreferredNotification(String task, @Nullable SimpleNotification simpleNotification, String notificationOrigin, BtLEAction extraAction) {
try {
TransactionBuilder builder = performInitialized(task);
Prefs prefs = GBApplication.getPrefs();
@@ -572,11 +572,8 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
return;
}
- String message = NotificationUtils.getPreferredTextFor(notificationSpec, 40, 40, getContext()).trim();
- SimpleNotification simpleNotification = new SimpleNotification(message, BLETypeConversions.toAlertCategory(notificationSpec.type));
-
String origin = notificationSpec.type.getGenericType();
- performPreferredNotification(origin + " received", simpleNotification, origin, null);
+ performPreferredNotification(origin + " received", null, origin, null);
}
private void onAlarmClock(NotificationSpec notificationSpec) {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/NoNotificationStrategy.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/NoNotificationStrategy.java
index 0aa68d250..32054d357 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/NoNotificationStrategy.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/NoNotificationStrategy.java
@@ -39,4 +39,9 @@ public class NoNotificationStrategy implements NotificationStrategy {
public void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
LOG.info("dummy notification stragegy: custom notification: " + simpleNotification);
}
+
+ @Override
+ public void stopCurrentNotification(TransactionBuilder builder) {
+ LOG.info("dummy notification stragegy: stop notification");
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/NotificationStrategy.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/NotificationStrategy.java
index 2d23b50f1..896b349cd 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/NotificationStrategy.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/NotificationStrategy.java
@@ -16,6 +16,8 @@
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
+import android.support.annotation.Nullable;
+
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
@@ -27,7 +29,7 @@ public interface NotificationStrategy {
/**
* Adds a custom notification to the given transaction builder
* @param vibrationProfile specifies how and how often the Band shall vibrate.
- * @param simpleNotification
+ * @param simpleNotification an optional notification containing a type and text message
* @param flashTimes
* @param flashColour
* @param originalColour
@@ -35,5 +37,11 @@ public interface NotificationStrategy {
* @param extraAction an extra action to be executed after every vibration and flash sequence. Allows to abort the repetition, for example.
* @param builder
*/
- void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder);
+ void sendCustomNotification(VibrationProfile vibrationProfile, @Nullable SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder);
+
+ /**
+ * Stops any current notification.
+ * @param builder
+ */
+ void stopCurrentNotification(TransactionBuilder builder);
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/V1NotificationStrategy.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/V1NotificationStrategy.java
index 3b58940c8..30a4e1866 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/V1NotificationStrategy.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/V1NotificationStrategy.java
@@ -103,6 +103,12 @@ public class V1NotificationStrategy implements NotificationStrategy {
}
}
+ @Override
+ public void stopCurrentNotification(TransactionBuilder builder) {
+ BluetoothGattCharacteristic controlPoint = support.getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT);
+ builder.write(controlPoint, stopVibrate);
+ }
+
// private void sendCustomNotification(int vibrateDuration, int vibrateTimes, int pause, int flashTimes, int flashColour, int originalColour, long flashDuration, TransactionBuilder builder) {
// BluetoothGattCharacteristic controlPoint = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT);
// int vDuration = Math.min(500, vibrateDuration); // longer than 500ms is not possible
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/V2NotificationStrategy.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/V2NotificationStrategy.java
index ff72eb213..865b30d2e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/V2NotificationStrategy.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/V2NotificationStrategy.java
@@ -17,25 +17,23 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
import android.bluetooth.BluetoothGattCharacteristic;
+import android.support.annotation.Nullable;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
-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;
-public class V2NotificationStrategy implements NotificationStrategy {
- private final AbstractBTLEDeviceSupport support;
+public class V2NotificationStrategy implements NotificationStrategy {
+ private final T support;
- public V2NotificationStrategy(AbstractBTLEDeviceSupport support) {
+ public V2NotificationStrategy(T support) {
this.support = support;
}
- protected AbstractBTLEDeviceSupport getSupport() {
+ protected T getSupport() {
return support;
}
@@ -45,7 +43,7 @@ public class V2NotificationStrategy implements NotificationStrategy {
sendCustomNotification(profile, simpleNotification, extraAction, builder);
}
- protected void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, BtLEAction extraAction, TransactionBuilder builder) {
+ protected void sendCustomNotification(VibrationProfile vibrationProfile, @Nullable SimpleNotification simpleNotification, BtLEAction extraAction, TransactionBuilder builder) {
//use the new alert characteristic
BluetoothGattCharacteristic alert = support.getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL);
for (short i = 0; i < vibrationProfile.getRepeat(); i++) {
@@ -69,13 +67,6 @@ public class V2NotificationStrategy implements NotificationStrategy {
}
}
}
-// sendAlert(simpleNotification, builder);
- }
-
- protected void sendAlert(SimpleNotification simpleNotification, TransactionBuilder builder) {
- AlertNotificationProfile> profile = new AlertNotificationProfile<>(getSupport());
- NewAlert alert = new NewAlert(simpleNotification.getAlertCategory(), 1, simpleNotification.getMessage());
- profile.newAlert(builder, alert, OverflowStrategy.MAKE_MULTIPLE);
}
@Override
@@ -83,4 +74,10 @@ public class V2NotificationStrategy implements NotificationStrategy {
// all other parameters are unfortunately not supported anymore ;-(
sendCustomNotification(vibrationProfile, simpleNotification, extraAction, builder);
}
+
+ @Override
+ public void stopCurrentNotification(TransactionBuilder builder) {
+ BluetoothGattCharacteristic alert = support.getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL);
+ builder.write(alert, new byte[]{GattCharacteristic.NO_ALERT});
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2FirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2FirmwareInfo.java
index 516b52217..a08a27afa 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2FirmwareInfo.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2FirmwareInfo.java
@@ -55,7 +55,16 @@ public class Mi2FirmwareInfo {
private static Map crcToVersion = new HashMap<>();
static {
+ // firmware
crcToVersion.put(41899, "1.0.0.39");
+ crcToVersion.put(49197, "1.0.0.53");
+ crcToVersion.put(32450, "1.0.1.28");
+ crcToVersion.put(51770, "1.0.1.34");
+ crcToVersion.put(3929, "1.0.1.39");
+
+ // fonts
+ crcToVersion.put(45624, "Font");
+ crcToVersion.put(6377, "Font (En)");
}
private FirmwareType firmwareType = FirmwareType.FIRMWARE;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2NotificationStrategy.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2NotificationStrategy.java
index 497bc2f93..4ec7471f1 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2NotificationStrategy.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2NotificationStrategy.java
@@ -17,34 +17,34 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2;
import android.bluetooth.BluetoothGattCharacteristic;
+import android.support.annotation.Nullable;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
-import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
-import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile;
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.V2NotificationStrategy;
-public class Mi2NotificationStrategy extends V2NotificationStrategy {
+public class Mi2NotificationStrategy extends V2NotificationStrategy {
- public Mi2NotificationStrategy(AbstractBTLEDeviceSupport support) {
+ private final BluetoothGattCharacteristic alertLevelCharacteristic;
+
+ public Mi2NotificationStrategy(MiBand2Support support) {
super(support);
+ alertLevelCharacteristic = support.getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL);
}
@Override
protected void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, BtLEAction extraAction, TransactionBuilder builder) {
- //use the new alert characteristic
- BluetoothGattCharacteristic alert = getSupport().getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL);
for (short i = 0; i < vibrationProfile.getRepeat(); i++) {
int[] onOffSequence = vibrationProfile.getOnOffSequence();
for (int j = 0; j < onOffSequence.length; j++) {
int on = onOffSequence[j];
on = Math.min(500, on); // longer than 500ms is not possible
- builder.write(alert, new byte[]{(byte) vibrationProfile.getAlertLevel()});
+ startNotify(builder, vibrationProfile.getAlertLevel(), simpleNotification);
builder.wait(on);
- builder.write(alert, new byte[]{GattCharacteristic.NO_ALERT});
+ stopNotify(builder);
if (++j < onOffSequence.length) {
int off = Math.max(onOffSequence[j], 25); // wait at least 25ms
@@ -56,12 +56,19 @@ public class Mi2NotificationStrategy extends V2NotificationStrategy {
}
}
}
+ }
- sendAlert(simpleNotification, builder);
+ protected void startNotify(TransactionBuilder builder, int alertLevel, @Nullable SimpleNotification simpleNotification) {
+ builder.write(alertLevelCharacteristic, new byte[] {(byte) alertLevel});
+
+ }
+
+ protected void stopNotify(TransactionBuilder builder) {
+ builder.write(alertLevelCharacteristic, new byte[]{GattCharacteristic.NO_ALERT});
}
@Override
- public void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
+ public void sendCustomNotification(VibrationProfile vibrationProfile, @Nullable SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
// all other parameters are unfortunately not supported anymore ;-(
sendCustomNotification(vibrationProfile, simpleNotification, extraAction, builder);
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2TextNotificationStrategy.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2TextNotificationStrategy.java
new file mode 100644
index 000000000..416da22d5
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2TextNotificationStrategy.java
@@ -0,0 +1,90 @@
+/* Copyright (C) 2017 Carsten Pfeiffer
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2;
+
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service;
+import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
+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.btle.profiles.alertnotification.OverflowStrategy;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
+import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
+
+public class Mi2TextNotificationStrategy extends Mi2NotificationStrategy {
+ private final BluetoothGattCharacteristic newAlertCharacteristic;
+
+ public Mi2TextNotificationStrategy(MiBand2Support support) {
+ super(support);
+ newAlertCharacteristic = support.getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_NEW_ALERT);
+ }
+
+ @Override
+ 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;
+ }
+
+ // announce text messages with configured alerts first
+ super.sendCustomNotification(vibrationProfile, simpleNotification, extraAction, builder);
+ // and finally send the text message, if any
+ if (simpleNotification != null && !StringUtils.isEmpty(simpleNotification.getMessage())) {
+ sendAlert(simpleNotification, builder);
+ }
+ }
+
+ @Override
+ protected void startNotify(TransactionBuilder builder, int alertLevel, SimpleNotification simpleNotification) {
+ builder.write(newAlertCharacteristic, getNotifyMessage(simpleNotification));
+ }
+
+ protected byte[] getNotifyMessage(SimpleNotification simpleNotification) {
+ int numAlerts = 1;
+ if (simpleNotification != null) {
+ switch (simpleNotification.getAlertCategory()) {
+ case Email:
+ return new byte[] { BLETypeConversions.fromUint8(MiBand2Service.ALERT_LEVEL_MESSAGE), BLETypeConversions.fromUint8(numAlerts)};
+ case InstantMessage:
+ return new byte[] { BLETypeConversions.fromUint8(MiBand2Service.ALERT_LEVEL_CUSTOM), BLETypeConversions.fromUint8(numAlerts), MiBand2Service.ICON_CHAT};
+ case News:
+ return new byte[] { BLETypeConversions.fromUint8(MiBand2Service.ALERT_LEVEL_CUSTOM), BLETypeConversions.fromUint8(numAlerts), MiBand2Service.ICON_PENGUIN};
+ }
+ }
+ return new byte[] { BLETypeConversions.fromUint8(AlertCategory.SMS.getId()), BLETypeConversions.fromUint8(numAlerts)};
+ }
+
+ protected void sendAlert(@NonNull SimpleNotification simpleNotification, TransactionBuilder builder) {
+ AlertNotificationProfile> profile = new AlertNotificationProfile<>(getSupport());
+ // override the alert category, since only SMS and incoming call support text notification
+ AlertCategory category = AlertCategory.SMS;
+ if (simpleNotification.getAlertCategory() == AlertCategory.IncomingCall) {
+ category = simpleNotification.getAlertCategory();
+ }
+ NewAlert alert = new NewAlert(category, 1, simpleNotification.getMessage());
+ profile.newAlert(builder, alert, OverflowStrategy.MAKE_MULTIPLE);
+ }
+}
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 8b8a04ce3..9ef66da91 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
@@ -84,6 +84,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
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.btle.profiles.deviceinfo.DeviceInfoProfile;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRateProfile;
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
@@ -96,6 +99,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.U
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
+import nodomain.freeyourgadget.gadgetbridge.util.Version;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_FLASH_COLOUR;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_FLASH_COUNT;
@@ -301,6 +305,16 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
}
private NotificationStrategy getNotificationStrategy() {
+ String firmwareVersion = getDevice().getFirmwareVersion();
+ if (firmwareVersion != null) {
+ Version ver = new Version(firmwareVersion);
+ if (MiBandConst.MI2_FW_VERSION_MIN_TEXT_NOTIFICATIONS.compareTo(ver) > 0) {
+ return new Mi2NotificationStrategy(this);
+ }
+ }
+ if (GBApplication.getPrefs().getBoolean(MiBandConst.PREF_MI2_ENABLE_TEXT_NOTIFICATIONS, true)) {
+ return new Mi2TextNotificationStrategy(this);
+ }
return new Mi2NotificationStrategy(this);
}
@@ -440,6 +454,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
int flashDuration = getPreferredFlashDuration(notificationOrigin, prefs);
sendCustomNotification(profile, simpleNotification, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
+
// sendCustomNotification(vibrateDuration, vibrateTimes, vibratePause, flashTimes, flashColour, originalColour, flashDuration, builder);
builder.queue(getQueue());
} catch (IOException ex) {
@@ -563,6 +578,17 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
performPreferredNotification("incoming call", MiBandConst.ORIGIN_INCOMING_CALL, simpleNotification, MiBand2Service.ALERT_LEVEL_PHONE_CALL, abortAction);
} else if ((callSpec.command == CallSpec.CALL_START) || (callSpec.command == CallSpec.CALL_END)) {
telephoneRinging = false;
+ stopCurrentNotification();
+ }
+ }
+
+ private void stopCurrentNotification() {
+ try {
+ TransactionBuilder builder = performInitialized("stop notification");
+ getNotificationStrategy().stopCurrentNotification(builder);
+ builder.queue(getQueue());
+ } catch (IOException e) {
+ LOG.error("Error stopping notification");
}
}
@@ -642,7 +668,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
return !isLocatingDevice;
}
};
- SimpleNotification simpleNotification = new SimpleNotification(getContext().getString(R.string.find_device_you_found_it), AlertCategory.HighPriorityAlert.HighPriorityAlert);
+ SimpleNotification simpleNotification = new SimpleNotification(getContext().getString(R.string.find_device_you_found_it), AlertCategory.HighPriorityAlert);
performDefaultNotification("locating device", simpleNotification, (short) 255, abortAction);
}
}
@@ -974,6 +1000,9 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
versionCmd.hwVersion = info.getHardwareRevision();
// versionCmd.fwVersion = info.getFirmwareRevision(); // always null
versionCmd.fwVersion = info.getSoftwareRevision();
+ if (versionCmd.fwVersion != null && versionCmd.fwVersion.length() > 0 && versionCmd.fwVersion.charAt(0) == 'V') {
+ versionCmd.fwVersion = versionCmd.fwVersion.substring(1);
+ }
handleGBDeviceEvent(versionCmd);
}
@@ -1044,11 +1073,12 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
@Override
public void onTestNewFunction() {
try {
- performInitialized("read characteristic 10")
- .read(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_10_BUTTON))
- .queue(getQueue());
+ TransactionBuilder builder = performInitialized("incoming call from peter");
+ NewAlert alert = new NewAlert(AlertCategory.Custom, 1, new String(new byte[] {0x19}));
+ AlertNotificationProfile profile = new AlertNotificationProfile<>(this);
+ profile.newAlert(builder, alert, OverflowStrategy.MAKE_MULTIPLE);
+ builder.queue(getQueue());
} catch (IOException e) {
- e.printStackTrace();
}
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java
index b0a8030e6..e7679301f 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java
@@ -16,6 +16,13 @@
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.util;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
public class CheckSums {
public static int getCRC8(byte[] seq) {
int len = seq.length;
@@ -51,4 +58,31 @@ public class CheckSums {
crc &= 0xffff;
return crc;
}
+
+ public static void main(String[] args) throws IOException {
+ if (args == null || args.length == 0) {
+ throw new IllegalArgumentException("Pass the files to be checksummed as arguments");
+ }
+ for (String name : args) {
+ try (FileInputStream in = new FileInputStream(name)) {
+ byte[] bytes = readAll(in, 1000 * 1000);
+ System.out.println(name + " : " + getCRC16(bytes));
+ }
+ }
+ }
+
+ public static byte[] readAll(InputStream in, long maxLen) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(8192, in.available()));
+ byte[] buf = new byte[8192];
+ int read = 0;
+ long totalRead = 0;
+ while ((read = in.read(buf)) > 0) {
+ out.write(buf, 0, read);
+ totalRead += read;
+ if (totalRead > maxLen) {
+ throw new IOException("Too much data to read into memory. Got already " + totalRead + buf);
+ }
+ }
+ return out.toByteArray();
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/NotificationUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/NotificationUtils.java
index 2623866b2..7e7b8df02 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/NotificationUtils.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/NotificationUtils.java
@@ -19,6 +19,7 @@ package nodomain.freeyourgadget.gadgetbridge.util;
import android.content.Context;
import android.support.annotation.NonNull;
+import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
@@ -47,13 +48,22 @@ public class NotificationUtils {
}
@NonNull
- public static String formatText(String sender, String subject, String body, int lengthBody, int lengthSubject, Context context) {
- StringBuilder builder = new StringBuilder();
- builder.append(StringUtils.truncate(body, lengthBody));
- builder.append(StringUtils.truncate(subject, lengthSubject));
- builder.append(StringUtils.formatSender(sender, context));
+ public static String formatSender(String sender, Context context) {
+ if (sender == null || sender.length() == 0) {
+ return "";
+ }
+ return context.getString(R.string.StringUtils_sender, sender);
+ }
- return builder.toString();
+
+ @NonNull
+ public static String formatText(String sender, String subject, String body, int lengthBody, int lengthSubject, Context context) {
+ String fBody = StringUtils.truncate(body, lengthBody);
+ String fSubject = StringUtils.truncate(subject, lengthSubject);
+ String fSender = formatSender(sender, context);
+
+ StringBuilder builder = StringUtils.join(" ", fBody, fSubject, fSender);
+ return builder.toString().trim();
}
public static String getPreferredTextFor(CallSpec callSpec) {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/StringUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/StringUtils.java
index 1ebe8ee3c..0a9eaae20 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/StringUtils.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/StringUtils.java
@@ -16,11 +16,8 @@
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.util;
-import android.content.Context;
import android.support.annotation.NonNull;
-import nodomain.freeyourgadget.gadgetbridge.R;
-
public class StringUtils {
public static String truncate(String s, int maxLength){
@@ -47,12 +44,31 @@ public class StringUtils {
return s;
}
+ /**
+ * Joins the given elements and adds a separator between each element in the resulting string.
+ * There will be no separator at the start or end of the string. There will be no consecutive
+ * separators (even in case an element is null or empty).
+ * @param separator the separator string
+ * @param elements the elements to concatenate to a new string
+ * @return the joined strings, separated by the separator
+ */
@NonNull
- public static String formatSender(String sender, Context context) {
- if (sender == null || sender.length() == 0) {
- return "";
+ public static StringBuilder join(String separator, String... elements) {
+ StringBuilder builder = new StringBuilder();
+ if (elements == null) {
+ return builder;
}
- return context.getString(R.string.StringUtils_sender, sender);
+ boolean hasAdded = false;
+ for (String element : elements) {
+ if (element != null && element.length() > 0) {
+ if (hasAdded) {
+ builder.append(separator);
+ }
+ builder.append(element);
+ hasAdded = true;
+ }
+ }
+ return builder;
}
@NonNull
@@ -65,4 +81,15 @@ public class StringUtils {
}
return "";
}
+
+ public static boolean isEmpty(String string) {
+ return string != null && string.length() == 0;
+ }
+
+ public static String ensureNotNull(String message) {
+ if (message != null) {
+ return message;
+ }
+ return "";
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/Version.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/Version.java
new file mode 100644
index 000000000..c1db22ec3
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/Version.java
@@ -0,0 +1,64 @@
+/* Copyright (C) 2017 Carsten Pfeiffer
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.util;
+
+// http://stackoverflow.com/questions/198431/how-do-you-compare-two-version-strings-in-java
+public class Version implements Comparable {
+
+ private String version;
+
+ public final String get() {
+ return this.version;
+ }
+
+ public Version(String version) {
+ if(version == null)
+ throw new IllegalArgumentException("Version can not be null");
+ if(!version.matches("[0-9]+(\\.[0-9]+)*"))
+ throw new IllegalArgumentException("Invalid version format");
+ this.version = version;
+ }
+
+ @Override public int compareTo(Version that) {
+ if(that == null)
+ return 1;
+ String[] thisParts = this.get().split("\\.");
+ String[] thatParts = that.get().split("\\.");
+ int length = Math.max(thisParts.length, thatParts.length);
+ for(int i = 0; i < length; i++) {
+ int thisPart = i < thisParts.length ?
+ Integer.parseInt(thisParts[i]) : 0;
+ int thatPart = i < thatParts.length ?
+ Integer.parseInt(thatParts[i]) : 0;
+ if(thisPart < thatPart)
+ return -1;
+ if(thisPart > thatPart)
+ return 1;
+ }
+ return 0;
+ }
+
+ @Override public boolean equals(Object that) {
+ if(this == that)
+ return true;
+ if(that == null)
+ return false;
+ if(this.getClass() != that.getClass())
+ return false;
+ return this.compareTo((Version) that) == 0;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_action_find_lost_device.xml b/app/src/main/res/drawable/ic_action_find_lost_device.xml
index 74f549430..84be5602b 100644
--- a/app/src/main/res/drawable/ic_action_find_lost_device.xml
+++ b/app/src/main/res/drawable/ic_action_find_lost_device.xml
@@ -1,9 +1,10 @@
+
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ android:fillColor="#000"
+ android:pathData="M3,17V7H5V17H3M19,17V7H21V17H19M22,9H24V15H22V9M0,15V9H2V15H0M17.96,11.97C17.96,13.87 17.07,15.57 15.68,16.67L14.97,20.95H9L8.27,16.67C6.88,15.57 6,13.87 6,11.97C6,10.07 6.88,8.37 8.27,7.28L9,3H14.97L15.68,7.28C17.07,8.37 17.96,10.07 17.96,11.97M7.5,11.97C7.5,14.45 9.5,16.46 11.97,16.46A4.5,4.5 0 0,0 16.46,11.97C16.46,9.5 14.45,7.5 11.97,7.5A4.47,4.47 0 0,0 7.5,11.97Z" />
diff --git a/app/src/main/res/layout/device_itemv2.xml b/app/src/main/res/layout/device_itemv2.xml
index b2911ac86..a8979189d 100644
--- a/app/src/main/res/layout/device_itemv2.xml
+++ b/app/src/main/res/layout/device_itemv2.xml
@@ -15,20 +15,19 @@
card_view:cardElevation="4dp"
card_view:contentPadding="8dp">
-
+ android:visibility="gone">
+ android:layout_marginTop="8dp" />
+ tools:text="My Pebble Watch" />
+ android:background="?android:attr/selectableItemBackground"
+ card_view:srcCompat="@drawable/ic_more_vert" />
+ android:orientation="vertical">
+ android:orientation="vertical">
+ card_view:srcCompat="@drawable/ic_activity_graphs"
+ android:background="?android:attr/selectableItemBackground"
+ android:contentDescription="@string/controlcenter_start_activitymonitor" />
-
+
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 242ce8ccf..72c4a6596 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -13,6 +13,12 @@
Gerät löschen
%1$s löschen
Das wird das Gerät und alle zugehörigen Daten löschen!
+ Navigations-Menü öffnen
+ Navigations-Menü schließen
+ Halte die Karte lange gedrückt, um die Verbindung zu trennen.
+ Trenne ...
+ Verbinde ...
+ Screenshot des Gerätes wird erstellt.
Debug
App Manager
@@ -181,6 +187,7 @@
Keine gültigen Benutzerinformationen angegeben, verwende Dummy-Daten für\'s Erste.
Wenn Dein Mi Band vibriert und blinkt, tippe ein paar Mal schnell hintereinander darauf.
Installieren
+ Mache dein Gerät auffindbar. Derzeit verbundene Geräte werden wahrscheinlich nicht erkannt. Aktiviere die Standortbestimmung (zum Beispiel GPS) in Android 6+. Deaktiviere den Privatsphäreschutz für Gadgetbridge, da er zu Abstürzen und Neustarts deines Telefons führen kann. Wenn nach einigen Minuten kein Gerät erkannt wird, versuche es nach einem Neustart deines Telefons erneut.
Tipp:
Bild des Geräts
Name/Alias
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 6e4405ba3..d7b8e2425 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -13,6 +13,12 @@
Borrar Dispositivo
Borrar %1$s
¡Esta acción borrará el dispositivo y toda su información asociada!
+ Abrir el cajón de navegación
+ Cerrar el cajón de navegación
+ Mantener pulsado el icono para desconectar
+ Desconectando
+ Conectando
+ Captura de pantalla del dispositivo
Depuración
Gestor de app
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 84992fdc2..634fc00cf 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -13,6 +13,12 @@
Supprimer l’appareil
Supprimer %1$s
Ceci va supprimer l’appareil et toutes les données associées !
+ Ouvrir le tiroir de navigation
+ Fermer le tiroir de navigation
+ Presser longuement l\'icône pour déconnecter
+ Déconnexion
+ Connexion
+ Capture d\'écran de l\'appareil
Déboguer
Gestionnaire d\'application
diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml
index a04c9706c..ff2299501 100644
--- a/app/src/main/res/values-he/strings.xml
+++ b/app/src/main/res/values-he/strings.xml
@@ -181,6 +181,7 @@
לא ניתנו נתוני משתמש, נעשה שימוש בנתוני דמה לבינתיים.
כאשר ה־Mi Band שלך רוטט ומהבהב, יש לגעת בו מספר פעמים ברצף.
התקנה
+ יש להפעיל את האפשרות לאיתור ההתקן שלך. התקנים שכבר מחוברים כעת לא יתגלו. יש להפעיל מיקום (GPS) באנדרואיד 6+. יש לנטרל את שומר הפרטיות עבור Gadgetbridge כיוון שתכונה זו עשויה להקריס ולהפעיל מחדש את הטלפון שלך. אם לא נמצא אף התקן לאחר מספר דקות יש לנסות שוב לאחר הפעלת הטלפון הנייד שלך מחדש.
לתשומת לבך:
תמונת ההתקן
שם/כינוי
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 93d322fe6..6367a6d15 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -13,6 +13,8 @@
Rimuovi dispositivo
Rimuovi %1$s
Il dispositivo verrà rimosso e tutti i dati ad esso associati verranno cancellati!
+ Disconnessione
+ Connessione
Debug
Gestione app
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 3bc4b752f..ddf2c425f 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -13,6 +13,12 @@
デバイスを削除
%1$s を削除
これにより、デバイスと関連するデータを削除します!
+ ナビゲーションドロワーを開く
+ ナビゲーションドロワーを閉じる
+ カードを長押しすると切断します
+ 切断中
+ 接続中
+ デバイスのスクリーンショットを取得中
デバッグ
アプリ管理画面
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 88685f63d..0bac667b8 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -158,12 +158,14 @@
- @string/pref_call_privacy_mode_off
- @string/pref_call_privacy_mode_name
+ - @string/pref_call_privacy_mode_number
- @string/pref_call_privacy_mode_complete
- @string/p_call_privacy_mode_off
- @string/p_call_privacy_mode_name
+ - @string/pref_call_privacy_mode_number
- @string/p_call_privacy_mode_complete
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ee631139a..95696d636 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -99,8 +99,10 @@
Call Privacy Mode
Display name and number
Hide name but display number
+ Hide number but display name
Hide name and number
+
Blacklist Apps
Canned Messages
@@ -407,4 +409,8 @@
(%1$s)
You found it!
Mi2: Time Format
+ You need to install version %1$s before installing this firmware!
+ Text notifications
+ = 1.0.1.28 and Mili_pro.ft* installed.]]>
+ off
diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml
index d8314326c..954f33d1b 100644
--- a/app/src/main/res/xml/changelog_master.xml
+++ b/app/src/main/res/xml/changelog_master.xml
@@ -10,6 +10,11 @@
Huge speedup for weekly charts when changing days
Drop support for pre Gadgetbride 0.12.0 database
Pebble: allow configuration webpages (clay) to access device location
+ Mi2: Initial support for text notifications, caller ID, and icons (requires font installation) (#560)
+ Mi2: Support for flashing Mili_pro.ft* font files
+ Mi2: Improved firmware/font updated
+ Mi2: Set 12h/24h time format, following the Android configuration (#573)
+ Improved BLE discovery and connectivity
Automatically start the service on boot (can be turned off)
diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml
index 1c8856822..e1bbb2f9c 100644
--- a/app/src/main/res/xml/miband_preferences.xml
+++ b/app/src/main/res/xml/miband_preferences.xml
@@ -48,6 +48,13 @@
android:key="mi2_activate_display_on_lift_wrist"
android:title="@string/mi2_prefs_activate_display_on_lift" />
+
+