From 34bd2ed9ccbf2bc0fdd41992fb729b6582f0835b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Sat, 15 Jul 2017 14:01:07 +0100 Subject: [PATCH] Mi Band 2: Do Not Disturb --- .../devices/miband/DoNotDisturb.java | 7 ++ .../devices/miband/MiBand2Coordinator.java | 50 +++++++++ .../devices/miband/MiBand2Service.java | 11 ++ .../devices/miband/MiBandConst.java | 6 ++ .../miband/MiBandPreferencesActivity.java | 60 +++++++++++ .../devices/miband2/MiBand2Support.java | 40 +++++++ .../gadgetbridge/util/TimePreference.java | 100 ++++++++++++++++++ app/src/main/res/values-pt/strings.xml | 7 ++ app/src/main/res/values/arrays.xml | 11 ++ app/src/main/res/values/strings.xml | 7 ++ app/src/main/res/values/values.xml | 4 + app/src/main/res/xml/miband_preferences.xml | 31 ++++++ 12 files changed, 334 insertions(+) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/DoNotDisturb.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/TimePreference.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/DoNotDisturb.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/DoNotDisturb.java new file mode 100644 index 00000000..138fd275 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/DoNotDisturb.java @@ -0,0 +1,7 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.miband; + +public enum DoNotDisturb { + OFF, + AUTOMATIC, + SCHEDULED +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Coordinator.java index 6dda128b..535da565 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Coordinator.java @@ -28,8 +28,11 @@ import android.support.annotation.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.Set; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -44,6 +47,9 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DO_NOT_DISTURB_END; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DO_NOT_DISTURB_START; + public class MiBand2Coordinator extends MiBandCoordinator { private static final Logger LOG = LoggerFactory.getLogger(MiBand2Coordinator.class); @@ -133,6 +139,50 @@ public class MiBand2Coordinator extends MiBandCoordinator { return prefs.getBoolean(MiBandConst.PREF_MI2_ROTATE_WRIST_TO_SWITCH_INFO, false); } + public static Date getDoNotDisturbStart() { + Prefs prefs = GBApplication.getPrefs(); + String time = prefs.getString(PREF_MI2_DO_NOT_DISTURB_START, "01:00"); + + DateFormat df = new SimpleDateFormat("HH:mm"); + try { + return df.parse(time); + } catch(Exception e) { + } + + return new Date(); + } + + public static Date getDoNotDisturbEnd() { + Prefs prefs = GBApplication.getPrefs(); + String time = prefs.getString(PREF_MI2_DO_NOT_DISTURB_END, "06:00"); + + DateFormat df = new SimpleDateFormat("HH:mm"); + try { + return df.parse(time); + } catch(Exception e) { + } + + return new Date(); + } + + public static DoNotDisturb getDoNotDisturb(Context context) { + Prefs prefs = GBApplication.getPrefs(); + + String dndOff = context.getString(R.string.p_off); + String dndAutomatic = context.getString(R.string.p_automatic); + String dndScheduled = context.getString(R.string.p_scheduled); + + String pref = prefs.getString(MiBandConst.PREF_MI2_DO_NOT_DISTURB, dndOff); + + if (dndAutomatic.equals(pref)) { + return DoNotDisturb.AUTOMATIC; + } else if (dndScheduled.equals(pref)) { + return DoNotDisturb.SCHEDULED; + } + + return DoNotDisturb.OFF; + } + @Override public InstallHandler findInstallHandler(Uri uri, Context context) { MiBand2FWInstallHandler handler = new MiBand2FWInstallHandler(uri, context); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java index 315d9533..3442cecb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java @@ -174,6 +174,17 @@ public class MiBand2Service { public static final byte[] DISPLAY_XXX = new byte[] {ENDPOINT_DISPLAY, 0x03, 0x0, 0x0 }; public static final byte[] DISPLAY_YYY = new byte[] {ENDPOINT_DISPLAY, 0x10, 0x0, 0x1, 0x1 }; + public static byte ENDPOINT_DND = 0x09; + + public static final byte[] COMMAND_DO_NOT_DISTURB_AUTOMATIC = new byte[] { ENDPOINT_DND, (byte) 0x83 }; + public static final byte[] COMMAND_DO_NOT_DISTURB_OFF = new byte[] { ENDPOINT_DND, (byte) 0x82 }; + public static final byte[] COMMAND_DO_NOT_DISTURB_SCHEDULED = new byte[] { ENDPOINT_DND, (byte) 0x81, 0x01, 0x00, 0x06, 0x00 }; + // The 4 last bytes set the start and end time in 24h format + public static byte DND_BYTE_START_HOURS = 2; + public static byte DND_BYTE_START_MINUTES = 3; + public static byte DND_BYTE_END_HOURS = 4; + public static byte DND_BYTE_END_MINUTES = 5; + public static final byte RESPONSE = 0x10; public static final byte SUCCESS = 0x01; 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 61b80968..a9bffb2c 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 @@ -46,6 +46,12 @@ public final class MiBandConst { public static final String PREF_MI2_ACTIVATE_DISPLAY_ON_LIFT = "mi2_activate_display_on_lift_wrist"; public static final String PREF_MI2_ROTATE_WRIST_TO_SWITCH_INFO = "mi2_rotate_wrist_to_switch_info"; public static final String PREF_MI2_ENABLE_TEXT_NOTIFICATIONS = "mi2_enable_text_notifications"; + public static final String PREF_MI2_DO_NOT_DISTURB = "mi2_do_not_disturb"; + public static final String PREF_MI2_DO_NOT_DISTURB_OFF = "off"; + public static final String PREF_MI2_DO_NOT_DISTURB_AUTOMATIC = "automatic"; + public static final String PREF_MI2_DO_NOT_DISTURB_SCHEDULED = "scheduled"; + public static final String PREF_MI2_DO_NOT_DISTURB_START = "mi2_do_not_disturb_start"; + public static final String PREF_MI2_DO_NOT_DISTURB_END = "mi2_do_not_disturb_end"; public static final String PREF_MIBAND_SETUP_BT_PAIRING = "mi_setup_bt_pairing"; 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 0b8911a7..124608a2 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 @@ -34,12 +34,18 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_ALARM_CLOCK; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_INCOMING_CALL; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_ACTIVATE_DISPLAY_ON_LIFT; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DATEFORMAT; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DISPLAY_ITEMS; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DO_NOT_DISTURB; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DO_NOT_DISTURB_END; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DO_NOT_DISTURB_OFF; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DO_NOT_DISTURB_SCHEDULED; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DO_NOT_DISTURB_START; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_ENABLE_TEXT_NOTIFICATIONS; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_GOAL_NOTIFICATION; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_ROTATE_WRIST_TO_SWITCH_INFO; @@ -60,6 +66,8 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity { addTryListeners(); + Prefs prefs = GBApplication.getPrefs(); + final Preference enableHeartrateSleepSupport = findPreference(PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION); enableHeartrateSleepSupport.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override @@ -139,6 +147,58 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity { } }); + String doNotDisturbState = prefs.getString(MiBandConst.PREF_MI2_DO_NOT_DISTURB, PREF_MI2_DO_NOT_DISTURB_OFF); + boolean doNotDisturbScheduled = doNotDisturbState.equals(PREF_MI2_DO_NOT_DISTURB_SCHEDULED); + + final Preference doNotDisturbStart = findPreference(PREF_MI2_DO_NOT_DISTURB_START); + doNotDisturbStart.setEnabled(doNotDisturbScheduled); + doNotDisturbStart.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newVal) { + invokeLater(new Runnable() { + @Override + public void run() { + GBApplication.deviceService().onSendConfiguration(PREF_MI2_DO_NOT_DISTURB_START); + } + }); + return true; + } + }); + + final Preference doNotDisturbEnd = findPreference(PREF_MI2_DO_NOT_DISTURB_END); + doNotDisturbEnd.setEnabled(doNotDisturbScheduled); + doNotDisturbEnd.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newVal) { + invokeLater(new Runnable() { + @Override + public void run() { + GBApplication.deviceService().onSendConfiguration(PREF_MI2_DO_NOT_DISTURB_END); + } + }); + return true; + } + }); + + final Preference doNotDisturb = findPreference(PREF_MI2_DO_NOT_DISTURB); + doNotDisturb.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newVal) { + final boolean scheduled = PREF_MI2_DO_NOT_DISTURB_SCHEDULED.equals(newVal.toString()); + + doNotDisturbStart.setEnabled(scheduled); + doNotDisturbEnd.setEnabled(scheduled); + + invokeLater(new Runnable() { + @Override + public void run() { + GBApplication.deviceService().onSendConfiguration(PREF_MI2_DO_NOT_DISTURB); + } + }); + return true; + } + }); + final Preference fitnessGoal = findPreference(ActivityUser.PREF_USER_STEPS_GOAL); fitnessGoal.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java index bd820eaf..13878293 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java @@ -36,6 +36,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; +import java.util.Date; import java.util.GregorianCalendar; import java.util.List; import java.util.Set; @@ -51,6 +52,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInf import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.miband.DateTimeDisplay; +import nodomain.freeyourgadget.gadgetbridge.devices.miband.DoNotDisturb; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2SampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service; @@ -1091,6 +1093,10 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { case ActivityUser.PREF_USER_STEPS_GOAL: setFitnessGoal(builder); break; + case MiBandConst.PREF_MI2_DO_NOT_DISTURB: + case MiBandConst.PREF_MI2_DO_NOT_DISTURB_START: + case MiBandConst.PREF_MI2_DO_NOT_DISTURB_END: + setDoNotDisturb(builder); } builder.queue(getQueue()); } catch (IOException e) { @@ -1199,6 +1205,39 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { return this; } + private MiBand2Support setDoNotDisturb(TransactionBuilder builder) { + DoNotDisturb doNotDisturb = MiBand2Coordinator.getDoNotDisturb(getContext()); + LOG.info("Setting do not disturb to " + doNotDisturb); + switch (doNotDisturb) { + case OFF: + builder.write(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_3_CONFIGURATION), MiBand2Service.COMMAND_DO_NOT_DISTURB_OFF); + break; + case AUTOMATIC: + builder.write(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_3_CONFIGURATION), MiBand2Service.COMMAND_DO_NOT_DISTURB_AUTOMATIC); + break; + case SCHEDULED: + byte[] data = MiBand2Service.COMMAND_DO_NOT_DISTURB_SCHEDULED.clone(); + + Calendar calendar = GregorianCalendar.getInstance(); + + Date start = MiBand2Coordinator.getDoNotDisturbStart(); + calendar.setTime(start); + data[MiBand2Service.DND_BYTE_START_HOURS] = (byte) calendar.get(Calendar.HOUR_OF_DAY); + data[MiBand2Service.DND_BYTE_START_MINUTES] = (byte) calendar.get(Calendar.MINUTE); + + Date end = MiBand2Coordinator.getDoNotDisturbEnd(); + calendar.setTime(end); + data[MiBand2Service.DND_BYTE_END_HOURS] = (byte) calendar.get(Calendar.HOUR_OF_DAY); + data[MiBand2Service.DND_BYTE_END_MINUTES] = (byte) calendar.get(Calendar.MINUTE); + + builder.write(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_3_CONFIGURATION), data); + + break; + } + + return this; + } + public void phase2Initialize(TransactionBuilder builder) { LOG.info("phase2Initialize..."); enableFurtherNotifications(builder, true); @@ -1208,6 +1247,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { setWearLocation(builder); setFitnessGoal(builder); setDisplayItems(builder); + setDoNotDisturb(builder); setRotateWristToSwitchInfo(builder); setActivateDisplayOnLiftWrist(builder); setGoalNotification(builder); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/TimePreference.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/TimePreference.java new file mode 100644 index 00000000..409557db --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/TimePreference.java @@ -0,0 +1,100 @@ +package nodomain.freeyourgadget.gadgetbridge.util; + +import android.content.Context; +import android.content.res.TypedArray; +import android.preference.DialogPreference; +import android.text.format.DateFormat; +import android.util.AttributeSet; +import android.view.View; +import android.widget.TimePicker; + +public class TimePreference extends DialogPreference { + private int hour = 0; + private int minute = 0; + + private TimePicker picker = null; + + public TimePreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected View onCreateDialogView() { + picker = new TimePicker(getContext()); + picker.setIs24HourView(DateFormat.is24HourFormat(getContext())); + picker.setPadding(0, 50, 0, 50); + + return picker; + } + + @Override + protected void onBindDialogView(View v) { + super.onBindDialogView(v); + + picker.setCurrentHour(hour); + picker.setCurrentMinute(minute); + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + super.onDialogClosed(positiveResult); + + if (positiveResult) { + hour = picker.getCurrentHour(); + minute = picker.getCurrentMinute(); + + String time = getTime24h(); + + if (callChangeListener(time)) { + persistString(time); + + updateSummary(); + } + } + } + + @Override + protected Object onGetDefaultValue(TypedArray a, int index) { + return a.getString(index); + } + + @Override + protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { + String time; + + if (restoreValue) { + if (defaultValue == null) { + time = getPersistedString("00:00"); + } else { + time = getPersistedString(defaultValue.toString()); + } + } else { + time = defaultValue.toString(); + } + + String[] pieces = time.split(":"); + + hour = Integer.parseInt(pieces[0]); + minute = Integer.parseInt(pieces[1]); + + updateSummary(); + } + + public void updateSummary() { + if (DateFormat.is24HourFormat(getContext())) + setSummary(getTime24h()); + else + setSummary(getTime12h()); + } + + public String getTime24h() { + return String.format("%02d", hour) + ":" + String.format("%02d", minute); + } + + public String getTime12h() { + String suffix = hour < 12 ? " AM" : " PM"; + int h = hour > 12 ? hour - 12 : hour; + + return String.valueOf(h) + ":" + String.format("%02d", minute) + suffix; + } +} diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 174573cc..3516f7d2 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -306,6 +306,10 @@ Escolher os items a mostrar no ecrã Ativar ecrã do dispositivo quando o levantar Rodar o pulso para mudar de ecrã + Não incomodar + A pulseira não recebe notificações enquanto activo + Hora de início + Hora de fim Prestes a transferir dados desde %1$s aguarde para tornar a ligar Sobre você @@ -371,6 +375,9 @@ Notificações de texto = 1.0.1.28 e Mili_pro.ft* instalado.]]> desligado + Desligado + Automático (deteção de sono) + Agendado (intervalo de tempo) A tentar emparelhar com %1$s Ative o Bluetooth para encontrar os dispositivos. Emparelhar com %1$s? diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index ed31547d..f6583a39 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -135,6 +135,17 @@ @string/p_dateformat_datetime + + @string/mi2_dnd_off + @string/mi2_dnd_automatic + @string/mi2_dnd_scheduled + + + @string/p_off + @string/p_automatic + @string/p_scheduled + + @string/chart_steps @string/distance diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0c5c0d15..4bc1ccf0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -352,6 +352,10 @@ Choose the items displayed on the band screen Activate display upon lift Rotate wrist to switch info + Do Not Disturb + The band won\'t receive notifications while active + Start time + End time About to transfer data since %1$s waiting for reconnect @@ -429,6 +433,9 @@ Text notifications = 1.0.1.28 and Mili_pro.ft* installed.]]> off + Off + Automatic (sleep detection) + Scheduled (time interval) Attempting to pair with %1$s Bonding with %1$s failed immediately. Trying to connect to: %1$s diff --git a/app/src/main/res/values/values.xml b/app/src/main/res/values/values.xml index 10b562f2..addbce96 100644 --- a/app/src/main/res/values/values.xml +++ b/app/src/main/res/values/values.xml @@ -19,6 +19,10 @@ heart_rate battery + off + automatic + scheduled + metric imperial diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index 8ce54720..e7338045 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -86,6 +86,37 @@ + + + + + + + + + + + + +