Mi Band 2: Inactivity Warnings

master
José Rebelo 2017-07-15 21:48:26 +01:00 committed by Carsten Pfeiffer
parent 42f4200209
commit f7abe2d4a3
8 changed files with 295 additions and 12 deletions

View File

@ -47,9 +47,6 @@ 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);
@ -139,27 +136,54 @@ public class MiBand2Coordinator extends MiBandCoordinator {
return prefs.getBoolean(MiBandConst.PREF_MI2_ROTATE_WRIST_TO_SWITCH_INFO, false);
}
public static Date getDoNotDisturbStart() {
public static boolean getInactivityWarnings() {
Prefs prefs = GBApplication.getPrefs();
String time = prefs.getString(PREF_MI2_DO_NOT_DISTURB_START, "01:00");
return prefs.getBoolean(MiBandConst.PREF_MI2_INACTIVITY_WARNINGS, false);
}
DateFormat df = new SimpleDateFormat("HH:mm");
try {
return df.parse(time);
} catch(Exception e) {
}
public static int getInactivityWarningsThreshold() {
Prefs prefs = GBApplication.getPrefs();
return prefs.getInt(MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_THRESHOLD, 60);
}
return new Date();
public static boolean getInactivityWarningsDnd() {
Prefs prefs = GBApplication.getPrefs();
return prefs.getBoolean(MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_DND, false);
}
public static Date getInactivityWarningsStart() {
return getTimePreference(MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_START, "06:00");
}
public static Date getInactivityWarningsEnd() {
return getTimePreference(MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_END, "22:00");
}
public static Date getInactivityWarningsDndStart() {
return getTimePreference(MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_DND_START, "12:00");
}
public static Date getInactivityWarningsDndEnd() {
return getTimePreference(MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_DND_END, "14:00");
}
public static Date getDoNotDisturbStart() {
return getTimePreference(MiBandConst.PREF_MI2_DO_NOT_DISTURB_START, "01:00");
}
public static Date getDoNotDisturbEnd() {
return getTimePreference(MiBandConst.PREF_MI2_DO_NOT_DISTURB_END, "06:00");
}
public static Date getTimePreference(String key, String defaultValue) {
Prefs prefs = GBApplication.getPrefs();
String time = prefs.getString(PREF_MI2_DO_NOT_DISTURB_END, "06:00");
String time = prefs.getString(key, defaultValue);
DateFormat df = new SimpleDateFormat("HH:mm");
try {
return df.parse(time);
} catch(Exception e) {
LOG.error("Unexpected exception in MiBand2Coordinator.getTime: " + e.getMessage());
}
return new Date();

View File

@ -174,6 +174,22 @@ 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 };
// The third byte controls the threshold, in minutes
// The last 8 bytes represent 2 separate time intervals for the inactivity warnings
// If there is no do not disturb interval, the last 4 bytes (the second interval) are 0
// and only the first interval of the command is used
public static int INACTIVITY_WARNINGS_THRESHOLD = 2;
public static int INACTIVITY_WARNINGS_INTERVAL_1_START_HOURS = 4;
public static int INACTIVITY_WARNINGS_INTERVAL_1_START_MINUTES = 5;
public static int INACTIVITY_WARNINGS_INTERVAL_1_END_HOURS = 6;
public static int INACTIVITY_WARNINGS_INTERVAL_1_END_MINUTES = 7;
public static int INACTIVITY_WARNINGS_INTERVAL_2_START_HOURS = 8;
public static int INACTIVITY_WARNINGS_INTERVAL_2_START_MINUTES = 9;
public static int INACTIVITY_WARNINGS_INTERVAL_2_END_HOURS = 10;
public static int INACTIVITY_WARNINGS_INTERVAL_2_END_MINUTES = 11;
public static final byte[] COMMAND_ENABLE_INACTIVITY_WARNINGS = new byte[] { 0x08, 0x01, 0x3c, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00 };
public static final byte[] COMMAND_DISABLE_INACTIVITY_WARNINGS = new byte[] { 0x08, 0x00, 0x3c, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00 };
public static byte ENDPOINT_DND = 0x09;
public static final byte[] COMMAND_DO_NOT_DISTURB_AUTOMATIC = new byte[] { ENDPOINT_DND, (byte) 0x83 };

View File

@ -52,6 +52,13 @@ public final class MiBandConst {
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_MI2_INACTIVITY_WARNINGS = "mi2_inactivity_warnings";
public static final String PREF_MI2_INACTIVITY_WARNINGS_THRESHOLD = "mi2_inactivity_warnings_threshold";
public static final String PREF_MI2_INACTIVITY_WARNINGS_START = "mi2_inactivity_warnings_start";
public static final String PREF_MI2_INACTIVITY_WARNINGS_END = "mi2_inactivity_warnings_end";
public static final String PREF_MI2_INACTIVITY_WARNINGS_DND = "mi2_inactivity_warnings_dnd";
public static final String PREF_MI2_INACTIVITY_WARNINGS_DND_START = "mi2_inactivity_warnings_dnd_start";
public static final String PREF_MI2_INACTIVITY_WARNINGS_DND_END = "mi2_inactivity_warnings_dnd_end";
public static final String PREF_MIBAND_SETUP_BT_PAIRING = "mi_setup_bt_pairing";

View File

@ -48,6 +48,13 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PR
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_INACTIVITY_WARNINGS;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_DND;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_DND_END;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_DND_START;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_END;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_START;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_THRESHOLD;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_ROTATE_WRIST_TO_SWITCH_INFO;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_ADDRESS;
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS;
@ -147,6 +154,104 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity {
}
});
final Preference inactivityWarnings = findPreference(PREF_MI2_INACTIVITY_WARNINGS);
inactivityWarnings.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_MI2_INACTIVITY_WARNINGS);
}
});
return true;
}
});
final Preference inactivityWarningsThreshold = findPreference(PREF_MI2_INACTIVITY_WARNINGS_THRESHOLD);
inactivityWarningsThreshold.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_MI2_INACTIVITY_WARNINGS_THRESHOLD);
}
});
return true;
}
});
final Preference inactivityWarningsStart = findPreference(PREF_MI2_INACTIVITY_WARNINGS_START);
inactivityWarningsStart.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_MI2_INACTIVITY_WARNINGS_START);
}
});
return true;
}
});
final Preference inactivityWarningsEnd = findPreference(PREF_MI2_INACTIVITY_WARNINGS_END);
inactivityWarningsEnd.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_MI2_INACTIVITY_WARNINGS_END);
}
});
return true;
}
});
final Preference inactivityWarningsDnd = findPreference(PREF_MI2_INACTIVITY_WARNINGS_DND);
inactivityWarningsDnd.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_MI2_INACTIVITY_WARNINGS_DND);
}
});
return true;
}
});
final Preference inactivityWarningsDndStart = findPreference(PREF_MI2_INACTIVITY_WARNINGS_DND_START);
inactivityWarningsDndStart.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_MI2_INACTIVITY_WARNINGS_DND_START);
}
});
return true;
}
});
final Preference inactivityWarningsDndEnd = findPreference(PREF_MI2_INACTIVITY_WARNINGS_DND_END);
inactivityWarningsDndEnd.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_MI2_INACTIVITY_WARNINGS_DND_END);
}
});
return true;
}
});
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);
@ -270,6 +375,7 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity {
prefKeys.add(PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR);
prefKeys.add(PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS);
prefKeys.add(PREF_MI2_ENABLE_TEXT_NOTIFICATIONS);
prefKeys.add(PREF_MI2_INACTIVITY_WARNINGS_THRESHOLD);
prefKeys.add(getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_ALARM_CLOCK));
prefKeys.add(getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_INCOMING_CALL));

View File

@ -1097,6 +1097,16 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
case MiBandConst.PREF_MI2_DO_NOT_DISTURB_START:
case MiBandConst.PREF_MI2_DO_NOT_DISTURB_END:
setDoNotDisturb(builder);
break;
case MiBandConst.PREF_MI2_INACTIVITY_WARNINGS:
case MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_THRESHOLD:
case MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_START:
case MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_END:
case MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_DND:
case MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_DND_START:
case MiBandConst.PREF_MI2_INACTIVITY_WARNINGS_DND_END:
setInactivityWarnings(builder);
break;
}
builder.queue(getQueue());
} catch (IOException e) {
@ -1238,6 +1248,60 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
return this;
}
private MiBand2Support setInactivityWarnings(TransactionBuilder builder) {
boolean enable = MiBand2Coordinator.getInactivityWarnings();
LOG.info("Setting inactivity warnings to " + enable);
if (enable) {
byte[] data = MiBand2Service.COMMAND_ENABLE_INACTIVITY_WARNINGS.clone();
int threshold = MiBand2Coordinator.getInactivityWarningsThreshold();
data[MiBand2Service.INACTIVITY_WARNINGS_THRESHOLD] = (byte) threshold;
Calendar calendar = GregorianCalendar.getInstance();
boolean enableDnd = MiBand2Coordinator.getInactivityWarningsDnd();
Date intervalStart = MiBand2Coordinator.getInactivityWarningsStart();
Date intervalEnd = MiBand2Coordinator.getInactivityWarningsEnd();
Date dndStart = MiBand2Coordinator.getInactivityWarningsDndStart();
Date dndEnd = MiBand2Coordinator.getInactivityWarningsDndEnd();
// The first interval always starts when the warnings interval starts
calendar.setTime(intervalStart);
data[MiBand2Service.INACTIVITY_WARNINGS_INTERVAL_1_START_HOURS] = (byte) calendar.get(Calendar.HOUR_OF_DAY);
data[MiBand2Service.INACTIVITY_WARNINGS_INTERVAL_1_START_MINUTES] = (byte) calendar.get(Calendar.MINUTE);
if(enableDnd) {
// The first interval ends when the dnd interval starts
calendar.setTime(dndStart);
data[MiBand2Service.INACTIVITY_WARNINGS_INTERVAL_1_END_HOURS] = (byte) calendar.get(Calendar.HOUR_OF_DAY);
data[MiBand2Service.INACTIVITY_WARNINGS_INTERVAL_1_END_MINUTES] = (byte) calendar.get(Calendar.MINUTE);
// The second interval starts when the dnd interval ends
calendar.setTime(dndEnd);
data[MiBand2Service.INACTIVITY_WARNINGS_INTERVAL_2_START_HOURS] = (byte) calendar.get(Calendar.HOUR_OF_DAY);
data[MiBand2Service.INACTIVITY_WARNINGS_INTERVAL_2_START_MINUTES] = (byte) calendar.get(Calendar.MINUTE);
// ... and it ends when the warnings interval ends
calendar.setTime(intervalEnd);
data[MiBand2Service.INACTIVITY_WARNINGS_INTERVAL_2_END_HOURS] = (byte) calendar.get(Calendar.HOUR_OF_DAY);
data[MiBand2Service.INACTIVITY_WARNINGS_INTERVAL_2_END_MINUTES] = (byte) calendar.get(Calendar.MINUTE);
} else {
// No Dnd, use the first interval
calendar.setTime(intervalEnd);
data[MiBand2Service.INACTIVITY_WARNINGS_INTERVAL_1_END_HOURS] = (byte) calendar.get(Calendar.HOUR_OF_DAY);
data[MiBand2Service.INACTIVITY_WARNINGS_INTERVAL_1_END_MINUTES] = (byte) calendar.get(Calendar.MINUTE);
}
builder.write(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_3_CONFIGURATION), data);
} else {
builder.write(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_3_CONFIGURATION), MiBand2Service.COMMAND_DISABLE_INACTIVITY_WARNINGS);
}
return this;
}
public void phase2Initialize(TransactionBuilder builder) {
LOG.info("phase2Initialize...");
enableFurtherNotifications(builder, true);
@ -1251,6 +1315,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
setRotateWristToSwitchInfo(builder);
setActivateDisplayOnLiftWrist(builder);
setGoalNotification(builder);
setInactivityWarnings(builder);
setHeartrateSleepSupport(builder);
}
}

View File

@ -310,6 +310,10 @@
<string name="mi2_prefs_do_not_disturb_summary">A pulseira não recebe notificações enquanto activo</string>
<string name="mi2_prefs_do_not_disturb_start">Hora de início</string>
<string name="mi2_prefs_do_not_disturb_end">Hora de fim</string>
<string name="mi2_prefs_inactivity_warnings">Avisos de inactividade</string>
<string name="mi2_prefs_inactivity_warnings_summary">A pulseira irá vibrar quando estiver inactivo durante algum tempo</string>
<string name="mi2_prefs_inactivity_warnings_threshold">Limite de inactividade (em minutos)</string>
<string name="mi2_prefs_inactivity_warnings_dnd_summary">Desactivar os avisos de inactividade durante um intervalo de tempo</string>
<string name="FetchActivityOperation_about_to_transfer_since">Prestes a transferir dados desde %1$s</string>
<string name="waiting_for_reconnect">aguarde para tornar a ligar</string>
<string name="activity_prefs_about_you">Sobre você</string>

View File

@ -354,6 +354,10 @@
<string name="mi2_prefs_rotate_wrist_to_switch_info">Rotate wrist to switch info</string>
<string name="mi2_prefs_do_not_disturb">Do Not Disturb</string>
<string name="mi2_prefs_do_not_disturb_summary">The band won\'t receive notifications while active</string>
<string name="mi2_prefs_inactivity_warnings">Inactivity warnings</string>
<string name="mi2_prefs_inactivity_warnings_summary">The band will vibrate when you have been inactive for a while</string>
<string name="mi2_prefs_inactivity_warnings_threshold">Inactivity threshold (in minutes)</string>
<string name="mi2_prefs_inactivity_warnings_dnd_summary">Disable the inactivity warnings for a time interval</string>
<string name="mi2_prefs_do_not_disturb_start">Start time</string>
<string name="mi2_prefs_do_not_disturb_end">End time</string>
<string name="FetchActivityOperation_about_to_transfer_since">About to transfer data since %1$s</string>

View File

@ -84,6 +84,63 @@
android:title="@string/miband2_prefs_dateformat"
android:summary="%s" />
<PreferenceScreen
android:key="mi2_inactivity_warning_key"
android:summary="@string/mi2_prefs_inactivity_warnings_summary"
android:title="@string/mi2_prefs_inactivity_warnings"
android:persistent="false">
<!-- workaround for missing toolbar -->
<PreferenceCategory
android:title="@string/mi2_prefs_inactivity_warnings"
/>
<CheckBoxPreference
android:defaultValue="false"
android:key="mi2_inactivity_warnings"
android:summary="@string/mi2_prefs_inactivity_warnings_summary"
android:title="@string/mi2_prefs_inactivity_warnings" />
<EditTextPreference
android:defaultValue="60"
android:dependency="mi2_inactivity_warnings"
android:inputType="numberSigned"
android:key="mi2_inactivity_warnings_threshold"
android:maxLength="2"
android:title="@string/mi2_prefs_inactivity_warnings_threshold" />
<nodomain.freeyourgadget.gadgetbridge.util.TimePreference
android:defaultValue="06:00"
android:dependency="mi2_inactivity_warnings"
android:key="mi2_inactivity_warnings_start"
android:title="@string/mi2_prefs_do_not_disturb_start" />
<nodomain.freeyourgadget.gadgetbridge.util.TimePreference
android:defaultValue="22:00"
android:dependency="mi2_inactivity_warnings"
android:key="mi2_inactivity_warnings_end"
android:title="@string/mi2_prefs_do_not_disturb_end" />
<CheckBoxPreference
android:defaultValue="false"
android:dependency="mi2_inactivity_warnings"
android:key="mi2_inactivity_warnings_dnd"
android:summary="@string/mi2_prefs_inactivity_warnings_dnd_summary"
android:title="@string/mi2_prefs_do_not_disturb" />
<nodomain.freeyourgadget.gadgetbridge.util.TimePreference
android:defaultValue="12:00"
android:dependency="mi2_inactivity_warnings_dnd"
android:key="mi2_inactivity_warnings_dnd_start"
android:title="@string/mi2_prefs_do_not_disturb_start" />
<nodomain.freeyourgadget.gadgetbridge.util.TimePreference
android:defaultValue="14:00"
android:dependency="mi2_inactivity_warnings_dnd"
android:key="mi2_inactivity_warnings_dnd_end"
android:title="@string/mi2_prefs_do_not_disturb_end" />
</PreferenceScreen>
</PreferenceCategory>
<PreferenceScreen