From b300534c32ddf14c04d372b9138abdb01989bab6 Mon Sep 17 00:00:00 2001 From: Mikael Vallerie Date: Tue, 12 Mar 2019 10:48:08 +0100 Subject: [PATCH 1/7] Initial impl. for Mi Band 2 'custom menu' --- .../devices/miband/MiBandConst.java | 2 + .../service/devices/huami/HuamiSupport.java | 154 +++++++++++++++++- .../Mi2CustomMenuNotificationStrategy.java | 60 +++++++ app/src/main/res/values/strings.xml | 4 + app/src/main/res/xml/miband_preferences.xml | 28 +++- 5 files changed, 242 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband2/Mi2CustomMenuNotificationStrategy.java 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 29608fc459..a124cd8a2b 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 @@ -32,6 +32,8 @@ public final class MiBandConst { public static final String PREF_MIBAND_ALARMS = "mi_alarms"; 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_BUTTON_ACTION_MENU_ENABLE = "mi2_enable_button_action_menu"; + public static final String PREF_MIBAND_MENU_ELEMENTS = "mi2_menu_elements"; public static final String PREF_MIBAND_BUTTON_ACTION_ENABLE = "mi2_enable_button_action"; public static final String PREF_MIBAND_BUTTON_ACTION_VIBRATE = "mi2_button_action_vibrate"; public static final String PREF_MIBAND_BUTTON_PRESS_COUNT = "mi_button_press_count"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index c9ca6d1f8b..b688797972 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -104,6 +104,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile; import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.actions.StopNotificationAction; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband2.Mi2CustomMenuNotificationStrategy; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband2.Mi2NotificationStrategy; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband2.Mi2TextNotificationStrategy; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.FetchActivityOperation; @@ -147,6 +148,10 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { private static long currentButtonPressTime = 0; private static long currentButtonTimerActivationTime = 0; + private static Boolean browsingCustomMenu = false; + private static int currentOptionId = 0; + private static Timer customMenuTimer = null; + private static final Logger LOG = LoggerFactory.getLogger(HuamiSupport.class); private final DeviceInfoProfile deviceInfoProfile; private final IntentListener mListener = new IntentListener() { @@ -340,7 +345,9 @@ public NotificationStrategy getNotificationStrategy() { return new Mi2NotificationStrategy(this); } } - if (GBApplication.getPrefs().getBoolean(MiBandConst.PREF_MI2_ENABLE_TEXT_NOTIFICATIONS, true)) { + if (browsingCustomMenu) { + return new Mi2CustomMenuNotificationStrategy(this); + } else if (GBApplication.getPrefs().getBoolean(MiBandConst.PREF_MI2_ENABLE_TEXT_NOTIFICATIONS, true)) { return new Mi2TextNotificationStrategy(this); } return new Mi2NotificationStrategy(this); @@ -1050,6 +1057,97 @@ public void runButtonAction() { currentButtonPressTime = System.currentTimeMillis(); } + public void runCustomMenu() { + Prefs prefs = GBApplication.getPrefs(); + + + if(this.getCustomMenuElements().length > 0) { + browsingCustomMenu = true; + if (currentButtonTimerActivationTime != currentButtonPressTime) { + return; + } + + this.displayCustomMenuOption(0); + + currentButtonPressCount = 0; + currentButtonPressTime = System.currentTimeMillis(); + } + } + + private void displayCustomMenuOption(int optionId) { + Prefs prefs = GBApplication.getPrefs(); + + currentOptionId = optionId; + + String eltLabel = this.getCustomMenuCurrentElement()[0]; + LOG.info("Sending Menu Option " + eltLabel); + try { + TransactionBuilder builder = performInitialized("sending menu option #" + eltLabel); + VibrationProfile profile = getPreferredVibrateProfile("Custom Menu", prefs, (short) 0); + profile.setAlertLevel(HuamiService.ALERT_LEVEL_MESSAGE); + SimpleNotification simpleNotification = new SimpleNotification(eltLabel, null, null/*NotificationType.UNKNOWN*/); + sendCustomNotification(profile, simpleNotification, 0, 0, 0, 0, null, builder); + builder.queue(getQueue()); + } catch (IOException ex) { + LOG.error("Unable to send notification to MI device", ex); + } + } + + private void runCustomMenuCurrentAction() { + Prefs prefs = GBApplication.getPrefs(); + + /*if (currentButtonTimerActivationTime != currentButtonPressTime) { + return; + }*/ + + String elementMessage = this.getCustomMenuCurrentElement()[1]; + Intent in = new Intent(); + in.setAction(elementMessage); + in.putExtra("button_id", currentButtonActionId); + LOG.info("Sending " + elementMessage + " with button_id " + currentButtonActionId); + this.getContext().getApplicationContext().sendBroadcast(in); + + LOG.info("Sending Confirmation"); + try { + TransactionBuilder builder = performInitialized("sending custom menu action confirmation"); + VibrationProfile profile = getPreferredVibrateProfile("Custom Menu", prefs, (short) 0); + profile.setAlertLevel(HuamiService.ALERT_LEVEL_MESSAGE); + SimpleNotification simpleNotification = new SimpleNotification("OK", null, null/*NotificationType.UNKNOWN*/); + sendCustomNotification(profile, simpleNotification, 0, 0, 0, 0, null, builder); + builder.queue(getQueue()); + } catch (IOException ex) { + LOG.error("Unable to send notification to MI device", ex); + } + + browsingCustomMenu = false; + + currentButtonActionId = 0; + + currentButtonPressCount = 0; + currentButtonPressTime = System.currentTimeMillis(); + } + + // TODO custom separator ? + private String[] getCustomMenuElements() { + Prefs prefs = GBApplication.getPrefs(); + return prefs.getString(MiBandConst.PREF_MIBAND_MENU_ELEMENTS, "").split(";"); + } + + // TODO custom separator ? + private String[] getCustomMenuCurrentElement() { + return getCustomMenuElements()[currentOptionId].split(":"); + } + + private int getCustomMenuNextOptionId() { + int menuElementCount = this.getCustomMenuElements().length; + return (currentOptionId + 1) % menuElementCount; + } + + private int getCustomMenuPreviousOptionId() { + int menuElementCount = this.getCustomMenuElements().length; + return (menuElementCount + currentOptionId - 1) % menuElementCount; + } + public void handleDeviceEvent(byte[] value) { if (value == null || value.length == 0) { return; @@ -1172,6 +1270,13 @@ public void handleButtonEvent() { if (requiredButtonPressCount > 0) { long timeSinceLastPress = System.currentTimeMillis() - currentButtonPressTime; + // TODO Mi band 2 seems to display notifications only during 5 secs + // This isn't very clean, but i couldn't find anything else. + if (timeSinceLastPress > 5000) { + LOG.info("Deactivating custom menu due to timeout"); + browsingCustomMenu = false; + } + if ((currentButtonPressTime == 0) || (timeSinceLastPress < buttonPressMaxDelay)) { currentButtonPressCount++; } @@ -1181,25 +1286,64 @@ public void handleButtonEvent() { } currentButtonPressTime = System.currentTimeMillis(); - if (currentButtonPressCount == requiredButtonPressCount) { + if (currentButtonPressCount == requiredButtonPressCount && !browsingCustomMenu) { currentButtonTimerActivationTime = currentButtonPressTime; + + final Boolean isCustomMenuEnabled = prefs.getBoolean(MiBandConst.PREF_MIBAND_BUTTON_ACTION_MENU_ENABLE, false); + if (buttonActionDelay > 0) { LOG.info("Activating timer"); final Timer buttonActionTimer = new Timer("Mi Band Button Action Timer"); buttonActionTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { - runButtonAction(); + if (isCustomMenuEnabled) { + runCustomMenu(); + } else { + runButtonAction(); + } buttonActionTimer.cancel(); } }, buttonActionDelay, buttonActionDelay); } else { - LOG.info("Activating button action"); - runButtonAction(); + if (isCustomMenuEnabled) { + LOG.info("Activating custom menu"); + runCustomMenu(); + } else { + LOG.info("Activating button action"); + runButtonAction(); + } } + currentButtonActionId++; currentButtonPressCount = 0; + } else if (browsingCustomMenu) { + if (customMenuTimer != null) { + customMenuTimer.cancel(); + } + customMenuTimer = new Timer("Mi Band Button Action Custom Menu Timer"); + final Timer buttonActionCustomMenuTimer = customMenuTimer; + buttonActionCustomMenuTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + if (currentButtonPressCount == 1) { + displayCustomMenuOption(getCustomMenuNextOptionId()); + currentButtonActionId++; + currentButtonPressCount = 0; + } else if (currentButtonPressCount == 2) { + displayCustomMenuOption(getCustomMenuPreviousOptionId()); + currentButtonActionId++; + currentButtonPressCount = 0; + } else if (currentButtonPressCount == 3) { + LOG.info("Selected action on custom menu"); + runCustomMenuCurrentAction(); + currentButtonActionId++; + currentButtonPressCount = 0; + } + buttonActionCustomMenuTimer.cancel(); + } + }, buttonPressMaxDelay, buttonPressMaxDelay); } } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband2/Mi2CustomMenuNotificationStrategy.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband2/Mi2CustomMenuNotificationStrategy.java new file mode 100644 index 0000000000..cb52aab983 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband2/Mi2CustomMenuNotificationStrategy.java @@ -0,0 +1,60 @@ +/* Copyright (C) 2017-2019 Andreas Shimokawa, Carsten Pfeiffer, Daniele + Gobbetti + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband2; + +import android.bluetooth.BluetoothGattCharacteristic; + +import androidx.annotation.NonNull; +import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile; +import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; +import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction; +import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic; +import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.NewAlert; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.OverflowStrategy; +import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiIcon; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport; +import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; + +public class Mi2CustomMenuNotificationStrategy extends Mi2NotificationStrategy { + public Mi2CustomMenuNotificationStrategy(HuamiSupport support) { + super(support); + } + + @Override + protected void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, BtLEAction extraAction, TransactionBuilder builder) { + // announce text messages with configured alerts first + // TODO this seems non-necessary + //super.sendCustomNotification(vibrationProfile, simpleNotification, extraAction, builder); + // and finally send the text message, if any + if (simpleNotification != null && !StringUtils.isEmpty(simpleNotification.getMessage())) { + sendAlert(simpleNotification, builder); + } + } + + protected void sendAlert(@NonNull SimpleNotification simpleNotification, TransactionBuilder builder) { + AlertNotificationProfile profile = new AlertNotificationProfile<>(getSupport()); + // override the alert category, since only SMS and incoming call support text notification + AlertCategory category = AlertCategory.SMS; + NewAlert alert = new NewAlert(category, 1, simpleNotification.getMessage()); + profile.newAlert(builder, alert, OverflowStrategy.MAKE_MULTIPLE); + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index caf9172cea..b50df01de9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -435,6 +435,10 @@ Disconnect notification Button actions Specify actions on Mi Band 2 button press + Custom Menu + Create a custom menu on Mi Band 2 + Menu Elements + The elements of your menu (label1:message1;label2:message2;...) Button press count Number of button presses to trigger message broadcast Broadcast message to send diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index 5a8b262f13..ac57ae6f16 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -84,6 +84,32 @@ android:key="mi_button_press_count_match_delay" android:summary="@string/mi2_prefs_button_press_count_match_delay_summary" android:title="@string/mi2_prefs_button_press_count_match_delay" /> + + + + + + + + + + + - \ No newline at end of file + From da9efd2ef55a9769ab3d88fbc8ecb90ee4a20311 Mon Sep 17 00:00:00 2001 From: Mikael Vallerie Date: Thu, 14 Mar 2019 02:54:31 +0100 Subject: [PATCH 2/7] Bugfix : make menu usable even if phone is slow to send the Menu Option --- .../gadgetbridge/service/devices/huami/HuamiSupport.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index b688797972..661ffbc7b3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -1068,9 +1068,6 @@ public void runCustomMenu() { } this.displayCustomMenuOption(0); - - currentButtonPressCount = 0; - currentButtonPressTime = System.currentTimeMillis(); } } @@ -1090,6 +1087,9 @@ private void displayCustomMenuOption(int optionId) { builder.queue(getQueue()); } catch (IOException ex) { LOG.error("Unable to send notification to MI device", ex); + } finally { + currentButtonPressCount = 0; + currentButtonPressTime = System.currentTimeMillis(); } } From 0ad9ec7c4da016e5b75407720362404f8d787c0a Mon Sep 17 00:00:00 2001 From: Mikael Vallerie Date: Thu, 14 Mar 2019 03:19:48 +0100 Subject: [PATCH 3/7] Configurable controls for Mi Band 2 custom menu --- .../devices/miband/MiBandConst.java | 3 +++ .../service/devices/huami/HuamiSupport.java | 10 ++++--- app/src/main/res/values/strings.xml | 6 +++++ app/src/main/res/xml/miband_preferences.xml | 26 ++++++++++++++++++- 4 files changed, 41 insertions(+), 4 deletions(-) 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 a124cd8a2b..ebeca84cf3 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 @@ -34,6 +34,9 @@ public final class MiBandConst { public static final String PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR = "mi_reserve_alarm_calendar"; public static final String PREF_MIBAND_BUTTON_ACTION_MENU_ENABLE = "mi2_enable_button_action_menu"; public static final String PREF_MIBAND_MENU_ELEMENTS = "mi2_menu_elements"; + public static final String PREF_MIBAND_MENU_FORWARD = "mi2_menu_forward"; + public static final String PREF_MIBAND_MENU_BACKWARD = "mi2_menu_backward"; + public static final String PREF_MIBAND_MENU_VALIDATE = "mi2_menu_validate"; public static final String PREF_MIBAND_BUTTON_ACTION_ENABLE = "mi2_enable_button_action"; public static final String PREF_MIBAND_BUTTON_ACTION_VIBRATE = "mi2_button_action_vibrate"; public static final String PREF_MIBAND_BUTTON_PRESS_COUNT = "mi_button_press_count"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index 661ffbc7b3..c269005414 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -1323,19 +1323,23 @@ public void run() { customMenuTimer.cancel(); } customMenuTimer = new Timer("Mi Band Button Action Custom Menu Timer"); + final int moveForwardTapCount = prefs.getInt(MiBandConst.PREF_MIBAND_MENU_FORWARD, 1); + final int moveBackwardTapCount = prefs.getInt(MiBandConst.PREF_MIBAND_MENU_BACKWARD, 2); + final int validateTapCount = prefs.getInt(MiBandConst.PREF_MIBAND_MENU_VALIDATE, 3); + final Timer buttonActionCustomMenuTimer = customMenuTimer; buttonActionCustomMenuTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { - if (currentButtonPressCount == 1) { + if (currentButtonPressCount == moveForwardTapCount) { displayCustomMenuOption(getCustomMenuNextOptionId()); currentButtonActionId++; currentButtonPressCount = 0; - } else if (currentButtonPressCount == 2) { + } else if (currentButtonPressCount == moveBackwardTapCount) { displayCustomMenuOption(getCustomMenuPreviousOptionId()); currentButtonActionId++; currentButtonPressCount = 0; - } else if (currentButtonPressCount == 3) { + } else if (currentButtonPressCount == validateTapCount) { LOG.info("Selected action on custom menu"); runCustomMenuCurrentAction(); currentButtonActionId++; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b50df01de9..0ac1388a00 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -439,6 +439,12 @@ Create a custom menu on Mi Band 2 Menu Elements The elements of your menu (label1:message1;label2:message2;...) + Move forward + How many taps to move forward in the menu + Move backward + How many taps to move backward in the menu + Validate current option + How many taps to confirm selected menu option Button press count Number of button presses to trigger message broadcast Broadcast message to send diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index ac57ae6f16..4e6f8ae794 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -103,12 +103,36 @@ android:title="@string/mi2_prefs_button_action_menu" /> + + + + + + From 2ef0024e02a1f95b273c62a4a92303b2526294b6 Mon Sep 17 00:00:00 2001 From: Mikael Vallerie Date: Thu, 14 Mar 2019 09:08:58 +0100 Subject: [PATCH 4/7] Mi band 2 custom menu : WAKE_LOCK authorization. Acquiring the wake lock only when enabled in settings and when browsing the custom menu. --- app/src/main/AndroidManifest.xml | 1 + .../devices/miband/MiBandConst.java | 1 + .../service/devices/huami/HuamiSupport.java | 70 +++++++++++++++---- app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/miband_preferences.xml | 6 ++ 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9597b4a212..6ce050552c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,6 +21,7 @@ + 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 ebeca84cf3..671dc95622 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 @@ -37,6 +37,7 @@ public final class MiBandConst { public static final String PREF_MIBAND_MENU_FORWARD = "mi2_menu_forward"; public static final String PREF_MIBAND_MENU_BACKWARD = "mi2_menu_backward"; public static final String PREF_MIBAND_MENU_VALIDATE = "mi2_menu_validate"; + public static final String PREF_MIBAND_MENU_WAKELOCK = "mi2_menu_wakelock"; public static final String PREF_MIBAND_BUTTON_ACTION_ENABLE = "mi2_enable_button_action"; public static final String PREF_MIBAND_BUTTON_ACTION_VIBRATE = "mi2_button_action_vibrate"; public static final String PREF_MIBAND_BUTTON_PRESS_COUNT = "mi_button_press_count"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index c269005414..89a708136a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.PowerManager; import android.text.format.DateFormat; import android.widget.Toast; @@ -151,6 +152,11 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { private static Boolean browsingCustomMenu = false; private static int currentOptionId = 0; private static Timer customMenuTimer = null; + private static Timer customMenuTimerTimeout = null; + + // To make Timers work correctly when Android device is in deep sleep + // @see https://stackoverflow.com/questions/47472741/timer-not-expiring-precisely-during-sleep-state-in-android + private static PowerManager.WakeLock deviceWakeLock = null; private static final Logger LOG = LoggerFactory.getLogger(HuamiSupport.class); private final DeviceInfoProfile deviceInfoProfile; @@ -1148,6 +1154,32 @@ private int getCustomMenuPreviousOptionId() { return (menuElementCount + currentOptionId - 1) % menuElementCount; } + private Timer resetCustomMenuTimerTimeout() { + Prefs prefs = GBApplication.getPrefs(); + final Boolean isWakelockEnabled = prefs.getBoolean(MiBandConst.PREF_MIBAND_MENU_WAKELOCK, false); + + if(customMenuTimerTimeout != null) { + customMenuTimerTimeout.cancel(); + } + + // TODO Mi band 2 seems to display notifications only during 5 secs + // This isn't very clean, but i couldn't find anything else. + customMenuTimerTimeout = new Timer("Mi Band Button Action Custom Menu Timeout Timer"); + customMenuTimerTimeout.schedule(new TimerTask() { + @Override + public void run() { + LOG.info("Deactivating custom menu due to timeout"); + browsingCustomMenu = false; + if (isWakelockEnabled && deviceWakeLock != null && deviceWakeLock.isHeld()) { + LOG.info("Releasing Wakelock"); + deviceWakeLock.release(); + } + customMenuTimerTimeout.cancel(); + } + }, 5000); + return customMenuTimerTimeout; + } + public void handleDeviceEvent(byte[] value) { if (value == null || value.length == 0) { return; @@ -1267,16 +1299,12 @@ public void handleButtonEvent() { int buttonActionDelay = prefs.getInt(MiBandConst.PREF_MIBAND_BUTTON_ACTION_DELAY, 0); int requiredButtonPressCount = prefs.getInt(MiBandConst.PREF_MIBAND_BUTTON_PRESS_COUNT, 0); + final Boolean isCustomMenuEnabled = prefs.getBoolean(MiBandConst.PREF_MIBAND_BUTTON_ACTION_MENU_ENABLE, false); + final Boolean isWakelockEnabled = prefs.getBoolean(MiBandConst.PREF_MIBAND_MENU_WAKELOCK, false); + if (requiredButtonPressCount > 0) { long timeSinceLastPress = System.currentTimeMillis() - currentButtonPressTime; - // TODO Mi band 2 seems to display notifications only during 5 secs - // This isn't very clean, but i couldn't find anything else. - if (timeSinceLastPress > 5000) { - LOG.info("Deactivating custom menu due to timeout"); - browsingCustomMenu = false; - } - if ((currentButtonPressTime == 0) || (timeSinceLastPress < buttonPressMaxDelay)) { currentButtonPressCount++; } @@ -1289,15 +1317,22 @@ public void handleButtonEvent() { if (currentButtonPressCount == requiredButtonPressCount && !browsingCustomMenu) { currentButtonTimerActivationTime = currentButtonPressTime; - final Boolean isCustomMenuEnabled = prefs.getBoolean(MiBandConst.PREF_MIBAND_BUTTON_ACTION_MENU_ENABLE, false); - if (buttonActionDelay > 0) { LOG.info("Activating timer"); + final Timer buttonActionTimer = new Timer("Mi Band Button Action Timer"); buttonActionTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { if (isCustomMenuEnabled) { + if(isWakelockEnabled) { + LOG.info("Acquiring wakelock"); + PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); + deviceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport:wakelock"); + deviceWakeLock.acquire(); + } + + resetCustomMenuTimerTimeout(); runCustomMenu(); } else { runButtonAction(); @@ -1322,32 +1357,39 @@ public void run() { if (customMenuTimer != null) { customMenuTimer.cancel(); } - customMenuTimer = new Timer("Mi Band Button Action Custom Menu Timer"); + final int moveForwardTapCount = prefs.getInt(MiBandConst.PREF_MIBAND_MENU_FORWARD, 1); final int moveBackwardTapCount = prefs.getInt(MiBandConst.PREF_MIBAND_MENU_BACKWARD, 2); final int validateTapCount = prefs.getInt(MiBandConst.PREF_MIBAND_MENU_VALIDATE, 3); - final Timer buttonActionCustomMenuTimer = customMenuTimer; - buttonActionCustomMenuTimer.scheduleAtFixedRate(new TimerTask() { + customMenuTimer = new Timer("Mi Band Button Action Custom Menu Timer"); + customMenuTimer.schedule(new TimerTask() { @Override public void run() { if (currentButtonPressCount == moveForwardTapCount) { + resetCustomMenuTimerTimeout(); displayCustomMenuOption(getCustomMenuNextOptionId()); currentButtonActionId++; currentButtonPressCount = 0; } else if (currentButtonPressCount == moveBackwardTapCount) { + resetCustomMenuTimerTimeout(); displayCustomMenuOption(getCustomMenuPreviousOptionId()); currentButtonActionId++; currentButtonPressCount = 0; } else if (currentButtonPressCount == validateTapCount) { + customMenuTimerTimeout.cancel(); LOG.info("Selected action on custom menu"); runCustomMenuCurrentAction(); currentButtonActionId++; currentButtonPressCount = 0; + if (isWakelockEnabled && deviceWakeLock != null && deviceWakeLock.isHeld()) { + LOG.info("Releasing wakelock"); + deviceWakeLock.release(); + } } - buttonActionCustomMenuTimer.cancel(); + customMenuTimer.cancel(); } - }, buttonPressMaxDelay, buttonPressMaxDelay); + }, buttonPressMaxDelay); } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0ac1388a00..6f9ce777fa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -445,6 +445,8 @@ How many taps to move backward in the menu Validate current option How many taps to confirm selected menu option + Enable WakeLock + Enable if you have issues when phone sleeps. WARNING : this may reduce your battery life. Button press count Number of button presses to trigger message broadcast Broadcast message to send diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index 4e6f8ae794..0503d6222e 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -133,6 +133,12 @@ android:summary="@string/mi2_prefs_menu_validate_summary" android:title="@string/mi2_prefs_menu_validate" /> + + From 762a32e9c312eaa0282b84a27fa4bc34c08b2385 Mon Sep 17 00:00:00 2001 From: Mikael Vallerie Date: Thu, 14 Mar 2019 11:15:55 +0100 Subject: [PATCH 5/7] Bugfixes for corner cases --- .../service/devices/huami/HuamiSupport.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index 89a708136a..1b686d36bc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -1072,7 +1072,7 @@ public void runCustomMenu() { if (currentButtonTimerActivationTime != currentButtonPressTime) { return; } - + currentButtonActionId = 0; this.displayCustomMenuOption(0); } } @@ -1123,14 +1123,13 @@ private void runCustomMenuCurrentAction() { builder.queue(getQueue()); } catch (IOException ex) { LOG.error("Unable to send notification to MI device", ex); - } - - browsingCustomMenu = false; - - currentButtonActionId = 0; + } finally { + browsingCustomMenu = false; + currentButtonActionId = 0; - currentButtonPressCount = 0; - currentButtonPressTime = System.currentTimeMillis(); + currentButtonPressCount = 0; + currentButtonPressTime = System.currentTimeMillis(); + } } // TODO custom separator ? @@ -1377,6 +1376,7 @@ public void run() { currentButtonActionId++; currentButtonPressCount = 0; } else if (currentButtonPressCount == validateTapCount) { + currentButtonTimerActivationTime = currentButtonPressTime; customMenuTimerTimeout.cancel(); LOG.info("Selected action on custom menu"); runCustomMenuCurrentAction(); From c794201fc15818f218fc1084b6f312c617830590 Mon Sep 17 00:00:00 2001 From: Mikael Vallerie Date: Thu, 14 Mar 2019 14:53:20 +0100 Subject: [PATCH 6/7] More bugfixes --- .../service/devices/huami/HuamiSupport.java | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index 1b686d36bc..870e9cf935 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -1068,10 +1068,11 @@ public void runCustomMenu() { if(this.getCustomMenuElements().length > 0) { - browsingCustomMenu = true; - if (currentButtonTimerActivationTime != currentButtonPressTime) { + /*if (currentButtonTimerActivationTime != currentButtonPressTime) { return; - } + }*/ + LOG.info("Running custom menu"); + browsingCustomMenu = true; currentButtonActionId = 0; this.displayCustomMenuOption(0); } @@ -1320,36 +1321,39 @@ public void handleButtonEvent() { LOG.info("Activating timer"); final Timer buttonActionTimer = new Timer("Mi Band Button Action Timer"); - buttonActionTimer.scheduleAtFixedRate(new TimerTask() { + buttonActionTimer.schedule(new TimerTask() { @Override public void run() { - if (isCustomMenuEnabled) { - if(isWakelockEnabled) { - LOG.info("Acquiring wakelock"); - PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); - deviceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport:wakelock"); - deviceWakeLock.acquire(); - } - - resetCustomMenuTimerTimeout(); - runCustomMenu(); - } else { - runButtonAction(); - } + runButtonAction(); buttonActionTimer.cancel(); } - }, buttonActionDelay, buttonActionDelay); + }, buttonActionDelay); } else { - if (isCustomMenuEnabled) { - LOG.info("Activating custom menu"); - runCustomMenu(); - } else { - LOG.info("Activating button action"); - runButtonAction(); - } + LOG.info("Activating button action"); + runButtonAction(); + } + + if (isCustomMenuEnabled) { + final Timer customMenuTimer = new Timer("Mi Band Button Action Custom Menu"); + customMenuTimer.schedule(new TimerTask() { + @Override + public void run() { + LOG.info("Activating custom menu"); + if(isWakelockEnabled) { + LOG.info("Acquiring wakelock"); + PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); + deviceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport:wakelock"); + deviceWakeLock.acquire(); + } + + resetCustomMenuTimerTimeout(); + runCustomMenu(); + customMenuTimer.cancel(); + } + }, buttonActionDelay); } - + currentButtonActionId++; currentButtonPressCount = 0; } else if (browsingCustomMenu) { From 4a00f4c06867d3d694728a8ff5545583dd9a2385 Mon Sep 17 00:00:00 2001 From: Mikael Vallerie Date: Thu, 14 Mar 2019 15:25:51 +0100 Subject: [PATCH 7/7] More fixes : acquiring the wakelock BEFORE scheduling the Timer --- .../service/devices/huami/HuamiSupport.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index 870e9cf935..f98781e42d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -1321,13 +1321,13 @@ public void handleButtonEvent() { LOG.info("Activating timer"); final Timer buttonActionTimer = new Timer("Mi Band Button Action Timer"); - buttonActionTimer.schedule(new TimerTask() { + buttonActionTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { runButtonAction(); buttonActionTimer.cancel(); } - }, buttonActionDelay); + }, buttonActionDelay, buttonActionDelay); } else { LOG.info("Activating button action"); @@ -1335,18 +1335,17 @@ public void run() { } if (isCustomMenuEnabled) { + if(isWakelockEnabled) { + LOG.info("Acquiring wakelock"); + PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); + deviceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport:wakelock"); + deviceWakeLock.acquire(); + } final Timer customMenuTimer = new Timer("Mi Band Button Action Custom Menu"); customMenuTimer.schedule(new TimerTask() { @Override public void run() { LOG.info("Activating custom menu"); - if(isWakelockEnabled) { - LOG.info("Acquiring wakelock"); - PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); - deviceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport:wakelock"); - deviceWakeLock.acquire(); - } - resetCustomMenuTimerTimeout(); runCustomMenu(); customMenuTimer.cancel();