From cbc57b4407ee5302605132857bc2166d94e42e1c Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 28 Mar 2016 23:44:39 +0200 Subject: [PATCH 01/43] Pebble: Fix stupid bug that made Pebble Health unavailable in App Manager (Fixes #269) --- .../gadgetbridge/activities/AppManagerActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index e2a1d56d..6b566f3e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -80,7 +80,7 @@ public class AppManagerActivity extends Activity { List systemApps = new ArrayList<>(); systemApps.add(new GBDeviceApp(UUID.fromString("4dab81a6-d2fc-458a-992c-7a1f3b96a970"), "Sports (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); systemApps.add(new GBDeviceApp(UUID.fromString("cf1e816a-9db0-4511-bbb8-f60c48ca8fac"), "Golf (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); - if (mGBDevice != null && !"aplite".equals(PebbleUtils.getPlatformName(mGBDevice.getFirmwareVersion()))) { + if (mGBDevice != null && !"aplite".equals(PebbleUtils.getPlatformName(mGBDevice.getHardwareVersion()))) { systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_PEBBLE_HEALTH, "Health (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); } From b3590fed358afed180f48d7faceb9677a0836952 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 28 Mar 2016 23:56:20 +0200 Subject: [PATCH 02/43] For simplicity hide some internal states from the user Display connecting->connected instead of connecting->connected->initializing->initialized --- .../freeyourgadget/gadgetbridge/impl/GBDevice.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java index 763e6375..1e46d978 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java @@ -53,7 +53,6 @@ public class GBDevice implements Parcelable { private BatteryState mBatteryState; private short mRssi = RSSI_UNKNOWN; private String mBusyTask; - private String infoString; private List mDeviceInfos; public GBDevice(String address, String name, DeviceType deviceType) { @@ -204,23 +203,25 @@ public class GBDevice implements Parcelable { } public String getStateString() { + /* + * for simplicity the user wont see all internal states, just connecting -> connected + * instead of connecting->connected->initializing->initialized + */ switch (mState) { case NOT_CONNECTED: return GBApplication.getContext().getString(R.string.not_connected); case WAITING_FOR_RECONNECT: return GBApplication.getContext().getString(R.string.waiting_for_reconnect); case CONNECTING: - return GBApplication.getContext().getString(R.string.connecting); case CONNECTED: - return GBApplication.getContext().getString(R.string.connected); case INITIALIZING: - return GBApplication.getContext().getString(R.string.initializing); + return GBApplication.getContext().getString(R.string.connecting); case AUTHENTICATION_REQUIRED: return GBApplication.getContext().getString(R.string.authentication_required); case AUTHENTICATING: return GBApplication.getContext().getString(R.string.authenticating); case INITIALIZED: - return GBApplication.getContext().getString(R.string.initialized); + return GBApplication.getContext().getString(R.string.connected); } return GBApplication.getContext().getString(R.string.unknown_state); } From 834a727a39ec5d083866a9a59ae5e31361540171 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 29 Mar 2016 00:05:29 +0200 Subject: [PATCH 03/43] update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c5bc3d5..7986a69b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ###Changelog +####Version 0.9.3 (next) +* Pebble: Fix Pebble Health activation (was not available in the App Manager) +* Simplify connection state display (only connecting->connected) +* Small improvements to the pairing activity + ####Version 0.9.2 * Mi Band: Fix update of second (HR) firmware on Mi1S (#234) * Fix ordering issue of device infos being displayed From e931cf47d71da2c898054426525cd4e730fcc790 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Tue, 29 Mar 2016 22:13:15 +0200 Subject: [PATCH 04/43] Need to pass '0' as parameter to mi band fw metadata info #234 --- .../devices/miband/operations/UpdateFirmwareOperation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java index 3acff6e6..710f4a34 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java @@ -193,7 +193,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { } else { LOG.info("is multi Mi Band firmware, sending fw2 (hr) first"); byte[] fw2Info = prepareFirmwareInfo(fw2Bytes, fw2OldVersion, fw2Version, fw2Checksum, 1, rebootWhenFinished /*, progress monitor */); - byte[] fw1Info = prepareFirmwareInfo(fw1Bytes, fw1OldVersion, fw1Version, fw1Checksum, 1, rebootWhenFinished /*, progress monitor */); + byte[] fw1Info = prepareFirmwareInfo(fw1Bytes, fw1OldVersion, fw1Version, fw1Checksum, 0, rebootWhenFinished /*, progress monitor */); return new DoubleUpdateCoordinator(fw1Info, fw1Bytes, fw2Info, fw2Bytes, rebootWhenFinished); } } From f8c761068e99ad321e6cbb5b1cdca9253eff1481 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Tue, 29 Mar 2016 22:41:21 +0200 Subject: [PATCH 05/43] Updated for 0.9.3 --- CHANGELOG.md | 3 ++- app/build.gradle | 4 ++-- app/src/main/res/xml/changelog_master.xml | 6 ++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7986a69b..c691eebf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ ###Changelog -####Version 0.9.3 (next) +####Version 0.9.3 * Pebble: Fix Pebble Health activation (was not available in the App Manager) * Simplify connection state display (only connecting->connected) * Small improvements to the pairing activity +* Mi Band 1S: Fix for mi band firmware update ####Version 0.9.2 * Mi Band: Fix update of second (HR) firmware on Mi1S (#234) diff --git a/app/build.gradle b/app/build.gradle index accb84ae..a1f7b997 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { targetSdkVersion 23 // note: always bump BOTH versionCode and versionName! - versionName "0.9.2" - versionCode 46 + versionName "0.9.3" + versionCode 47 } buildTypes { release { diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 608a543c..0c25965e 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,5 +1,11 @@ + + Pebble: Fix Pebble Health activation (was not available in the App Manager) + Simplify connection state display (only connecting->connected) + Small improvements to the pairing activity + Mi Band 1S: Fix for mi band firmware update + Mi Band: Fix update of second (HR) firmware on Mi1S (#234) Fix ordering issue of device infos being displayed From 5f72daa43a2f628c94ba192ddf3231b014fffd2f Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Tue, 29 Mar 2016 22:59:22 +0200 Subject: [PATCH 06/43] Add SVG launcher icon, closes #190 THANKS! --- app/src/main/res/drawable/ic_launcher.svg | 149 ++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 app/src/main/res/drawable/ic_launcher.svg diff --git a/app/src/main/res/drawable/ic_launcher.svg b/app/src/main/res/drawable/ic_launcher.svg new file mode 100644 index 00000000..03b47994 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + From cc7f5406efa1f24d5ca97267653ab1f1296e617a Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 30 Mar 2016 21:48:42 +0200 Subject: [PATCH 07/43] Use low latency transfer mode for fw update #234 --- .../gadgetbridge/service/btle/AbstractBTLEOperation.java | 4 ++++ .../devices/miband/operations/UpdateFirmwareOperation.java | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java index b7a7e938..258199ad 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java @@ -113,6 +113,10 @@ public abstract class AbstractBTLEOperation return operationStatus == OperationStatus.RUNNING; } + public boolean isOperationFinished() { + return operationStatus == OperationStatus.FINISHED; + } + public T getSupport() { return mSupport; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java index 710f4a34..c953e663 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java @@ -60,6 +60,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { } private void done() { + LOG.info("Operation done."); updateCoordinator = null; operationFinished(); unsetBusy(); @@ -273,6 +274,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { try { TransactionBuilder builder = performInitialized("send firmware packet"); + getSupport().setLowLatency(builder); for (int i = 0; i < packets; i++) { byte[] fwChunk = Arrays.copyOfRange(fwbytes, i * packetLength, i * packetLength + packetLength); @@ -319,6 +321,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { public boolean sendFwInfo() { try { TransactionBuilder builder = performInitialized("send firmware info"); + getSupport().setLowLatency(builder); builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.updating_firmware), getContext())); builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), getFirmwareInfo()); builder.add(new FirmwareInfoSucceededAction()); @@ -440,7 +443,9 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { private class FirmwareInfoSucceededAction extends PlainAction { @Override public boolean run(BluetoothGatt gatt) { - firmwareInfoSent = true; + if (isOperationRunning()) { + firmwareInfoSent = true; + } return true; } } From ffc006c21cddc86b7f1df472c56845a781ffa583 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 30 Mar 2016 21:56:00 +0200 Subject: [PATCH 08/43] Fix ordering problem with firmwareInfoSent state variable #234 --- .../devices/miband/operations/UpdateFirmwareOperation.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java index c953e663..35072d56 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java @@ -323,8 +323,8 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { TransactionBuilder builder = performInitialized("send firmware info"); getSupport().setLowLatency(builder); builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.updating_firmware), getContext())); + builder.add(new FirmwareInfoSentAction()); // Note: *before* actually sending the info, otherwise it's too late! builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), getFirmwareInfo()); - builder.add(new FirmwareInfoSucceededAction()); builder.queue(getQueue()); return true; } catch (IOException e) { @@ -440,7 +440,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { } } - private class FirmwareInfoSucceededAction extends PlainAction { + private class FirmwareInfoSentAction extends PlainAction { @Override public boolean run(BluetoothGatt gatt) { if (isOperationRunning()) { From 776a7432854c17f7be3ebb50d8e901c748bbc806 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 30 Mar 2016 22:06:03 +0200 Subject: [PATCH 09/43] Move svg file to another place to fix build --- app/src/main/res/drawable/ic_launcher.svg | 149 ---------------------- 1 file changed, 149 deletions(-) delete mode 100644 app/src/main/res/drawable/ic_launcher.svg diff --git a/app/src/main/res/drawable/ic_launcher.svg b/app/src/main/res/drawable/ic_launcher.svg deleted file mode 100644 index 03b47994..00000000 --- a/app/src/main/res/drawable/ic_launcher.svg +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - From 4631df67ac27558f767c5da1dec473d28348b50e Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 30 Mar 2016 22:53:08 +0200 Subject: [PATCH 10/43] Some more logging + add svg launcher again (somehow it was not added again) --- app/src/main/assets/ic_launcher.svg | 149 ++++++++++++++++++ .../gadgetbridge/devices/InstallHandler.java | 2 +- .../operations/UpdateFirmwareOperation.java | 2 + 3 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 app/src/main/assets/ic_launcher.svg diff --git a/app/src/main/assets/ic_launcher.svg b/app/src/main/assets/ic_launcher.svg new file mode 100644 index 00000000..03b47994 --- /dev/null +++ b/app/src/main/assets/ic_launcher.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/InstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/InstallHandler.java index 1314dc0e..e83815e6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/InstallHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/InstallHandler.java @@ -28,7 +28,7 @@ public interface InstallHandler { void validateInstallation(InstallActivity installActivity, GBDevice device); /** - * Allows device specivic code to be execute just before the installation starts + * Allows device specific code to be executed just before the installation starts */ void onStartInstall(GBDevice device); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java index 35072d56..87723639 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java @@ -107,6 +107,8 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { done(); } firmwareInfoSent = false; + } else { + LOG.warn("firmwareInfoSent is false -- not sending firmware data even though we got meta data success notification"); } break; case MiBandService.NOTIFY_FW_CHECK_FAILED: From 66c1b3f178080fcb475e02f9953ea55462a8b9d1 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 31 Mar 2016 21:39:51 +0200 Subject: [PATCH 11/43] Relax check for Mi1S device detection #234 --- .../gadgetbridge/service/devices/miband/DeviceInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java index 21798878..1072ff50 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java @@ -109,7 +109,7 @@ public class DeviceInfo extends AbstractInfo { public boolean isMili1S() { // TODO: this is probably not quite correct, but hopefully sufficient for early 1S support - return feature == 4 && appearance == 0 || feature == 4 && hwVersion == 4; + return (feature == 4 && appearance == 0) || hwVersion == 4; } public String getHwVersion() { From 6f97b8c1e507e3e6391c951ffe5738846bd33133 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 31 Mar 2016 21:54:09 +0200 Subject: [PATCH 12/43] Log the date that we receive from the Mi Band --- .../gadgetbridge/service/devices/miband/MiBandSupport.java | 7 +++++++ 1 file changed, 7 insertions(+) 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 733b89ac..e1656924 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 @@ -725,6 +725,8 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { handleBatteryInfo(characteristic.getValue(), status); } else if (MiBandService.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT.equals(characteristicUUID)) { logHeartrate(characteristic.getValue()); + } else if (MiBandService.UUID_CHARACTERISTIC_DATE_TIME.equals(characteristicUUID)) { + logDate(characteristic.getValue()); } else { LOG.info("Unhandled characteristic read: " + characteristicUUID); logMessageContent(characteristic.getValue()); @@ -756,6 +758,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } } + public void logDate(byte[] value) { + GregorianCalendar calendar = MiBandDateConverter.rawBytesToCalendar(value); + LOG.info("Got Mi Band Date: " + DateTimeUtils.formatDateTime(calendar.getTime())); + } + public void logHeartrate(byte[] value) { LOG.info("Got heartrate:"); if (value.length == 2 && value[0] == 6) { From ea5c6a0848f231129428a1802f9c5e1453cca953 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 31 Mar 2016 21:57:36 +0200 Subject: [PATCH 13/43] Log ignored notifications when updateCoordinator is null --- .../devices/miband/operations/UpdateFirmwareOperation.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java index 87723639..0d8e26ec 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java @@ -94,7 +94,8 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { return; } if (updateCoordinator == null) { - LOG.error("received notification when updateCoordinator is null, ignoring!"); + LOG.error("received notification when updateCoordinator is null, ignoring (notification content follows):"); + getSupport().logMessageContent(value); return; } From 72258c178ca7e246b29824b39cd862b7d32fd6f0 Mon Sep 17 00:00:00 2001 From: Christian Fischer Date: Sat, 2 Apr 2016 16:08:36 +0200 Subject: [PATCH 14/43] fix in string represantation conversion --- .../gadgetbridge/activities/AbstractSettingsActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java index d12fee96..4d3c48a1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java @@ -33,7 +33,7 @@ public abstract class AbstractSettingsActivity extends PreferenceActivity { } public void updateSummary(Preference preference, Object value) { - String stringValue = value.toString(); + String stringValue = String.valueOf(value); if (preference instanceof ListPreference) { // For list preferences, look up the correct display value in From 20aa7d9ad9cbe64c206b32369039e56470510a92 Mon Sep 17 00:00:00 2001 From: Christian Fischer Date: Sat, 2 Apr 2016 16:09:30 +0200 Subject: [PATCH 15/43] add preference to set hartrate sleep detection --- .../devices/miband/MiBandConst.java | 2 ++ .../devices/miband/MiBandCoordinator.java | 5 ++++ .../miband/MiBandPreferencesActivity.java | 2 ++ .../service/devices/miband/MiBandSupport.java | 25 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/miband_preferences.xml | 4 +++ 6 files changed, 40 insertions(+) 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 6f3aa77f..f3cc3182 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 @@ -15,6 +15,8 @@ public final class MiBandConst { public static final String PREF_MIBAND_FITNESS_GOAL = "mi_fitness_goal"; public static final String PREF_MIBAND_DONT_ACK_TRANSFER = "mi_dont_ack_transfer"; public static final String PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR = "mi_reserve_alarm_calendar"; + public static final String PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION = "mi_hr_sleep_detection"; + public static final String ORIGIN_SMS = "sms"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java index 3ecf4c65..86ea9330 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java @@ -135,6 +135,11 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator { return location; } + public static boolean getHeartrateSleepSupport(String miBandAddress) throws IllegalArgumentException { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); + return prefs.getBoolean(MiBandConst.PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION, false); + } + public static int getFitnessGoal(String miBandAddress) throws IllegalArgumentException { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); return Integer.parseInt(prefs.getString(MiBandConst.PREF_MIBAND_FITNESS_GOAL, "10000")); 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 3cb8343f..76cca5cb 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 @@ -18,6 +18,7 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PR import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_DONT_ACK_TRANSFER; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_FITNESS_GOAL; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_WEARSIDE; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_USER_ALIAS; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.VIBRATION_COUNT; @@ -54,6 +55,7 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity { PREF_MIBAND_FITNESS_GOAL, PREF_MIBAND_DONT_ACK_TRANSFER, PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, + PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION, getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_SMS), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_SMS), getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_INCOMING_CALL), diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index 733b89ac..a72e23db 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 @@ -109,6 +109,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { .sendUserInfo(builder) .checkAuthenticationNeeded(builder, getDevice()) .setWearLocation(builder) + .setHeartrateSleepSupport(builder) .setFitnessGoal(builder) .enableFurtherNotifications(builder, true) .setCurrentTime(builder) @@ -368,6 +369,30 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { return this; } + /** + * Part of device initialization process. Do not call manually. + * + * @param transaction + * @return + */ + private MiBandSupport setHeartrateSleepSupport(TransactionBuilder transaction) { + LOG.info("Attempting to set heartrate sleep support..."); + BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT); + if (characteristic != null) { + if(MiBandCoordinator.getHeartrateSleepSupport(getDevice().getAddress())) { + LOG.info("Enabling heartrate sleep support..."); + transaction.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementSleep); + } + else { + LOG.info("Disabling heartrate sleep support..."); + transaction.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementSleep); + } + } else { + LOG.info("Unable to set Wear Location"); + } + return this; + } + private void performDefaultNotification(String task, short repeat, BtLEAction extraAction) { try { TransactionBuilder builder = performInitialized(task); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3bcbddd8..5c06b5a5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -213,6 +213,8 @@ Incompatible firmware This firmware is not compatible with the device Alarms to reserve for upcoming events + Use Heartrate Sensor to improve sleep detection + waiting for reconnect Reinstall diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index 65997e95..042cd8e1 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -30,6 +30,10 @@ android:maxLength="1" android:digits="0123" android:title="@string/miband_prefs_reserve_alarm_calendar" /> + Date: Sat, 2 Apr 2016 16:11:51 +0200 Subject: [PATCH 16/43] test if heartrate is supported before writing preferences --- .../service/devices/miband/MiBandSupport.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) 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 a72e23db..a3367180 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 @@ -376,20 +376,24 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { * @return */ private MiBandSupport setHeartrateSleepSupport(TransactionBuilder transaction) { - LOG.info("Attempting to set heartrate sleep support..."); - BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT); - if (characteristic != null) { - if(MiBandCoordinator.getHeartrateSleepSupport(getDevice().getAddress())) { - LOG.info("Enabling heartrate sleep support..."); - transaction.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementSleep); + if (supportsHeartRate()) { + LOG.info("Attempting to set heartrate sleep support..."); + BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT); + if (characteristic != null) { + if(MiBandCoordinator.getHeartrateSleepSupport(getDevice().getAddress())) { + LOG.info("Enabling heartrate sleep support..."); + transaction.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementSleep); + } + else { + LOG.info("Disabling heartrate sleep support..."); + transaction.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementSleep); + } + } else { + LOG.info("Unable to set Heartrate sleep support"); } - else { - LOG.info("Disabling heartrate sleep support..."); - transaction.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementSleep); - } - } else { - LOG.info("Unable to set Wear Location"); - } + + } else + GB.toast(getContext(), "Heart rate is not supported on this device", Toast.LENGTH_LONG, GB.ERROR); return this; } From 0e495359663b84f87c63c976a1e0fd7d8443e5ff Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sat, 2 Apr 2016 22:24:33 +0200 Subject: [PATCH 17/43] Fix progress during fw update #234 --- .../devices/miband/operations/UpdateFirmwareOperation.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java index 0d8e26ec..59b042db 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java @@ -272,10 +272,11 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { final int packetLength = 20; int packets = len / packetLength; - // going from 0 to len - int firmwareProgress = 0; try { + // going from 0 to len + int firmwareProgress = 0; + TransactionBuilder builder = performInitialized("send firmware packet"); getSupport().setLowLatency(builder); for (int i = 0; i < packets; i++) { @@ -284,7 +285,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_FIRMWARE_DATA), fwChunk); firmwareProgress += packetLength; - int progressPercent = (int) (((float) firmwareProgress) / len) * 100; + int progressPercent = (int) ((((float) firmwareProgress) / len) * 100); if ((i > 0) && (i % 50 == 0)) { builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), new byte[]{MiBandService.COMMAND_SYNC}); builder.add(new SetProgressAction(getContext().getString(R.string.updatefirmwareoperation_update_in_progress), true, progressPercent, getContext())); From 2d10c11005c242646ab31aafa4dcb7776ce48471 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sat, 2 Apr 2016 22:35:37 +0200 Subject: [PATCH 18/43] Log the length of the bytes written --- .../gadgetbridge/service/devices/miband/MiBandSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e1656924..1210c108 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 @@ -896,7 +896,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { if (status != BluetoothGatt.GATT_SUCCESS) { LOG.warn("Could not write to the control point."); } - LOG.info("handleControlPoint write status:" + status); + LOG.info("handleControlPoint write status:" + status + "; length: " + (value != null ? value.length : "(null)")); if (value != null) { for (byte b : value) { From 7a224243a34c914ce4cb27e671d3e9bbf798e098 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 3 Apr 2016 00:49:54 +0200 Subject: [PATCH 19/43] Try to quit Gadgetbridge by stopping the service --- .../gadgetbridge/externalevents/NotificationListener.java | 5 +++++ 1 file changed, 5 insertions(+) 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 d4f6ed63..079f0132 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; @@ -54,6 +55,9 @@ public class NotificationListener extends NotificationListenerService { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); switch (action) { + case GBApplication.ACTION_QUIT: + stopSelf(); + break; case ACTION_MUTE: case ACTION_OPEN: { StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications(); @@ -130,6 +134,7 @@ public class NotificationListener extends NotificationListenerService { public void onCreate() { super.onCreate(); IntentFilter filterLocal = new IntentFilter(); + filterLocal.addAction(GBApplication.ACTION_QUIT); filterLocal.addAction(ACTION_OPEN); filterLocal.addAction(ACTION_DISMISS); filterLocal.addAction(ACTION_DISMISS_ALL); From a4919789ca21342358be58e8f440791a3a18655a Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 3 Apr 2016 00:50:45 +0200 Subject: [PATCH 20/43] Add some progress to firmware updating #271 #234 Also: remove the low latency mode for firmware update, because my Mi1S simply disconnects then. Still missing in the view: device disconnects --- .../activities/FwAppInstallerActivity.java | 46 ++++++++++++++++--- .../adapter/ItemWithDetailsAdapter.java | 21 ++++++++- .../GBDeviceEventDisplayMessage.java | 21 +++++++++ .../service/AbstractDeviceSupport.java | 12 +++++ .../operations/UpdateFirmwareOperation.java | 26 +++++++---- .../freeyourgadget/gadgetbridge/util/GB.java | 6 ++- .../main/res/layout/activity_appinstaller.xml | 8 ++++ .../res/layout/item_with_details_small.xml | 42 +++++++++++++++++ 8 files changed, 164 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventDisplayMessage.java create mode 100644 app/src/main/res/layout/item_with_details_small.xml 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 0c7b88cd..7f8d507f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java @@ -29,6 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.adapter.ItemWithDetailsAdapter; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.GenericItem; import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -37,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB; public class FwAppInstallerActivity extends Activity implements InstallActivity { private static final Logger LOG = LoggerFactory.getLogger(FwAppInstallerActivity.class); + private static final String ITEM_DETAILS = "details"; private TextView fwAppInstallTextView; private Button installButton; @@ -45,13 +47,22 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity private InstallHandler installHandler; private boolean mayConnect; + private ProgressBar mProgressBar; + private ListView itemListView; + private final List mItems = new ArrayList<>(); + private ItemWithDetailsAdapter mItemAdapter; + + private ListView detailsListView; + private ItemWithDetailsAdapter mDetailsItemAdapter; + private ArrayList mDetails = new ArrayList<>(); + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (action.equals(GBApplication.ACTION_QUIT)) { + if (GBApplication.ACTION_QUIT.equals(action)) { finish(); - } else if (action.equals(GBDevice.ACTION_DEVICE_CHANGED)) { + } else if (GBDevice.ACTION_DEVICE_CHANGED.equals(action)) { device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE); if (device != null) { refreshBusyState(device); @@ -67,13 +78,13 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity validateInstallation(); } } + } else if (GB.ACTION_DISPLAY_MESSAGE.equals(action)) { + String message = intent.getStringExtra(GB.DISPLAY_MESSAGE_MESSAGE); + int severity = intent.getIntExtra(GB.DISPLAY_MESSAGE_SEVERITY, GB.INFO); + addMessage(message, severity); } } }; - private ProgressBar mProgressBar; - private ListView itemListView; - private final List mItems = new ArrayList<>(); - private ItemWithDetailsAdapter mItemAdapter; private void refreshBusyState(GBDevice dev) { if (dev.isConnecting() || dev.isBusy()) { @@ -107,6 +118,13 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity if (dev != null) { device = dev; } + if (savedInstanceState != null) { + mDetails = savedInstanceState.getParcelableArrayList(ITEM_DETAILS); + if (mDetails == null) { + mDetails = new ArrayList<>(); + } + } + mayConnect = true; itemListView = (ListView) findViewById(R.id.itemListView); mItemAdapter = new ItemWithDetailsAdapter(this, mItems); @@ -114,10 +132,15 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity fwAppInstallTextView = (TextView) findViewById(R.id.infoTextView); installButton = (Button) findViewById(R.id.installButton); mProgressBar = (ProgressBar) findViewById(R.id.installProgressBar); + detailsListView = (ListView) findViewById(R.id.detailsListView); + mDetailsItemAdapter = new ItemWithDetailsAdapter(this, mDetails); + mDetailsItemAdapter.setSize(ItemWithDetailsAdapter.SIZE_SMALL); + detailsListView.setAdapter(mDetailsItemAdapter); setInstallEnabled(false); IntentFilter filter = new IntentFilter(); filter.addAction(GBApplication.ACTION_QUIT); filter.addAction(GBDevice.ACTION_DEVICE_CHANGED); + filter.addAction(GB.ACTION_DISPLAY_MESSAGE); LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter); installButton.setOnClickListener(new View.OnClickListener() { @@ -145,6 +168,12 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity } } + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelableArrayList(ITEM_DETAILS, mDetails); + } + private InstallHandler findInstallHandlerFor(Uri uri) { for (DeviceCoordinator coordinator : DeviceHelper.getInstance().getAllCoordinators()) { InstallHandler handler = coordinator.findInstallHandler(uri, this); @@ -195,4 +224,9 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity mItems.add(item); mItemAdapter.notifyDataSetChanged(); } + + private void addMessage(String message, int severity) { + mDetails.add(new GenericItem(message)); + mDetailsItemAdapter.notifyDataSetChanged(); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ItemWithDetailsAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ItemWithDetailsAdapter.java index 92448d9c..dcfee994 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ItemWithDetailsAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ItemWithDetailsAdapter.java @@ -18,8 +18,12 @@ import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails; */ public class ItemWithDetailsAdapter extends ArrayAdapter { + public static final int SIZE_SMALL = 1; + public static final int SIZE_MEDIUM = 2; + public static final int SIZE_LARGE = 3; private final Context context; private boolean horizontalAlignment; + private int size = SIZE_MEDIUM; public ItemWithDetailsAdapter(Context context, List items) { super(context, 0, items); @@ -42,7 +46,14 @@ public class ItemWithDetailsAdapter extends ArrayAdapter { if (horizontalAlignment) { view = inflater.inflate(R.layout.item_with_details_horizontal, parent, false); } else { - view = inflater.inflate(R.layout.item_with_details, parent, false); + switch (size) { + case SIZE_SMALL: + view = inflater.inflate(R.layout.item_with_details_small, parent, false); + break; + default: + view = inflater.inflate(R.layout.item_with_details, parent, false); + break; + } } } ImageView iconView = (ImageView) view.findViewById(R.id.item_image); @@ -55,4 +66,12 @@ public class ItemWithDetailsAdapter extends ArrayAdapter { return view; } + + public void setSize(int size) { + this.size = size; + } + + public int getSize() { + return size; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventDisplayMessage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventDisplayMessage.java new file mode 100644 index 00000000..33250737 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventDisplayMessage.java @@ -0,0 +1,21 @@ +package nodomain.freeyourgadget.gadgetbridge.deviceevents; + +public class GBDeviceEventDisplayMessage { + public String message; + public int duration; + public int severity; + + /** + * An event for displaying a message to the user. How the message is displayed + * is a detail of the current activity, which needs to listen to the Intent + * GB.ACTION_DISPLAY_MESSAGE. + * @param message + * @param duration + * @param severity + */ + public GBDeviceEventDisplayMessage(String message, int duration, int severity) { + this.message = message; + this.duration = duration; + this.severity = severity; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java index ad88c179..d33b9dd9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java @@ -1,5 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.service; +import android.app.Application; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -32,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventScreenshot; @@ -280,4 +282,14 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { gbDevice.sendDeviceUpdateIntent(context); } + public void handleGBDeviceEvent(GBDeviceEventDisplayMessage message) { + GB.log(message.message, message.severity, null); + + Intent messageIntent = new Intent(GB.ACTION_DISPLAY_MESSAGE); + messageIntent.putExtra(GB.DISPLAY_MESSAGE_MESSAGE, message.message); + messageIntent.putExtra(GB.DISPLAY_MESSAGE_DURATION, message.duration); + messageIntent.putExtra(GB.DISPLAY_MESSAGE_SEVERITY, message.severity); + + LocalBroadcastManager.getInstance(context).sendBroadcast(messageIntent); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java index 59b042db..03c40517 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java @@ -2,6 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; +import android.content.Context; import android.net.Uri; import android.widget.Toast; @@ -13,6 +14,7 @@ import java.util.Arrays; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandFWHelper; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; @@ -53,7 +55,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { updateCoordinator.initNextOperation(); if (!updateCoordinator.sendFwInfo()) { - GB.toast(getContext(), "Error sending firmware info, aborting.", Toast.LENGTH_LONG, GB.ERROR); + displayMessage(getContext(), "Error sending firmware info, aborting.", Toast.LENGTH_LONG, GB.ERROR); done(); } //the firmware will be sent by the notification listener if the band confirms that the metadata are ok. @@ -102,9 +104,9 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { switch (value[0]) { case MiBandService.NOTIFY_FW_CHECK_SUCCESS: if (firmwareInfoSent) { - GB.toast(getContext(), "Firmware metadata successfully sent.", Toast.LENGTH_LONG, GB.INFO); + displayMessage(getContext(), "Firmware metadata successfully sent.", Toast.LENGTH_LONG, GB.INFO); if (!updateCoordinator.sendFwData()) { - GB.toast(getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR); + displayMessage(getContext(), getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR); done(); } firmwareInfoSent = false; @@ -113,20 +115,20 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { } break; case MiBandService.NOTIFY_FW_CHECK_FAILED: - GB.toast(getContext().getString(R.string.updatefirmwareoperation_metadata_updateproblem), Toast.LENGTH_LONG, GB.ERROR); + displayMessage(getContext(), getContext().getString(R.string.updatefirmwareoperation_metadata_updateproblem), Toast.LENGTH_LONG, GB.ERROR); firmwareInfoSent = false; done(); break; case MiBandService.NOTIFY_FIRMWARE_UPDATE_SUCCESS: if (updateCoordinator.initNextOperation()) { - GB.toast(getContext(), "Heart Rate Firmware successfully updated, now updating Mi Band Firmware", Toast.LENGTH_LONG, GB.INFO); + displayMessage(getContext(), "Heart Rate Firmware successfully updated, now updating Mi Band Firmware", Toast.LENGTH_LONG, GB.INFO); if (!updateCoordinator.sendFwInfo()) { - GB.toast(getContext(), "Error sending firmware info, aborting.", Toast.LENGTH_LONG, GB.ERROR); + displayMessage(getContext(), "Error sending firmware info, aborting.", Toast.LENGTH_LONG, GB.ERROR); done(); } break; } else if (updateCoordinator.needsReboot()) { - GB.toast(getContext(), getContext().getString(R.string.updatefirmwareoperation_update_complete_rebooting), Toast.LENGTH_LONG, GB.INFO); + displayMessage(getContext(), getContext().getString(R.string.updatefirmwareoperation_update_complete_rebooting), Toast.LENGTH_LONG, GB.INFO); GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_update_complete), false, 100, getContext()); getSupport().onReboot(); } else { @@ -136,7 +138,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { break; case MiBandService.NOTIFY_FIRMWARE_UPDATE_FAILED: //TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do? - GB.toast(getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR); + displayMessage(getContext(), getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR); GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_write_failed), false, 0, getContext()); done(); break; @@ -147,6 +149,10 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { } } + private void displayMessage(Context context, String message, int duration, int severity) { + getSupport().handleGBDeviceEvent(new GBDeviceEventDisplayMessage(message, duration, severity)); + } + /** * Prepare the MiBand to receive the new firmware data. * Some information about the new firmware version have to be pushed to the MiBand before sending @@ -278,7 +284,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { int firmwareProgress = 0; TransactionBuilder builder = performInitialized("send firmware packet"); - getSupport().setLowLatency(builder); +// getSupport().setLowLatency(builder); for (int i = 0; i < packets; i++) { byte[] fwChunk = Arrays.copyOfRange(fwbytes, i * packetLength, i * packetLength + packetLength); @@ -325,7 +331,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { public boolean sendFwInfo() { try { TransactionBuilder builder = performInitialized("send firmware info"); - getSupport().setLowLatency(builder); +// getSupport().setLowLatency(builder); builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.updating_firmware), getContext())); builder.add(new FirmwareInfoSentAction()); // Note: *before* actually sending the info, otherwise it's too late! builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), getFirmwareInfo()); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index c6f87cff..a20e0f2e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -39,6 +39,10 @@ public class GB { public static final int INFO = 1; public static final int WARN = 2; public static final int ERROR = 3; + public static final String ACTION_DISPLAY_MESSAGE = "GB_Display_Message"; + public static final String DISPLAY_MESSAGE_MESSAGE = "message"; + public static final String DISPLAY_MESSAGE_DURATION = "duration"; + public static final String DISPLAY_MESSAGE_SEVERITY = "severity"; public static GBEnvironment environment; public static Notification createNotification(String text, Context context) { @@ -225,7 +229,7 @@ public class GB { } } - private static void log(String message, int severity, Throwable ex) { + public static void log(String message, int severity, Throwable ex) { switch (severity) { case INFO: LOG.info(message, ex); diff --git a/app/src/main/res/layout/activity_appinstaller.xml b/app/src/main/res/layout/activity_appinstaller.xml index 8846623b..eb13abc1 100644 --- a/app/src/main/res/layout/activity_appinstaller.xml +++ b/app/src/main/res/layout/activity_appinstaller.xml @@ -62,6 +62,14 @@ android:layout_below="@+id/installProgressBar" android:layout_marginTop="10dp" /> + + + + + + + + + + + + + + + \ No newline at end of file From 7ddfd35c35ae74598d1bd18eeb34538d8b69542f Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 3 Apr 2016 18:30:20 +0200 Subject: [PATCH 21/43] Pebble: auto connect on incoming notification or phone call if connection was lost unxpectedly before --- .../devices/pebble/PebbleIoThread.java | 11 +++-- .../service/devices/pebble/PebbleSupport.java | 44 ++++++++++++++++++- .../serial/AbstractSerialDeviceSupport.java | 4 +- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index b5bfe222..504a3629 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -200,11 +200,16 @@ public class PebbleIoThread extends GBDeviceIoThread { } mPebbleProtocol.setForceProtocol(sharedPrefs.getBoolean("pebble_force_protocol", false)); - gbDevice.setState(GBDevice.State.CONNECTED); - gbDevice.sendDeviceUpdateIntent(getContext()); mIsConnected = true; - write(mPebbleProtocol.encodeFirmwareVersionReq()); + if (originalState == GBDevice.State.WAITING_FOR_RECONNECT) { + gbDevice.setState(GBDevice.State.INITIALIZED); + } else { + gbDevice.setState(GBDevice.State.CONNECTED); + write(mPebbleProtocol.encodeFirmwareVersionReq()); + } + gbDevice.sendDeviceUpdateIntent(getContext()); + return true; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java index 66560c0d..2734a67c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java @@ -10,7 +10,10 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.UUID; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; @@ -35,7 +38,7 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { @Override public boolean useAutoConnect() { - return false; + return true; } @Override @@ -71,6 +74,45 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { return (PebbleIoThread) super.getDeviceIOThread(); } + private boolean reconnect() { + if (!isConnected() && useAutoConnect()) { + if (getDevice().getState() == GBDevice.State.WAITING_FOR_RECONNECT) { + gbDeviceIOThread.interrupt(); + gbDeviceIOThread = null; + if (!connect()) { + return false; + } + try { + Thread.sleep(2000); // this is about the time the connect takes, so the notification can come though + } catch (InterruptedException ignored) { + } + } + } + return true; + } + + @Override + public void onNotification(NotificationSpec notificationSpec) { + if (reconnect()) { + super.onNotification(notificationSpec); + } + } + + @Override + public void onSetCallState(String number, String name, ServiceCommand command) { + if (reconnect()) { + super.onSetCallState(number, name, command); + } + } + + @Override + public void onSetMusicInfo(String artist, String album, String track, int duration, int trackCount, int trackNr) { + if (reconnect()) { + super.onSetMusicInfo(artist, album, track, duration, trackCount, trackNr); + } + } + + @Override public void onSetAlarms(ArrayList alarms) { //nothing to do ATM diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index 5563de59..9801b8cb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -29,8 +29,8 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport private static final Logger LOG = LoggerFactory.getLogger(AbstractDeviceSupport.class); - private GBDeviceProtocol gbDeviceProtocol; - private GBDeviceIoThread gbDeviceIOThread; + protected GBDeviceProtocol gbDeviceProtocol; + protected GBDeviceIoThread gbDeviceIOThread; /** * Factory method to create the device specific GBDeviceProtocol instance to be used. From 4389c1cca3dc8110a1e1169e19c783e3a36ff970 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 3 Apr 2016 18:36:30 +0200 Subject: [PATCH 22/43] Pebble: wait 4 seconds instead of 2 when notifications/calls trigger reconnection --- .../gadgetbridge/service/devices/pebble/PebbleSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java index 2734a67c..f9fc5de8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java @@ -83,7 +83,7 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { return false; } try { - Thread.sleep(2000); // this is about the time the connect takes, so the notification can come though + Thread.sleep(4000); // this is about the time the connect takes, so the notification can come though } catch (InterruptedException ignored) { } } From 804a85d31fcb74a3a8df5cff16688af64c0d8be3 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 3 Apr 2016 21:41:52 +0200 Subject: [PATCH 23/43] Small refactoring of BtLE actions --- .../btle/AbstractBTLEDeviceSupport.java | 1 + .../{ => actions}/CheckInitializedAction.java | 3 +- .../btle/actions/ConditionalWriteAction.java | 29 +++++++++++++++++++ .../service/btle/actions/WriteAction.java | 18 +++++++++--- .../CheckAuthenticationNeededAction.java | 12 ++++---- 5 files changed, 50 insertions(+), 13 deletions(-) rename app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/{ => actions}/CheckInitializedAction.java (85%) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/ConditionalWriteAction.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java index 051c8ce6..6361431a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java @@ -16,6 +16,7 @@ import java.util.Set; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; +import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.CheckInitializedAction; /** * Abstract base class for all devices connected through Bluetooth Low Energy (LE) aka diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/CheckInitializedAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/CheckInitializedAction.java similarity index 85% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/CheckInitializedAction.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/CheckInitializedAction.java index 21bc0be8..414d983f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/CheckInitializedAction.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/CheckInitializedAction.java @@ -1,10 +1,9 @@ -package nodomain.freeyourgadget.gadgetbridge.service.btle; +package nodomain.freeyourgadget.gadgetbridge.service.btle.actions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; -import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction; /** * A special action that is executed at the very front of the initialization diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/ConditionalWriteAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/ConditionalWriteAction.java new file mode 100644 index 00000000..a7cb39ce --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/ConditionalWriteAction.java @@ -0,0 +1,29 @@ +package nodomain.freeyourgadget.gadgetbridge.service.btle.actions; + +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; + +public abstract class ConditionalWriteAction extends WriteAction { + public ConditionalWriteAction(BluetoothGattCharacteristic characteristic) { + super(characteristic, null); + } + + @Override + protected boolean writeValue(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, byte[] value) { + byte[] conditionalValue = checkCondition(); + if (conditionalValue != null) { + return super.writeValue(gatt, characteristic, conditionalValue); + } + return true; + } + + /** + * Checks the condition whether the write shall happen or not. + * Returns the actual value to be written or null in case nothing shall be written. + * + * Note that returning null will not cause run() to return false, in other words, + * the rest of the queue will still be executed. + * @return the value to be written or null to not write anything + */ + protected abstract byte[] checkCondition(); +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/WriteAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/WriteAction.java index b4ec9548..5cecee06 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/WriteAction.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/WriteAction.java @@ -22,16 +22,26 @@ public class WriteAction extends BtLEAction { @Override public boolean run(BluetoothGatt gatt) { - int properties = getCharacteristic().getProperties(); + BluetoothGattCharacteristic characteristic = getCharacteristic(); + int properties = characteristic.getProperties(); //TODO: expectsResult should return false if PROPERTY_WRITE_NO_RESPONSE is true, but this yelds to timing issues if ((properties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0 || ((properties & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0)) { - if (getCharacteristic().setValue(value)) { - return gatt.writeCharacteristic(getCharacteristic()); - } + return writeValue(gatt, characteristic, value); } return false; } + protected boolean writeValue(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, byte[] value) { + if (characteristic.setValue(value)) { + return gatt.writeCharacteristic(characteristic); + } + return false; + } + + protected final byte[] getValue() { + return value; + } + @Override public boolean expectsResult() { return true; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/CheckAuthenticationNeededAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/CheckAuthenticationNeededAction.java index 6f25b163..8415c695 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/CheckAuthenticationNeededAction.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/CheckAuthenticationNeededAction.java @@ -1,11 +1,9 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband; -import android.bluetooth.BluetoothGatt; - import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; -import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.PlainAction; +import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction; -public class CheckAuthenticationNeededAction extends PlainAction { +public class CheckAuthenticationNeededAction extends AbortTransactionAction { private final GBDevice mDevice; public CheckAuthenticationNeededAction(GBDevice device) { @@ -14,14 +12,14 @@ public class CheckAuthenticationNeededAction extends PlainAction { } @Override - public boolean run(BluetoothGatt gatt) { + protected boolean shouldAbort() { // the state is set in MiBandSupport.handleNotificationNotif() switch (mDevice.getState()) { case AUTHENTICATION_REQUIRED: // fall through case AUTHENTICATING: - return false; // abort the whole thing + return true; // abort the whole thing default: - return true; + return false; } } } From b129844169e54283fd72bd57491a5cdeba35ebd4 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 3 Apr 2016 22:38:06 +0200 Subject: [PATCH 24/43] Small fixes to PR 273 #232 - dynamically toggle hr sleep support when preference changes - check hr support dynaically after device info is available to avoid false error message --- .../gadgetbridge/devices/EventHandler.java | 1 + .../miband/MiBandPreferencesActivity.java | 10 +++- .../gadgetbridge/impl/GBDeviceService.java | 9 +++- .../gadgetbridge/model/DeviceService.java | 3 +- .../service/DeviceCommunicationService.java | 13 +++-- .../service/ServiceDeviceSupport.java | 8 +++ .../service/devices/miband/MiBandSupport.java | 52 +++++++++++-------- .../serial/AbstractSerialDeviceSupport.java | 6 +++ .../service/serial/GBDeviceProtocol.java | 2 + .../service/TestDeviceSupport.java | 5 ++ 10 files changed, 82 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index f03413af..af6f9a5e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -48,4 +48,5 @@ public interface EventHandler { void onScreenshotReq(); + void onEnableHeartRateSleepSupport(boolean enable); } 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 76cca5cb..7ef19b80 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 @@ -5,6 +5,7 @@ import android.os.Bundle; import android.preference.Preference; import android.support.v4.content.LocalBroadcastManager; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity; import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter; @@ -44,6 +45,14 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity { }); + final Preference enableHeartrateSleepSupport = findPreference(PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION); + enableHeartrateSleepSupport.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newVal) { + GBApplication.deviceService().onEnableHeartRateSleepSupport(Boolean.TRUE.equals(newVal)); + return true; + } + }); } @Override @@ -55,7 +64,6 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity { PREF_MIBAND_FITNESS_GOAL, PREF_MIBAND_DONT_ACK_TRANSFER, PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, - PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION, getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_SMS), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_SMS), getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_INCOMING_CALL), 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 62d7f15c..17b8614f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -205,7 +205,14 @@ public class GBDeviceService implements DeviceService { @Override public void onEnableRealtimeSteps(boolean enable) { Intent intent = createIntent().setAction(ACTION_ENABLE_REALTIME_STEPS) - .putExtra(EXTRA_ENABLE_REALTIME_STEPS, enable); + .putExtra(EXTRA_BOOLEAN_ENABLE, enable); + invokeService(intent); + } + + @Override + public void onEnableHeartRateSleepSupport(boolean enable) { + Intent intent = createIntent().setAction(ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT) + .putExtra(EXTRA_BOOLEAN_ENABLE, enable); invokeService(intent); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java index 8217f6d4..7c38088f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -33,6 +33,7 @@ public interface DeviceService extends EventHandler { String ACTION_SET_ALARMS = PREFIX + ".action.set_alarms"; String ACTION_ENABLE_REALTIME_STEPS = PREFIX + ".action.enable_realtime_steps"; String ACTION_REALTIME_STEPS = PREFIX + ".action.realtime_steps"; + String ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT = PREFIX + ".action.enable_heartrate_sleep_support"; String EXTRA_DEVICE_ADDRESS = "device_address"; String EXTRA_NOTIFICATION_BODY = "notification_body"; String EXTRA_NOTIFICATION_FLAGS = "notification_flags"; @@ -58,7 +59,7 @@ public interface DeviceService extends EventHandler { String EXTRA_URI = "uri"; String EXTRA_ALARMS = "alarms"; String EXTRA_PERFORM_PAIR = "perform_pair"; - String EXTRA_ENABLE_REALTIME_STEPS = "enable_realtime_steps"; + String EXTRA_BOOLEAN_ENABLE = "enable_realtime_steps"; String EXTRA_REALTIME_STEPS = "realtime_steps"; String EXTRA_TIMESTAMP = "timestamp"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index a9261f7b..68ecefee 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -44,6 +44,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CA import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CONNECT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DELETEAPP; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DISCONNECT; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_REALTIME_STEPS; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_FETCH_ACTIVITY_DATA; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_FIND_DEVICE; @@ -66,7 +67,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_APP import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALL_COMMAND; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALL_PHONENUMBER; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_DEVICE_ADDRESS; -import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_ENABLE_REALTIME_STEPS; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_BOOLEAN_ENABLE; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_FIND_START; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_ALBUM; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_ARTIST; @@ -331,10 +332,16 @@ public class DeviceCommunicationService extends Service { ArrayList alarms = intent.getParcelableArrayListExtra(EXTRA_ALARMS); mDeviceSupport.onSetAlarms(alarms); break; - case ACTION_ENABLE_REALTIME_STEPS: - boolean enable = intent.getBooleanExtra(EXTRA_ENABLE_REALTIME_STEPS, false); + case ACTION_ENABLE_REALTIME_STEPS: { + boolean enable = intent.getBooleanExtra(EXTRA_BOOLEAN_ENABLE, false); mDeviceSupport.onEnableRealtimeSteps(enable); break; + } + case ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT: { + boolean enable = intent.getBooleanExtra(EXTRA_BOOLEAN_ENABLE, false); + mDeviceSupport.onEnableHeartRateSleepSupport(enable); + break; + } } return START_STICKY; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index 993b0319..a3994b47 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -241,4 +241,12 @@ public class ServiceDeviceSupport implements DeviceSupport { } delegate.onEnableRealtimeSteps(enable); } + + @Override + public void onEnableHeartRateSleepSupport(boolean enable) { + if (checkBusy("enable heartrate sleep support: " + enable)) { + return; + } + delegate.onEnableHeartRateSleepSupport(enable); + } } 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 136cb5f1..f6dd7ce9 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 @@ -44,6 +44,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic; import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction; +import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.ConditionalWriteAction; import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WriteAction; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.FetchActivityOperation; @@ -369,31 +370,40 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { return this; } + @Override + public void onEnableHeartRateSleepSupport(boolean enable) { + try { + TransactionBuilder builder = performInitialized("enable heart rate sleep support: " + enable); + setHeartrateSleepSupport(builder); + builder.queue(getQueue()); + } catch (IOException e) { + GB.toast(getContext(), "Error toggling heart rate sleep support: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR); + } + } + /** * Part of device initialization process. Do not call manually. - * - * @param transaction - * @return + * @param builder */ - private MiBandSupport setHeartrateSleepSupport(TransactionBuilder transaction) { - if (supportsHeartRate()) { - LOG.info("Attempting to set heartrate sleep support..."); - BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT); - if (characteristic != null) { - if(MiBandCoordinator.getHeartrateSleepSupport(getDevice().getAddress())) { - LOG.info("Enabling heartrate sleep support..."); - transaction.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementSleep); + private MiBandSupport setHeartrateSleepSupport(TransactionBuilder builder) { + BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT); + if (characteristic != null) { + builder.add(new ConditionalWriteAction(characteristic) { + @Override + protected byte[] checkCondition() { + if (!supportsHeartRate()) { + return null; + } + if (MiBandCoordinator.getHeartrateSleepSupport(getDevice().getAddress())) { + LOG.info("Enabling heartrate sleep support..."); + return startHeartMeasurementSleep; + } else { + LOG.info("Disabling heartrate sleep support..."); + return stopHeartMeasurementSleep; + } } - else { - LOG.info("Disabling heartrate sleep support..."); - transaction.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementSleep); - } - } else { - LOG.info("Unable to set Heartrate sleep support"); - } - - } else - GB.toast(getContext(), "Heart rate is not supported on this device", Toast.LENGTH_LONG, GB.ERROR); + }); + } return this; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index 9801b8cb..a871cac6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -178,4 +178,10 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport byte[] bytes = gbDeviceProtocol.encodeEnableRealtimeSteps(enable); sendToDevice(bytes); } + + @Override + public void onEnableHeartRateSleepSupport(boolean enable) { + byte[] bytes = gbDeviceProtocol.encodeEnableHeartRateSleepSupport(enable); + sendToDevice(bytes); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index b08b105d..5cd9ef82 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -60,6 +60,8 @@ public abstract class GBDeviceProtocol { return null; } + public byte[] encodeEnableHeartRateSleepSupport(boolean enable) { return null; } + public GBDeviceEvent[] decodeResponse(byte[] responseData) { return null; } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java index 6528b613..b3604199 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java @@ -124,4 +124,9 @@ public class TestDeviceSupport extends AbstractDeviceSupport { public void onEnableRealtimeSteps(boolean enable) { } + + @Override + public void onEnableHeartRateSleepSupport(boolean enable) { + + } } From 59c3970008734cf9104b461cebee2a864540c9ca Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 3 Apr 2016 23:01:58 +0200 Subject: [PATCH 25/43] Reuse characteristic objects #234 --- .../miband/operations/UpdateFirmwareOperation.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java index 03c40517..4bb7d6ba 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java @@ -278,7 +278,8 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { final int packetLength = 20; int packets = len / packetLength; - + BluetoothGattCharacteristic characteristicControlPoint = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT); + BluetoothGattCharacteristic characteristicFWData = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_FIRMWARE_DATA); try { // going from 0 to len int firmwareProgress = 0; @@ -288,23 +289,23 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation { for (int i = 0; i < packets; i++) { byte[] fwChunk = Arrays.copyOfRange(fwbytes, i * packetLength, i * packetLength + packetLength); - builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_FIRMWARE_DATA), fwChunk); + builder.write(characteristicFWData, fwChunk); firmwareProgress += packetLength; int progressPercent = (int) ((((float) firmwareProgress) / len) * 100); if ((i > 0) && (i % 50 == 0)) { - builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), new byte[]{MiBandService.COMMAND_SYNC}); + builder.write(characteristicControlPoint, new byte[]{MiBandService.COMMAND_SYNC}); builder.add(new SetProgressAction(getContext().getString(R.string.updatefirmwareoperation_update_in_progress), true, progressPercent, getContext())); } } if (firmwareProgress < len) { byte[] lastChunk = Arrays.copyOfRange(fwbytes, packets * packetLength, len); - builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_FIRMWARE_DATA), lastChunk); + builder.write(characteristicFWData, lastChunk); firmwareProgress = len; } - builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), new byte[]{MiBandService.COMMAND_SYNC}); + builder.write(characteristicControlPoint, new byte[]{MiBandService.COMMAND_SYNC}); builder.queue(getQueue()); } catch (IOException ex) { From 3e3cf462a693a11d33b6b92fc43586ecfaed5888 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 3 Apr 2016 23:32:15 +0200 Subject: [PATCH 26/43] Attempt to re-enable automatic reconnect (autosensing) #249 (now that initializing device works again) --- .../freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index b74cdbfd..b31ba1d2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -158,7 +158,7 @@ public final class BtLEQueue { mBluetoothAdapter.cancelDiscovery(); BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(mGbDevice.getAddress()); synchronized (mGattMonitor) { - mBluetoothGatt = remoteDevice.connectGatt(mContext, false, internalGattCallback); + mBluetoothGatt = remoteDevice.connectGatt(mContext, true, internalGattCallback); // result = mBluetoothGatt.connect(); } boolean result = mBluetoothGatt != null; From a15b327ff1c90a5133c1fd40eeb01bd03e738cdc Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 4 Apr 2016 20:08:34 +0200 Subject: [PATCH 27/43] Refactoring: get rid of ServiceCommand, use new CallSpec and MusicSpec to pass Call and Music info --- .../activities/DebugActivity.java | 46 ++++++++++--------- .../GBDeviceEventDisplayMessage.java | 1 + .../gadgetbridge/devices/EventHandler.java | 8 ++-- .../devices/miband/MiBandConst.java | 1 - .../externalevents/MusicPlaybackReceiver.java | 12 +++-- .../externalevents/NotificationListener.java | 1 - .../externalevents/PhoneCallReceiver.java | 21 +++++---- .../gadgetbridge/impl/GBDeviceService.java | 23 +++++----- .../gadgetbridge/model/CallSpec.java | 15 ++++++ .../gadgetbridge/model/MusicSpec.java | 17 +++++++ .../gadgetbridge/model/ServiceCommand.java | 22 --------- .../service/AbstractDeviceSupport.java | 1 - .../service/DeviceCommunicationService.java | 34 +++++++++----- .../service/ServiceDeviceSupport.java | 11 +++-- .../btle/actions/ConditionalWriteAction.java | 3 +- .../service/devices/miband/MiBandSupport.java | 12 +++-- .../devices/pebble/PebbleProtocol.java | 14 +++--- .../service/devices/pebble/PebbleSupport.java | 11 +++-- .../serial/AbstractSerialDeviceSupport.java | 11 +++-- .../service/serial/GBDeviceProtocol.java | 7 +-- .../service/TestDeviceSupport.java | 8 ++-- 21 files changed, 158 insertions(+), 121 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CallSpec.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicSpec.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ServiceCommand.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index 3d438bcd..dc7eb2f5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -29,9 +29,10 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -118,20 +119,20 @@ public class DebugActivity extends Activity { incomingCallButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - GBApplication.deviceService().onSetCallState( - editContent.getText().toString(), - null, - ServiceCommand.CALL_INCOMING); + CallSpec callSpec = new CallSpec(); + callSpec.command = CallSpec.CALL_INCOMING; + callSpec.number = editContent.getText().toString(); + GBApplication.deviceService().onSetCallState(callSpec); } }); outgoingCallButton = (Button) findViewById(R.id.outgoingCallButton); outgoingCallButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - GBApplication.deviceService().onSetCallState( - editContent.getText().toString(), - null, - ServiceCommand.CALL_OUTGOING); + CallSpec callSpec = new CallSpec(); + callSpec.command = CallSpec.CALL_OUTGOING; + callSpec.number = editContent.getText().toString(); + GBApplication.deviceService().onSetCallState(callSpec); } }); @@ -139,20 +140,18 @@ public class DebugActivity extends Activity { startCallButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - GBApplication.deviceService().onSetCallState( - null, - null, - ServiceCommand.CALL_START); + CallSpec callSpec = new CallSpec(); + callSpec.command = CallSpec.CALL_START; + GBApplication.deviceService().onSetCallState(callSpec); } }); endCallButton = (Button) findViewById(R.id.endCallButton); endCallButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - GBApplication.deviceService().onSetCallState( - null, - null, - ServiceCommand.CALL_END); + CallSpec callSpec = new CallSpec(); + callSpec.command = CallSpec.CALL_END; + GBApplication.deviceService().onSetCallState(callSpec); } }); @@ -199,10 +198,15 @@ public class DebugActivity extends Activity { setMusicInfoButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - GBApplication.deviceService().onSetMusicInfo( - editContent.getText().toString() + "(artist)", - editContent.getText().toString() + "(album)", - editContent.getText().toString() + "(track)", 20, 10, 2); + MusicSpec musicSpec = new MusicSpec(); + musicSpec.artist = editContent.getText().toString() + "(artist)"; + musicSpec.album = editContent.getText().toString() + "(album)"; + musicSpec.track = editContent.getText().toString() + "(track)"; + musicSpec.duration = 10; + musicSpec.trackCount = 5; + musicSpec.trackNr = 2; + + GBApplication.deviceService().onSetMusicInfo(musicSpec); } }); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventDisplayMessage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventDisplayMessage.java index 33250737..29e5ed12 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventDisplayMessage.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventDisplayMessage.java @@ -9,6 +9,7 @@ public class GBDeviceEventDisplayMessage { * An event for displaying a message to the user. How the message is displayed * is a detail of the current activity, which needs to listen to the Intent * GB.ACTION_DISPLAY_MESSAGE. + * * @param message * @param duration * @param severity diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index af6f9a5e..5ddad49e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -1,14 +1,14 @@ package nodomain.freeyourgadget.gadgetbridge.devices; import android.net.Uri; -import android.support.annotation.Nullable; import java.util.ArrayList; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; /** * Specifies all events that GadgetBridge intends to send to the gadget device. @@ -22,9 +22,9 @@ public interface EventHandler { void onSetAlarms(ArrayList alarms); - void onSetCallState(@Nullable String number, @Nullable String name, ServiceCommand command); + void onSetCallState(CallSpec callSpec); - void onSetMusicInfo(String artist, String album, String track, int duration, int trackCount, int trackNr); + void onSetMusicInfo(MusicSpec musicSpec); void onEnableRealtimeSteps(boolean enable); 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 f3cc3182..511de9dd 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 @@ -18,7 +18,6 @@ public final class MiBandConst { public static final String PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION = "mi_hr_sleep_detection"; - public static final String ORIGIN_SMS = "sms"; public static final String ORIGIN_INCOMING_CALL = "incoming_call"; public static final String ORIGIN_K9MAIL = "k9mail"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java index 1b452030..d910e75e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java @@ -8,12 +8,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; public class MusicPlaybackReceiver extends BroadcastReceiver { private static final Logger LOG = LoggerFactory.getLogger(MusicPlaybackReceiver.class); - private static String mLastSource; - @Override public void onReceive(Context context, Intent intent) { String artist = intent.getStringExtra("artist"); @@ -24,11 +23,16 @@ public class MusicPlaybackReceiver extends BroadcastReceiver { for (String key : bundle.keySet()) { Object value = bundle.get(key); LOG.info(String.format("%s %s (%s)", key, - value.toString(), value.getClass().getName())); + value != null ? value.toString() : "null", value != null ? value.getClass().getName() : "no class")); } */ LOG.info("Current track: " + artist + ", " + album + ", " + track); - GBApplication.deviceService().onSetMusicInfo(artist, album, track, 0, 0, 0); + MusicSpec musicSpec = new MusicSpec(); + musicSpec.artist = artist; + musicSpec.artist = album; + musicSpec.artist = track; + + GBApplication.deviceService().onSetMusicInfo(musicSpec); } } 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 079f0132..124c0b99 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -26,7 +26,6 @@ import org.slf4j.LoggerFactory; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java index 26513a06..010b5fb8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java @@ -8,7 +8,7 @@ import android.preference.PreferenceManager; import android.telephony.TelephonyManager; import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; public class PhoneCallReceiver extends BroadcastReceiver { @@ -40,35 +40,38 @@ public class PhoneCallReceiver extends BroadcastReceiver { return; } - ServiceCommand callCommand = null; + int callCommand = CallSpec.CALL_UNDEFINED; switch (state) { case TelephonyManager.CALL_STATE_RINGING: mSavedNumber = number; - callCommand = ServiceCommand.CALL_INCOMING; + callCommand = CallSpec.CALL_INCOMING; break; case TelephonyManager.CALL_STATE_OFFHOOK: if (mLastState == TelephonyManager.CALL_STATE_RINGING) { - callCommand = ServiceCommand.CALL_START; + callCommand = CallSpec.CALL_START; } else { - callCommand = ServiceCommand.CALL_OUTGOING; + callCommand = CallSpec.CALL_OUTGOING; mSavedNumber = number; } break; case TelephonyManager.CALL_STATE_IDLE: if (mLastState == TelephonyManager.CALL_STATE_RINGING) { //missed call would be correct here - callCommand = ServiceCommand.CALL_END; + callCommand = CallSpec.CALL_END; } else { - callCommand = ServiceCommand.CALL_END; + callCommand = CallSpec.CALL_END; } break; } - if (callCommand != null) { + if (callCommand != CallSpec.CALL_UNDEFINED) { SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); if ("never".equals(sharedPrefs.getString("notification_mode_calls", "always"))) { return; } - GBApplication.deviceService().onSetCallState(mSavedNumber, null, callCommand); + CallSpec callSpec = new CallSpec(); + callSpec.number = mSavedNumber; + callSpec.command = callCommand; + GBApplication.deviceService().onSetCallState(callSpec); } mLastState = state; } 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 17b8614f..add9f676 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -10,9 +10,10 @@ import java.util.ArrayList; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; public class GBDeviceService implements DeviceService { @@ -115,23 +116,23 @@ public class GBDeviceService implements DeviceService { } @Override - public void onSetCallState(String number, String name, ServiceCommand command) { + public void onSetCallState(CallSpec callSpec) { // name is actually ignored and provided by the service itself... Intent intent = createIntent().setAction(ACTION_CALLSTATE) - .putExtra(EXTRA_CALL_PHONENUMBER, number) - .putExtra(EXTRA_CALL_COMMAND, command); + .putExtra(EXTRA_CALL_PHONENUMBER, callSpec.number) + .putExtra(EXTRA_CALL_COMMAND, callSpec.command); invokeService(intent); } @Override - public void onSetMusicInfo(String artist, String album, String track, int duration, int trackCount, int trackNr) { + public void onSetMusicInfo(MusicSpec musicSpec) { Intent intent = createIntent().setAction(ACTION_SETMUSICINFO) - .putExtra(EXTRA_MUSIC_ARTIST, artist) - .putExtra(EXTRA_MUSIC_ALBUM, album) - .putExtra(EXTRA_MUSIC_TRACK, track) - .putExtra(EXTRA_MUSIC_DURATION, duration) - .putExtra(EXTRA_MUSIC_TRACKCOUNT, trackCount) - .putExtra(EXTRA_MUSIC_TRACKNR, trackNr); + .putExtra(EXTRA_MUSIC_ARTIST, musicSpec.artist) + .putExtra(EXTRA_MUSIC_ALBUM, musicSpec.album) + .putExtra(EXTRA_MUSIC_TRACK, musicSpec.track) + .putExtra(EXTRA_MUSIC_DURATION, musicSpec.duration) + .putExtra(EXTRA_MUSIC_TRACKCOUNT, musicSpec.trackCount) + .putExtra(EXTRA_MUSIC_TRACKNR, musicSpec.trackNr); invokeService(intent); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CallSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CallSpec.java new file mode 100644 index 00000000..1d088a49 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CallSpec.java @@ -0,0 +1,15 @@ +package nodomain.freeyourgadget.gadgetbridge.model; + +public class CallSpec { + public static final int CALL_UNDEFINED = 1; + public static final int CALL_ACCEPT = 1; + public static final int CALL_INCOMING = 2; + public static final int CALL_OUTGOING = 3; + public static final int CALL_REJECT = 4; + public static final int CALL_START = 5; + public static final int CALL_END = 6; + + public String number; + public String name; + public int command; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicSpec.java new file mode 100644 index 00000000..af52f02f --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicSpec.java @@ -0,0 +1,17 @@ +package nodomain.freeyourgadget.gadgetbridge.model; + +public class MusicSpec { + public static final int MUSIC_UNDEFINED = 0; + public static final int MUSIC_PLAY = 1; + public static final int MUSIC_PAUSE = 2; + public static final int MUSIC_PLAYPAUSE = 3; + public static final int MUSIC_NEXT = 4; + public static final int MUSIC_PREVIOUS = 5; + + public String artist; + public String album; + public String track; + public int duration; + public int trackCount; + public int trackNr; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ServiceCommand.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ServiceCommand.java deleted file mode 100644 index 5cb94511..00000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ServiceCommand.java +++ /dev/null @@ -1,22 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.model; - -public enum ServiceCommand { - - UNDEFINED, - - CALL_ACCEPT, - CALL_END, - CALL_INCOMING, - CALL_OUTGOING, - CALL_REJECT, - CALL_START, - - MUSIC_PLAY, - MUSIC_PAUSE, - MUSIC_PLAYPAUSE, - MUSIC_NEXT, - MUSIC_PREVIOUS, - - APP_INFO_NAME, - VERSION_FIRMWARE -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java index d33b9dd9..d103011a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java @@ -1,6 +1,5 @@ package nodomain.freeyourgadget.gadgetbridge.service; -import android.app.Application; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index 68ecefee..6ade401d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -33,9 +33,10 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.SMSReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.TimeChangeReceiver; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -64,10 +65,10 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_ALA import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_APP_CONFIG; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_APP_START; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_APP_UUID; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_BOOLEAN_ENABLE; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALL_COMMAND; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALL_PHONENUMBER; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_DEVICE_ADDRESS; -import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_BOOLEAN_ENABLE; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_FIND_START; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_ALBUM; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_ARTIST; @@ -278,26 +279,32 @@ public class DeviceCommunicationService extends Service { break; } case ACTION_CALLSTATE: - ServiceCommand command = (ServiceCommand) intent.getSerializableExtra(EXTRA_CALL_COMMAND); + int command = intent.getIntExtra(EXTRA_CALL_COMMAND, CallSpec.CALL_UNDEFINED); String phoneNumber = intent.getStringExtra(EXTRA_CALL_PHONENUMBER); String callerName = null; if (phoneNumber != null) { callerName = getContactDisplayNameByNumber(phoneNumber); } - mDeviceSupport.onSetCallState(phoneNumber, callerName, command); + + CallSpec callSpec = new CallSpec(); + callSpec.command = command; + callSpec.number = phoneNumber; + callSpec.name = callerName; + mDeviceSupport.onSetCallState(callSpec); break; case ACTION_SETTIME: mDeviceSupport.onSetTime(); break; case ACTION_SETMUSICINFO: - String artist = intent.getStringExtra(EXTRA_MUSIC_ARTIST); - String album = intent.getStringExtra(EXTRA_MUSIC_ALBUM); - String track = intent.getStringExtra(EXTRA_MUSIC_TRACK); - int duration = intent.getIntExtra(EXTRA_MUSIC_DURATION, 0); - int trackCount = intent.getIntExtra(EXTRA_MUSIC_TRACKCOUNT, 0); - int trackNr = intent.getIntExtra(EXTRA_MUSIC_TRACKNR, 0); - mDeviceSupport.onSetMusicInfo(artist, album, track, duration, trackCount, trackNr); + MusicSpec musicSpec = new MusicSpec(); + musicSpec.artist = intent.getStringExtra(EXTRA_MUSIC_ARTIST); + musicSpec.album = intent.getStringExtra(EXTRA_MUSIC_ALBUM); + musicSpec.track = intent.getStringExtra(EXTRA_MUSIC_TRACK); + musicSpec.duration = intent.getIntExtra(EXTRA_MUSIC_DURATION, 0); + musicSpec.trackCount = intent.getIntExtra(EXTRA_MUSIC_TRACKCOUNT, 0); + musicSpec.trackNr = intent.getIntExtra(EXTRA_MUSIC_TRACKNR, 0); + mDeviceSupport.onSetMusicInfo(musicSpec); break; case ACTION_REQUEST_APPINFO: mDeviceSupport.onAppInfoReq(); @@ -424,7 +431,10 @@ public class DeviceCommunicationService extends Service { } if (mMusicPlaybackReceiver == null) { mMusicPlaybackReceiver = new MusicPlaybackReceiver(); - registerReceiver(mMusicPlaybackReceiver, new IntentFilter("com.android.music.metachanged")); + IntentFilter filter = new IntentFilter(); + filter.addAction("com.android.music.metachanged"); + //filter.addAction("com.android.music.playstatechanged"); + registerReceiver(mMusicPlaybackReceiver, filter); } if (mTimeChangeReceiver == null) { mTimeChangeReceiver = new TimeChangeReceiver(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index a3994b47..e54e61bd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -13,8 +13,9 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; /** * Wraps another device support instance and supports busy-checking and throttling of events. @@ -131,19 +132,19 @@ public class ServiceDeviceSupport implements DeviceSupport { // No throttling for the other events @Override - public void onSetCallState(String number, String name, ServiceCommand command) { + public void onSetCallState(CallSpec callSpec) { if (checkBusy("set call state")) { return; } - delegate.onSetCallState(number, name, command); + delegate.onSetCallState(callSpec); } @Override - public void onSetMusicInfo(String artist, String album, String track, int duration, int trackCount, int trackNr) { + public void onSetMusicInfo(MusicSpec musicSpec) { if (checkBusy("set music info")) { return; } - delegate.onSetMusicInfo(artist, album, track, duration, trackCount, trackNr); + delegate.onSetMusicInfo(musicSpec); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/ConditionalWriteAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/ConditionalWriteAction.java index a7cb39ce..6d373faf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/ConditionalWriteAction.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/ConditionalWriteAction.java @@ -20,9 +20,10 @@ public abstract class ConditionalWriteAction extends WriteAction { /** * Checks the condition whether the write shall happen or not. * Returns the actual value to be written or null in case nothing shall be written. - * + *

* Note that returning null will not cause run() to return false, in other words, * the rest of the queue will still be executed. + * * @return the value to be written or null to not write anything */ protected abstract byte[] checkCondition(); 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 f6dd7ce9..37b22591 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 @@ -34,10 +34,11 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.model.GenericItem; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction; import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic; @@ -383,6 +384,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { /** * Part of device initialization process. Do not call manually. + * * @param builder */ private MiBandSupport setHeartrateSleepSupport(TransactionBuilder builder) { @@ -558,8 +560,8 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } @Override - public void onSetCallState(String number, String name, ServiceCommand command) { - if (ServiceCommand.CALL_INCOMING.equals(command)) { + public void onSetCallState(CallSpec callSpec) { + if (callSpec.command == CallSpec.CALL_INCOMING) { telephoneRinging = true; AbortTransactionAction abortAction = new AbortTransactionAction() { @Override @@ -568,7 +570,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } }; performPreferredNotification("incoming call", MiBandConst.ORIGIN_INCOMING_CALL, abortAction); - } else if (ServiceCommand.CALL_START.equals(command) || ServiceCommand.CALL_END.equals(command)) { + } else if ((callSpec.command == CallSpec.CALL_START) || (callSpec.command == CallSpec.CALL_END)) { telephoneRinging = false; } } @@ -579,7 +581,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } @Override - public void onSetMusicInfo(String artist, String album, String track, int duration, int trackCount, int trackNr) { + public void onSetMusicInfo(MusicSpec musicSpec) { // not supported } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index fc00f327..2f6f9236 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -33,9 +33,9 @@ import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleColor; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleIconID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; public class PebbleProtocol extends GBDeviceProtocol { @@ -495,7 +495,7 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeFindDevice(boolean start) { - return encodeSetCallState("Where are you?", "Gadgetbridge", start ? ServiceCommand.CALL_INCOMING : ServiceCommand.CALL_END); + return encodeSetCallState("Where are you?", "Gadgetbridge", start ? CallSpec.CALL_INCOMING : CallSpec.CALL_END); } private static byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, String[] cannedReplies) { @@ -1044,20 +1044,20 @@ public class PebbleProtocol extends GBDeviceProtocol { } @Override - public byte[] encodeSetCallState(String number, String name, ServiceCommand command) { + public byte[] encodeSetCallState(String number, String name, int command) { String[] parts = {number, name}; byte pebbleCmd; switch (command) { - case CALL_START: + case CallSpec.CALL_START: pebbleCmd = PHONECONTROL_START; break; - case CALL_END: + case CallSpec.CALL_END: pebbleCmd = PHONECONTROL_END; break; - case CALL_INCOMING: + case CallSpec.CALL_INCOMING: pebbleCmd = PHONECONTROL_INCOMINGCALL; break; - case CALL_OUTGOING: + case CallSpec.CALL_OUTGOING: // pebbleCmd = PHONECONTROL_OUTGOINGCALL; /* * HACK/WORKAROUND for non-working outgoing call display. diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java index f9fc5de8..74e4736d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java @@ -12,8 +12,9 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; @@ -99,16 +100,16 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { } @Override - public void onSetCallState(String number, String name, ServiceCommand command) { + public void onSetCallState(CallSpec callSpec) { if (reconnect()) { - super.onSetCallState(number, name, command); + super.onSetCallState(callSpec); } } @Override - public void onSetMusicInfo(String artist, String album, String track, int duration, int trackCount, int trackNr) { + public void onSetMusicInfo(MusicSpec musicSpec) { if (reconnect()) { - super.onSetMusicInfo(artist, album, track, duration, trackCount, trackNr); + super.onSetMusicInfo(musicSpec); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index a871cac6..5d3bd610 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -8,8 +8,9 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; /** @@ -120,14 +121,14 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport } @Override - public void onSetCallState(String number, String name, ServiceCommand command) { - byte[] bytes = gbDeviceProtocol.encodeSetCallState(number, name, command); + public void onSetCallState(CallSpec callSpec) { + byte[] bytes = gbDeviceProtocol.encodeSetCallState(callSpec.number, callSpec.name, callSpec.command); sendToDevice(bytes); } @Override - public void onSetMusicInfo(String artist, String album, String track, int duration, int trackCount, int trackNr) { - byte[] bytes = gbDeviceProtocol.encodeSetMusicInfo(artist, album, track, duration, trackCount, trackNr); + public void onSetMusicInfo(MusicSpec musicSpec) { + byte[] bytes = gbDeviceProtocol.encodeSetMusicInfo(musicSpec.artist, musicSpec.album, musicSpec.track, musicSpec.duration, musicSpec.trackCount, musicSpec.trackNr); sendToDevice(bytes); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index 5cd9ef82..2aa1fb66 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -4,7 +4,6 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; public abstract class GBDeviceProtocol { @@ -16,7 +15,7 @@ public abstract class GBDeviceProtocol { return null; } - public byte[] encodeSetCallState(String number, String name, ServiceCommand command) { + public byte[] encodeSetCallState(String number, String name, int command) { return null; } @@ -60,7 +59,9 @@ public abstract class GBDeviceProtocol { return null; } - public byte[] encodeEnableHeartRateSleepSupport(boolean enable) { return null; } + public byte[] encodeEnableHeartRateSleepSupport(boolean enable) { + return null; + } public GBDeviceEvent[] decodeResponse(byte[] responseData) { return null; diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java index b3604199..19fd1810 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java @@ -3,15 +3,15 @@ package nodomain.freeyourgadget.gadgetbridge.service; import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.net.Uri; -import android.support.annotation.Nullable; import java.util.ArrayList; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; public class TestDeviceSupport extends AbstractDeviceSupport { @@ -61,12 +61,12 @@ public class TestDeviceSupport extends AbstractDeviceSupport { } @Override - public void onSetCallState(@Nullable String number, @Nullable String name, ServiceCommand command) { + public void onSetCallState(CallSpec callSpec) { } @Override - public void onSetMusicInfo(String artist, String album, String track, int duration, int trackCount, int trackNr) { + public void onSetMusicInfo(MusicSpec musicSpec) { } From 403f74e59bfd5e7f5a694ce5ebf52773a0099396 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Mon, 4 Apr 2016 23:05:00 +0200 Subject: [PATCH 28/43] Enable heart rate charts #232 (And fix some charting issues) --- .../charts/AbstractChartFragment.java | 29 ++++++++++++++----- .../charts/ActivitySleepChartFragment.java | 7 +++++ .../activities/charts/SleepChartFragment.java | 13 +++++++-- app/src/main/res/values/colors.xml | 2 +- app/src/main/res/values/strings.xml | 1 + 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index 21f7774f..13bbc2c0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -79,7 +79,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } }; private boolean mChartDirty = true; - private boolean supportsHeartrateChart = false; + private boolean supportsHeartrateChart = true; public boolean isChartDirty() { return mChartDirty; @@ -119,6 +119,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { protected int AK_LIGHT_SLEEP_COLOR; protected int AK_NOT_WORN_COLOR; + protected String HEARTRATE_LABEL; + protected AbstractChartFragment(String... intentFilterActions) { mIntentFilterActions = new HashSet<>(); if (intentFilterActions != null) { @@ -153,6 +155,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { AK_LIGHT_SLEEP_COLOR = getResources().getColor(R.color.chart_deep_sleep_light); AK_NOT_WORN_COLOR = getResources().getColor(R.color.chart_not_worn_light); + HEARTRATE_LABEL = getContext().getString(R.string.charts_legend_heartrate); + akActivity = new ActivityConfig(ActivityKind.TYPE_ACTIVITY, getString(R.string.abstract_chart_fragment_kind_activity), AK_ACTIVITY_COLOR); akLightSleep = new ActivityConfig(ActivityKind.TYPE_LIGHT_SLEEP, getString(R.string.abstract_chart_fragment_kind_light_sleep), AK_LIGHT_SLEEP_COLOR); akDeepSleep = new ActivityConfig(ActivityKind.TYPE_DEEP_SLEEP, getString(R.string.abstract_chart_fragment_kind_deep_sleep), AK_DEEP_SLEEP_COLOR); @@ -445,7 +449,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { colors.add(akActivity.color); } activityEntries.add(createBarEntry(value, i)); - if (hr) { + if (hr && isValidHeartRateValue(sample.getCustomValue())) { heartrateEntries.add(createLineEntry(sample.getCustomValue(), i)); } @@ -488,7 +492,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { barData.setGroupSpace(0); combinedData.setData(barData); - if (hr) { + if (hr && heartrateEntries.size() > 0) { LineDataSet heartrateSet = createHeartrateSet(heartrateEntries, "Heart Rate"); LineData lineData = new LineData(xLabels, heartrateSet); combinedData.setData(lineData); @@ -507,6 +511,10 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } } + protected boolean isValidHeartRateValue(int value) { + return value > 0 && value < 255; + } + /** * Implement this to supply the samples to be displayed. * @@ -550,14 +558,19 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { LineDataSet set1 = new LineDataSet(values, label); set1.setColor(HEARTRATE_COLOR); // set1.setColors(colors); -// set1.setDrawCubic(true); -// set1.setCubicIntensity(0.2f); + set1.setDrawCubic(true); + set1.setCubicIntensity(0.1f); // //set1.setDrawFilled(true); // set1.setDrawCircles(false); - set1.setLineWidth(2f); -// set1.setCircleSize(5f); +// set1.setLineWidth(2f); + + set1.setDrawCircles(false); +// set1.setCircleRadius(2f); +// set1.setDrawFilled(true); + + set1.setLineWidth(0.8f); // set1.setFillColor(ColorTemplate.getHoloBlue()); - set1.setDrawValues(false); + set1.setDrawValues(true); // set1.setHighLightColor(Color.rgb(128, 0, 255)); // set1.setColor(Color.rgb(89, 178, 44)); set1.setValueTextColor(CHART_TEXT_COLOR); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java index 608a6f2a..cd45452d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java @@ -70,6 +70,7 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { // y.setDrawLabels(false); // TODO: make fixed max value optional y.setAxisMaxValue(1f); + y.setAxisMinValue(0); y.setDrawTopYLabelEntry(false); y.setTextColor(CHART_TEXT_COLOR); @@ -82,6 +83,8 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { yAxisRight.setDrawLabels(true); yAxisRight.setDrawTopYLabelEntry(true); yAxisRight.setTextColor(CHART_TEXT_COLOR); + yAxisRight.setAxisMaxValue(250); + yAxisRight.setAxisMinValue(0); // refresh immediately instead of use refreshIfVisible(), for perceived performance refresh(); @@ -125,6 +128,10 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { legendLabels.add(akDeepSleep.label); legendColors.add(akNotWorn.color); legendLabels.add(akNotWorn.label); + if (supportsHeartrate()) { + legendColors.add(HEARTRATE_COLOR); + legendLabels.add(HEARTRATE_LABEL); + } chart.getLegend().setCustom(legendColors, legendLabels); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java index 6b9a7561..b0836eeb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java @@ -151,6 +151,7 @@ public class SleepChartFragment extends AbstractChartFragment { // y.setDrawLabels(false); // TODO: make fixed max value optional y.setAxisMaxValue(1f); + y.setAxisMinValue(0); y.setDrawTopYLabelEntry(false); y.setTextColor(CHART_TEXT_COLOR); @@ -159,10 +160,12 @@ public class SleepChartFragment extends AbstractChartFragment { YAxis yAxisRight = mActivityChart.getAxisRight(); yAxisRight.setDrawGridLines(false); - yAxisRight.setEnabled(false); - yAxisRight.setDrawLabels(false); - yAxisRight.setDrawTopYLabelEntry(false); + yAxisRight.setEnabled(supportsHeartrate()); + yAxisRight.setDrawLabels(true); + yAxisRight.setDrawTopYLabelEntry(true); yAxisRight.setTextColor(CHART_TEXT_COLOR); + yAxisRight.setAxisMaxValue(250); + yAxisRight.setAxisMinValue(0); } protected void setupLegend(Chart chart) { @@ -172,6 +175,10 @@ public class SleepChartFragment extends AbstractChartFragment { legendLabels.add(akLightSleep.label); legendColors.add(akDeepSleep.color); legendLabels.add(akDeepSleep.label); + if (supportsHeartrate()) { + legendColors.add(HEARTRATE_COLOR); + legendLabels.add(HEARTRATE_LABEL); + } chart.getLegend().setCustom(legendColors, legendLabels); chart.getLegend().setTextColor(LEGEND_TEXT_COLOR); } diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f5a0bc4f..8d5f07fd 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -11,7 +11,7 @@ #ff808080 #1f000000 - #b40000 + #ffab40 #0071b7 #4c5aff diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5c06b5a5..407d428f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -239,5 +239,6 @@ "HR: " Firmware update in progress Firmware not sent + Heart Rate From 34600e085e861083fa8326a200fdaecb712bca14 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Mon, 4 Apr 2016 23:13:57 +0200 Subject: [PATCH 29/43] Fix wrong assignment, needed to properly deal with datalog messages longer than 255 --- .../gadgetbridge/service/devices/pebble/PebbleProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 2f6f9236..d79f3d9f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -1876,7 +1876,7 @@ public class PebbleProtocol extends GBDeviceProtocol { int timestamp = buf.getInt(); int log_tag = buf.getInt(); byte item_type = buf.get(); - short item_size = buf.get(); + short item_size = buf.getShort(); LOG.info("DATALOG OPENSESSION. id=" + (id & 0xff) + ", App UUID=" + uuid.toString() + ", log_tag=" + log_tag + ", item_type=" + item_type + ", itemSize=" + item_size); if (!mDatalogSessions.containsKey(id)) { if (uuid.equals(UUID_ZERO) && log_tag == 81) { From 51def0d497c3cf05d6a1098fb8d5922e0fd720fb Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Mon, 4 Apr 2016 23:33:17 +0200 Subject: [PATCH 30/43] Add light intensity to the known steps datalog message. Add support for record version 6 introduced with firmware 3.11. There are more data in each record now, but we still do not know what they mean. Close #270 --- .../devices/pebble/DatalogSessionHealthSteps.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java index 81bb4319..f89f0363 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java @@ -46,7 +46,7 @@ public class DatalogSessionHealthSteps extends DatalogSession { recordVersion = datalogMessage.getShort(); - if (recordVersion != 5) + if ((recordVersion != 5) && (recordVersion != 6)) return false; //we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it timestamp = datalogMessage.getInt(); @@ -59,8 +59,7 @@ public class DatalogSessionHealthSteps extends DatalogSession { for (int recordIdx = 0; recordIdx < recordNum; recordIdx++) { datalogMessage.position(beginOfRecordPosition + recordIdx * recordLength); //we may not consume all the bytes of a record - stepsRecords[recordIdx] = new StepsRecord(timestamp, datalogMessage.get() & 0xff, datalogMessage.get() & 0xff, datalogMessage.getShort() & 0xffff); - datalogMessage.getShort(); // skip + stepsRecords[recordIdx] = new StepsRecord(timestamp, datalogMessage.get() & 0xff, datalogMessage.get() & 0xff, datalogMessage.getShort() & 0xffff, datalogMessage.get() & 0xff); timestamp += 60; } @@ -102,12 +101,14 @@ public class DatalogSessionHealthSteps extends DatalogSession { int steps; int orientation; int intensity; + int light_intensity; - public StepsRecord(int timestamp, int steps, int orientation, int intensity) { + public StepsRecord(int timestamp, int steps, int orientation, int intensity, int light_intensity) { this.timestamp = timestamp; this.steps = steps; this.orientation = orientation; this.intensity = intensity; + this.light_intensity = light_intensity; } } From e42a04144896c29c3aed9768d86635a05cf7b1c7 Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Wed, 6 Apr 2016 12:37:23 +0200 Subject: [PATCH 31/43] Pebble: Smarter reconnection attempts Sleep several seconds between reconnection attempts: One second after first attempt, two after the second, and so on. refs #89 --- .../service/devices/pebble/PebbleIoThread.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 504a3629..1c8b6606 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -365,12 +365,19 @@ public class PebbleIoThread extends GBDeviceIoThread { LOG.info(e.getMessage()); mIsConnected = false; int reconnectAttempts = Integer.valueOf(sharedPrefs.getString("pebble_reconnect_attempts", "10")); + int maxReconnectAttempts = reconnectAttempts; if (reconnectAttempts > 0) { gbDevice.setState(GBDevice.State.CONNECTING); gbDevice.sendDeviceUpdateIntent(getContext()); while (reconnectAttempts-- > 0 && !mQuit && !mIsConnected) { LOG.info("Trying to reconnect (attempts left " + reconnectAttempts + ")"); mIsConnected = connect(gbDevice.getAddress()); + if (!mIsConnected) { + try { + Thread.sleep((maxReconnectAttempts-reconnectAttempts)*1000); + } catch (InterruptedException ignored) { + } + } } } if (!mIsConnected && !mQuit) { From d2af3468f085effb1d75ed937711f43da0bc2df6 Mon Sep 17 00:00:00 2001 From: danielegobbetti Date: Wed, 6 Apr 2016 21:48:16 +0200 Subject: [PATCH 32/43] Add support for new datalog message added in pebble firmware 3.11 This adds support for storing deep sleep data. --- CHANGELOG.md | 3 + .../pebble/DatalogSessionHealthSleep.java | 93 +++++++++++++++++-- .../devices/pebble/PebbleProtocol.java | 2 +- app/src/main/res/xml/changelog_master.xml | 5 + 4 files changed, 93 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c691eebf..13335a92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ###Changelog +####Version (next) +* Pebble: support pebble health datalog messages of firmware 3.11 (this adds the support for deep sleep!) + ####Version 0.9.3 * Pebble: Fix Pebble Health activation (was not available in the App Manager) * Simplify connection state display (only connecting->connected) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java index 8528287f..aaa67ec3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java @@ -21,22 +21,33 @@ class DatalogSessionHealthSleep extends DatalogSession { public DatalogSessionHealthSleep(byte id, UUID uuid, int tag, byte item_type, short item_size) { super(id, uuid, tag, item_type, item_size); - taginfo = "(health - sleep)"; + taginfo = "(health - sleep " + tag + " )"; } @Override public boolean handleMessage(ByteBuffer datalogMessage, int length) { LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length)); + switch (this.tag) { + case 83: + return handleMessage83(datalogMessage, length); + case 84: + return handleMessage84(datalogMessage, length); + default: + return false; + } + } + private boolean handleMessage84(ByteBuffer datalogMessage, int length) { int initialPosition = datalogMessage.position(); int beginOfRecordPosition; short recordVersion; //probably + short recordType; //probably: 1=sleep, 2=deep sleep if (0 != (length % itemSize)) return false;//malformed message? int recordCount = length / itemSize; - SleepRecord[] sleepRecords = new SleepRecord[recordCount]; + SleepRecord84[] sleepRecords = new SleepRecord84[recordCount]; for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) { beginOfRecordPosition = initialPosition + recordIdx * itemSize; @@ -45,23 +56,73 @@ class DatalogSessionHealthSleep extends DatalogSession { if (recordVersion != 1) return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it - sleepRecords[recordIdx] = new SleepRecord(datalogMessage.getInt(), + datalogMessage.getShort();//throwaway, unknown + recordType = datalogMessage.getShort(); + + sleepRecords[recordIdx] = new SleepRecord84(recordType, datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt()); + } + + return store84(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. + } + + private boolean store84(SleepRecord84[] sleepRecords) { + DBHandler dbHandler = null; + SampleProvider sampleProvider = new HealthSampleProvider(); + try { + dbHandler = GBApplication.acquireDB(); + int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider); + for (SleepRecord84 sleepRecord : sleepRecords) { + if (latestTimestamp < (sleepRecord.timestampStart + sleepRecord.durationSeconds)) + return false; + int activityType = sleepRecord.type == 2 ? sampleProvider.toRawActivityKind(ActivityKind.TYPE_DEEP_SLEEP) : sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP); + + dbHandler.changeStoredSamplesType(sleepRecord.timestampStart, (sleepRecord.timestampStart + sleepRecord.durationSeconds), activityType, sampleProvider); + } + } catch (Exception ex) { + LOG.debug(ex.getMessage()); + } finally { + if (dbHandler != null) { + dbHandler.release(); + } + } + return true; + } + + private boolean handleMessage83(ByteBuffer datalogMessage, int length) { + int initialPosition = datalogMessage.position(); + int beginOfRecordPosition; + short recordVersion; //probably + + if (0 != (length % itemSize)) + return false;//malformed message? + + int recordCount = length / itemSize; + SleepRecord83[] sleepRecords = new SleepRecord83[recordCount]; + + for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) { + beginOfRecordPosition = initialPosition + recordIdx * itemSize; + datalogMessage.position(beginOfRecordPosition);//we may not consume all the bytes of a record + recordVersion = datalogMessage.getShort(); + if (recordVersion != 1) + return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it + + sleepRecords[recordIdx] = new SleepRecord83(datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt()); } - return store(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. + return store83(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. } - private boolean store(SleepRecord[] sleepRecords) { + private boolean store83(SleepRecord83[] sleepRecords) { DBHandler dbHandler = null; SampleProvider sampleProvider = new HealthSampleProvider(); - GB.toast("We don't know how to store deep sleep from the pebble yet.", Toast.LENGTH_LONG, GB.INFO); + GB.toast("Deep sleep is supported only from firmware 3.11 onwards.", Toast.LENGTH_LONG, GB.INFO); try { dbHandler = GBApplication.acquireDB(); int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider); - for (SleepRecord sleepRecord : sleepRecords) { + for (SleepRecord83 sleepRecord : sleepRecords) { if (latestTimestamp < sleepRecord.bedTimeEnd) return false; dbHandler.changeStoredSamplesType(sleepRecord.bedTimeStart, sleepRecord.bedTimeEnd, sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); @@ -76,17 +137,31 @@ class DatalogSessionHealthSleep extends DatalogSession { return true; } - private class SleepRecord { + private class SleepRecord83 { int offsetUTC; //probably int bedTimeStart; int bedTimeEnd; int deepSleepSeconds; - public SleepRecord(int offsetUTC, int bedTimeStart, int bedTimeEnd, int deepSleepSeconds) { + public SleepRecord83(int offsetUTC, int bedTimeStart, int bedTimeEnd, int deepSleepSeconds) { this.offsetUTC = offsetUTC; this.bedTimeStart = bedTimeStart; this.bedTimeEnd = bedTimeEnd; this.deepSleepSeconds = deepSleepSeconds; } } + + private class SleepRecord84 { + int type; //1=sleep, 2=deep sleep + int offsetUTC; //probably + int timestampStart; + int durationSeconds; + + public SleepRecord84(int type, int offsetUTC, int timestampStart, int durationSeconds) { + this.type = type; + this.offsetUTC = offsetUTC; + this.timestampStart = timestampStart; + this.durationSeconds = durationSeconds; + } + } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index d79f3d9f..5d261e6a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -1881,7 +1881,7 @@ public class PebbleProtocol extends GBDeviceProtocol { if (!mDatalogSessions.containsKey(id)) { if (uuid.equals(UUID_ZERO) && log_tag == 81) { mDatalogSessions.put(id, new DatalogSessionHealthSteps(id, uuid, log_tag, item_type, item_size)); - } else if (uuid.equals(UUID_ZERO) && log_tag == 83) { + } else if (uuid.equals(UUID_ZERO) && (log_tag == 83 || log_tag == 84)) { mDatalogSessions.put(id, new DatalogSessionHealthSleep(id, uuid, log_tag, item_type, item_size)); } else { mDatalogSessions.put(id, new DatalogSession(id, uuid, log_tag, item_type, item_size)); diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 0c25965e..8527cad6 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,5 +1,10 @@ + + Pebble: support pebble health datalog messages of firmware 3.11 (this adds the + support for deep sleep!) + + Pebble: Fix Pebble Health activation (was not available in the App Manager) Simplify connection state display (only connecting->connected) From 4055cc1173834b375ea404cf766f1024b929e320 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 6 Apr 2016 22:44:50 +0200 Subject: [PATCH 33/43] bump version --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a1f7b997..d0646fe5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { targetSdkVersion 23 // note: always bump BOTH versionCode and versionName! - versionName "0.9.3" - versionCode 47 + versionName "0.9.4" + versionCode 48 } buildTypes { release { From e91b5a07bd8b7e9db97abf989174825c6b32d4b6 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 6 Apr 2016 22:55:04 +0200 Subject: [PATCH 34/43] Pebble: change delay between reconects to 1,2,4,8,16,32,64 (max) seconds --- .../service/devices/pebble/PebbleIoThread.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 1c8b6606..b2a42630 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -365,18 +365,21 @@ public class PebbleIoThread extends GBDeviceIoThread { LOG.info(e.getMessage()); mIsConnected = false; int reconnectAttempts = Integer.valueOf(sharedPrefs.getString("pebble_reconnect_attempts", "10")); - int maxReconnectAttempts = reconnectAttempts; if (reconnectAttempts > 0) { gbDevice.setState(GBDevice.State.CONNECTING); gbDevice.sendDeviceUpdateIntent(getContext()); + int delaySeconds = 1; while (reconnectAttempts-- > 0 && !mQuit && !mIsConnected) { LOG.info("Trying to reconnect (attempts left " + reconnectAttempts + ")"); mIsConnected = connect(gbDevice.getAddress()); if (!mIsConnected) { try { - Thread.sleep((maxReconnectAttempts-reconnectAttempts)*1000); + Thread.sleep(delaySeconds * 1000); } catch (InterruptedException ignored) { } + if (delaySeconds < 64) { + delaySeconds *= 2; + } } } } From 10be21e07b813d0c02264e0035998f4043b5f408 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 6 Apr 2016 23:00:18 +0200 Subject: [PATCH 35/43] add Pebble stuff to CHANGELOG.md (Mi Band is still missing) --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13335a92..6d4d3b66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ ###Changelog ####Version (next) -* Pebble: support pebble health datalog messages of firmware 3.11 (this adds the support for deep sleep!) +* Pebble: support pebble health datalog messages of firmware 3.11 (this adds support for deep sleep!) +* Pebble: try to reconnect on new notifications and phone calls when connection was lost unexpectedly +* Pebble: delay between reconnection attempts (from 1 up to 64 seconds) ####Version 0.9.3 * Pebble: Fix Pebble Health activation (was not available in the App Manager) From c7b64b6da72802aec736d591210c8772ca3944ec Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 6 Apr 2016 23:03:56 +0200 Subject: [PATCH 36/43] update Japanese translation from transifex (thanks!) --- app/src/main/res/values-ja/strings.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 1ca2b0ed..6cf3ba01 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -102,7 +102,7 @@ 有効なユーザーデータはありません。今のところ、ダミーのユーザーデータを使用します。 お使いのMi Bandが振動と点滅したとき、それを連続して数回タップしてください。 インストール - お使いのデバイスを検出可能にしてください。現在、接続されたデバイスは、おそらく検出されません。 + お使いのデバイスを検出可能にしてください。現在、接続されたデバイスは、おそらく検出されません。お使いのデバイスが 2 分しても表示されない場合は、モバイルデバイスを再起動した後にもう一度試してください。 注: デバイスイメージ 名前/別名 @@ -197,6 +197,7 @@ 非互換性のファームウェア このファームウェアは、デバイスと互換性がありません 今後のイベントのために予約するアラーム + 睡眠の検出を改善するために心拍センサーを使用する 再接続の待機中 再インストール あなたについて @@ -217,4 +218,6 @@ FW: %1$s ログファイルのディレクトリを作成中にエラー: %1$s HR: + ファームウェアを更新しています + ファームウェアを送信しませんでした From 6895c5b77643f94efd7b29d095db2018b04f23f3 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 6 Apr 2016 23:29:59 +0200 Subject: [PATCH 37/43] fix xml changelog --- app/src/main/res/xml/changelog_master.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 8527cad6..dddd9bab 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,15 +1,15 @@ - - Pebble: support pebble health datalog messages of firmware 3.11 (this adds the - support for deep sleep!) - + + Pebble: support pebble health datalog messages of firmware 3.11 (this adds support for deep sleep!) + Pebble: try to reconnect on new notifications and phone calls when connection was lost unexpectedly + Pebble: delay between reconnection attempts (from 1 up to 64 seconds) - Pebble: Fix Pebble Health activation (was not available in the App Manager) - Simplify connection state display (only connecting->connected) - Small improvements to the pairing activity - Mi Band 1S: Fix for mi band firmware update + Pebble: Fix Pebble Health activation (was not available in the App Manager) + Simplify connection state display (only connecting->connected) + Small improvements to the pairing activity + Mi Band 1S: Fix for mi band firmware update Mi Band: Fix update of second (HR) firmware on Mi1S (#234) From b1a93c430d006abde8932af955e7ae773f1cff41 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 7 Apr 2016 00:21:21 +0200 Subject: [PATCH 38/43] interrupt thread instead of joining to fix ANR --- .../service/serial/AbstractSerialDeviceSupport.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index 5d3bd610..aa78a393 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -48,11 +48,7 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport // currently only one thread allowed if (gbDeviceIOThread != null) { gbDeviceIOThread.quit(); - try { - gbDeviceIOThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } + gbDeviceIOThread.interrupt(); gbDeviceIOThread = null; } } From a49335fa67188aa55d429f04d59a9b1a5f59c102 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Thu, 7 Apr 2016 17:52:15 +0200 Subject: [PATCH 39/43] Allow to change stored samples converting only certain old types --- .../database/ActivityDatabaseHandler.java | 18 ++++++++++++++++++ .../gadgetbridge/database/DBHandler.java | 2 ++ .../pebble/DatalogSessionHealthSleep.java | 9 ++++++--- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java index f8812b30..ce9e1ae4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java @@ -275,6 +275,24 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl } } + @Override + public void changeStoredSamplesType(int timestampFrom, int timestampTo, int fromKind, int toKind, SampleProvider provider) { + try (SQLiteDatabase db = this.getReadableDatabase()) { + String sql = "UPDATE " + TABLE_GBACTIVITYSAMPLES + " SET " + KEY_TYPE + "= ? WHERE " + + KEY_TYPE + " = ? AND " + + KEY_PROVIDER + " = ? AND " + + KEY_TIMESTAMP + " >= ? AND " + KEY_TIMESTAMP + " < ? ;"; //do not use BETWEEN because the range is inclusive in that case! + + SQLiteStatement statement = db.compileStatement(sql); + statement.bindLong(1, toKind); + statement.bindLong(2, fromKind); + statement.bindLong(3, provider.getID()); + statement.bindLong(4, timestampFrom); + statement.bindLong(5, timestampTo); + statement.execute(); + } + } + @Override public int fetchLatestTimestamp(SampleProvider provider) { try (SQLiteDatabase db = this.getReadableDatabase()) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java index 42aa64de..49dbbd40 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java @@ -32,6 +32,8 @@ public interface DBHandler { void changeStoredSamplesType(int timestampFrom, int timestampTo, int kind, SampleProvider provider); + void changeStoredSamplesType(int timestampFrom, int timestampTo, int fromKind, int toKind, SampleProvider provider); + int fetchLatestTimestamp(SampleProvider provider); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java index aaa67ec3..7d06876f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java @@ -74,9 +74,12 @@ class DatalogSessionHealthSleep extends DatalogSession { for (SleepRecord84 sleepRecord : sleepRecords) { if (latestTimestamp < (sleepRecord.timestampStart + sleepRecord.durationSeconds)) return false; - int activityType = sleepRecord.type == 2 ? sampleProvider.toRawActivityKind(ActivityKind.TYPE_DEEP_SLEEP) : sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP); + if (sleepRecord.type == 2) { + dbHandler.changeStoredSamplesType(sleepRecord.timestampStart, (sleepRecord.timestampStart + sleepRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_DEEP_SLEEP), sampleProvider); + } else { + dbHandler.changeStoredSamplesType(sleepRecord.timestampStart, (sleepRecord.timestampStart + sleepRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); + } - dbHandler.changeStoredSamplesType(sleepRecord.timestampStart, (sleepRecord.timestampStart + sleepRecord.durationSeconds), activityType, sampleProvider); } } catch (Exception ex) { LOG.debug(ex.getMessage()); @@ -125,7 +128,7 @@ class DatalogSessionHealthSleep extends DatalogSession { for (SleepRecord83 sleepRecord : sleepRecords) { if (latestTimestamp < sleepRecord.bedTimeEnd) return false; - dbHandler.changeStoredSamplesType(sleepRecord.bedTimeStart, sleepRecord.bedTimeEnd, sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); + dbHandler.changeStoredSamplesType(sleepRecord.bedTimeStart, sleepRecord.bedTimeEnd, sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); } } catch (Exception ex) { LOG.debug(ex.getMessage()); From 1e5dbb6a239895983c59fa76ac7ff916681f9067 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 7 Apr 2016 20:52:26 +0200 Subject: [PATCH 40/43] OK, just connect(true) is not sufficient #249 (we again get connection problems. Let's try this.) --- .../freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index b31ba1d2..4839a992 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -157,11 +157,12 @@ public final class BtLEQueue { LOG.info("Attempting to connect to " + mGbDevice.getName()); mBluetoothAdapter.cancelDiscovery(); BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(mGbDevice.getAddress()); + boolean result; synchronized (mGattMonitor) { mBluetoothGatt = remoteDevice.connectGatt(mContext, true, internalGattCallback); -// result = mBluetoothGatt.connect(); + result = mBluetoothGatt.connect(); } - boolean result = mBluetoothGatt != null; +// boolean result = mBluetoothGatt != null; if (result) { setDeviceConnectionState(State.CONNECTING); } From 3953e4232d2bb36d600e440f519f18bfe0f6f72b Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 7 Apr 2016 20:52:55 +0200 Subject: [PATCH 41/43] Update gradle build tools to 2.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6d40ae25..cce93864 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.5.0' + classpath 'com.android.tools.build:gradle:2.0.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files From 059c7d0b15ec17c38db29dc97f08b70d5cf35487 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Fri, 8 Apr 2016 22:28:06 +0200 Subject: [PATCH 42/43] Hopefully fix travis jdk7 build (permgen space issue) --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index a73f784f..38045ed0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,12 @@ language: android + jdk: - oraclejdk8 - oraclejdk7 + +env: + - GRADLE_OPTS="-XX:MaxPermSize=256m" + android: components: # Uncomment the lines below if you want to From 42dda911e46f72bb3f5ddd59d1a752a745f452e2 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Fri, 8 Apr 2016 23:02:50 +0200 Subject: [PATCH 43/43] Fix crash in charts activity, closes #277 --- .../activities/charts/AbstractChartFragment.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index 13bbc2c0..f163ba65 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -4,6 +4,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; @@ -80,6 +81,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { }; private boolean mChartDirty = true; private boolean supportsHeartrateChart = true; + private AsyncTask refreshTask; public boolean isChartDirty() { return mChartDirty; @@ -367,7 +369,10 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { if (chartsHost.getDevice() != null) { mChartDirty = false; updateDateInfo(getStartDate(), getEndDate()); - createRefreshTask("Visualizing data", getActivity()).execute(); + if (refreshTask != null && refreshTask.getStatus() != AsyncTask.Status.FINISHED) { + refreshTask.cancel(true); + } + refreshTask = createRefreshTask("Visualizing data", getActivity()).execute(); } } }