From 10c9b07c692081f5634e0c221534e889aa13fe90 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Sun, 12 Jan 2020 10:12:21 +0300 Subject: [PATCH] Control alarm snooze mode on MiBand2 --- .../gadgetbridge/daogen/GBDaoGenerator.java | 3 +- .../gadgetbridge/SleepAlarmWidget.java | 2 +- .../gadgetbridge/activities/AlarmDetails.java | 20 ++++++++++ .../activities/ConfigureAlarms.java | 2 +- .../activities/WidgetAlarmsActivity.java | 2 +- .../schema/GadgetbridgeUpdate_23.java | 40 +++++++++++++++++++ .../devices/AbstractDeviceCoordinator.java | 6 +++ .../devices/DeviceCoordinator.java | 6 +++ .../huami/miband2/MiBand2Coordinator.java | 5 +++ .../huami/miband2/MiBand2HRXCoordinator.java | 5 +++ .../gadgetbridge/model/Alarm.java | 2 + .../service/devices/huami/HuamiSupport.java | 12 ++++-- .../service/devices/miband/MiBandSupport.java | 2 +- .../gadgetbridge/util/AlarmUtils.java | 6 +-- .../res/layout/activity_alarm_details.xml | 10 +++++ app/src/main/res/values/strings.xml | 1 + 16 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_23.java diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java index 3f07e9250..0528c1c9b 100644 --- a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java +++ b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java @@ -43,7 +43,7 @@ public class GBDaoGenerator { public static void main(String[] args) throws Exception { - Schema schema = new Schema(22, MAIN_PACKAGE + ".entities"); + Schema schema = new Schema(23, MAIN_PACKAGE + ".entities"); Entity userAttributes = addUserAttributes(schema); Entity user = addUserInfo(schema, userAttributes); @@ -383,6 +383,7 @@ public class GBDaoGenerator { alarm.addIndex(indexUnique); alarm.addBooleanProperty("enabled").notNull(); alarm.addBooleanProperty("smartWakeup").notNull(); + alarm.addBooleanProperty("snooze").notNull(); alarm.addIntProperty("repetition").notNull().codeBeforeGetter( "public boolean isRepetitive() { return getRepetition() != ALARM_ONCE; } " + "public boolean getRepetition(int dow) { return (this.repetition & dow) > 0; }" diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/SleepAlarmWidget.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/SleepAlarmWidget.java index cac85d137..25ba6def5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/SleepAlarmWidget.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/SleepAlarmWidget.java @@ -121,7 +121,7 @@ public class SleepAlarmWidget extends AppWidgetProvider { context.getString(R.string.appwidget_setting_alarm, hours, minutes), Toast.LENGTH_SHORT, GB.INFO); - Alarm alarm = AlarmUtils.createSingleShot(0,true, calendar); + Alarm alarm = AlarmUtils.createSingleShot(0, true, false, calendar); ArrayList alarms = new ArrayList<>(1); alarms.add(alarm); GBApplication.deviceService().onSetAlarms(alarms); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java index 86069bc1a..f0d88d805 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java @@ -38,6 +38,7 @@ public class AlarmDetails extends AbstractGBActivity { private Alarm alarm; private TimePicker timePicker; private CheckedTextView cbSmartWakeup; + private CheckedTextView cbSnooze; private CheckedTextView cbMonday; private CheckedTextView cbTuesday; private CheckedTextView cbWednesday; @@ -57,6 +58,7 @@ public class AlarmDetails extends AbstractGBActivity { timePicker = findViewById(R.id.alarm_time_picker); cbSmartWakeup = findViewById(R.id.alarm_cb_smart_wakeup); + cbSnooze = findViewById(R.id.alarm_cb_snooze); cbMonday = findViewById(R.id.alarm_cb_monday); cbTuesday = findViewById(R.id.alarm_cb_tuesday); cbWednesday = findViewById(R.id.alarm_cb_wednesday); @@ -71,6 +73,11 @@ public class AlarmDetails extends AbstractGBActivity { ((CheckedTextView) v).toggle(); } }); + cbSnooze.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + ((CheckedTextView) v).toggle(); + } + }); cbMonday.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { ((CheckedTextView) v).toggle(); @@ -115,6 +122,10 @@ public class AlarmDetails extends AbstractGBActivity { int smartAlarmVisibility = supportsSmartWakeup() ? View.VISIBLE : View.GONE; cbSmartWakeup.setVisibility(smartAlarmVisibility); + cbSnooze.setChecked(alarm.getSnooze()); + int snoozeVisibility = supportsSnoozing() ? View.VISIBLE : View.GONE; + cbSnooze.setVisibility(snoozeVisibility); + cbMonday.setChecked(alarm.getRepetition(Alarm.ALARM_MON)); cbTuesday.setChecked(alarm.getRepetition(Alarm.ALARM_TUE)); cbWednesday.setChecked(alarm.getRepetition(Alarm.ALARM_WED)); @@ -133,6 +144,14 @@ public class AlarmDetails extends AbstractGBActivity { return false; } + private boolean supportsSnoozing() { + if (device != null) { + DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(device); + return coordinator.supportsAlarmSnoozing(); + } + return false; + } + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { @@ -146,6 +165,7 @@ public class AlarmDetails extends AbstractGBActivity { private void updateAlarm() { alarm.setSmartWakeup(supportsSmartWakeup() && cbSmartWakeup.isChecked()); + alarm.setSnooze(supportsSnoozing() && cbSnooze.isChecked()); int repetitionMask = AlarmUtils.createRepetitionMassk(cbMonday.isChecked(), cbTuesday.isChecked(), cbWednesday.isChecked(), cbThursday.isChecked(), cbFriday.isChecked(), cbSaturday.isChecked(), cbSunday.isChecked()); alarm.setRepetition(repetitionMask); alarm.setHour(timePicker.getCurrentHour()); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java index 2e072c680..a1da37366 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java @@ -146,7 +146,7 @@ public class ConfigureAlarms extends AbstractGBActivity { } private Alarm createDefaultAlarm(@NonNull Device device, @NonNull User user, int position) { - return new Alarm(device.getId(), user.getId(), position, false, false, 0, 6, 30, false); + return new Alarm(device.getId(), user.getId(), position, false, false, false, 0, 6, 30, false); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/WidgetAlarmsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/WidgetAlarmsActivity.java index ca2641e83..8e01404a7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/WidgetAlarmsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/WidgetAlarmsActivity.java @@ -135,7 +135,7 @@ public class WidgetAlarmsActivity extends Activity implements View.OnClickListen this.getString(R.string.appwidget_setting_alarm, hours, minutes), Toast.LENGTH_SHORT, GB.INFO); - Alarm alarm = AlarmUtils.createSingleShot(0, true, calendar); + Alarm alarm = AlarmUtils.createSingleShot(0, true, false, calendar); ArrayList alarms = new ArrayList<>(1); alarms.add(alarm); GBApplication.deviceService().onSetAlarms(alarms); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_23.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_23.java new file mode 100644 index 000000000..dd29cdca7 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_23.java @@ -0,0 +1,40 @@ +/* Copyright (C) 2017-2020 Andreas Shimokawa, protomors + + 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.database.schema; + +import android.database.sqlite.SQLiteDatabase; + +import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; +import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript; +import nodomain.freeyourgadget.gadgetbridge.entities.AlarmDao; + +public class GadgetbridgeUpdate_23 implements DBUpdateScript { + @Override + public void upgradeSchema(SQLiteDatabase db) { + if (!DBHelper.existsColumn(AlarmDao.TABLENAME, AlarmDao.Properties.Snooze.columnName, db)) { + // Setting default value of SNOOZE column to 1 (true), so that existing MiBand2 alarms + // behave as before + String ADD_COLUMN_SNOOZE = "ALTER TABLE " + AlarmDao.TABLENAME + " ADD COLUMN " + + AlarmDao.Properties.Snooze.columnName + " INTEGER NOT NULL DEFAULT 1;"; + db.execSQL(ADD_COLUMN_SNOOZE); + } + } + + @Override + public void downgradeSchema(SQLiteDatabase db) { + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java index 9bc253c82..7f27a9cd1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java @@ -145,11 +145,17 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator { return false; } + @Override + public boolean supportsAlarmSnoozing() { + return false; + } + @Override public boolean supportsMusicInfo() { return false; } + @Override public boolean supportsLedColor() { return false; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java index eb21ecd4e..4c08012bd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java @@ -201,6 +201,12 @@ public interface DeviceCoordinator { */ boolean supportsSmartWakeup(GBDevice device); + /** + * Returns true if this device/coordinator supports alarm snoozing + * @return + */ + boolean supportsAlarmSnoozing(); + /** * Returns true if the given device supports heart rate measurements. * @return diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2Coordinator.java index 0beb31b51..d9b3bbc8b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2Coordinator.java @@ -65,6 +65,11 @@ public class MiBand2Coordinator extends HuamiCoordinator { return handler.isValid() ? handler : null; } + @Override + public boolean supportsAlarmSnoozing() { + return true; + } + @Override public boolean supportsHeartRateMeasurement(GBDevice device) { return true; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2HRXCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2HRXCoordinator.java index f6ef95be1..43475b16e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2HRXCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2HRXCoordinator.java @@ -67,6 +67,11 @@ public class MiBand2HRXCoordinator extends HuamiCoordinator { return null; } + @Override + public boolean supportsAlarmSnoozing() { + return true; + } + @Override public boolean supportsHeartRateMeasurement(GBDevice device) { return false; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Alarm.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Alarm.java index 831f00f1a..d996bfa20 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Alarm.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Alarm.java @@ -41,6 +41,8 @@ public interface Alarm extends Serializable { boolean getSmartWakeup(); + boolean getSnooze(); + int getRepetition(); boolean isRepetitive(); 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 ebe1524a4..9fe2f3004 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 @@ -1608,10 +1608,14 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { return; } - int base = 0; + int actionMask = 0; int daysMask = 0; if (alarm.getEnabled() && !alarm.getUnused()) { - base = 128; + actionMask = 0x80; + + if (coordinator.supportsAlarmSnoozing() && !alarm.getSnooze()) { + actionMask |= 0x40; + } } if (!alarm.getUnused()) { daysMask = alarm.getRepetition(); @@ -1622,7 +1626,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { byte[] alarmMessage = new byte[] { (byte) 0x2, // TODO what is this? - (byte) (base + alarm.getPosition()), // 128 is the base, alarm slot is added + (byte) (actionMask | alarm.getPosition()), // action mask + alarm slot (byte) calendar.get(Calendar.HOUR_OF_DAY), (byte) calendar.get(Calendar.MINUTE), (byte) daysMask, @@ -1684,7 +1688,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport { int slotToUse = 2 - iteration; Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(mEvt.getBegin()); - Alarm alarm = AlarmUtils.createSingleShot(slotToUse, false, calendar); + Alarm alarm = AlarmUtils.createSingleShot(slotToUse, false, true, calendar); queueAlarm(alarm, builder, characteristic); iteration++; } 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 99c8d9c3e..1ac09ec40 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 @@ -1243,7 +1243,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { int slotToUse = 2 - iteration; Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(mEvt.getBegin()); - Alarm alarm = AlarmUtils.createSingleShot(slotToUse, false, calendar); + Alarm alarm = AlarmUtils.createSingleShot(slotToUse, false, false, calendar); queueAlarm(alarm, builder, characteristic); iteration++; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AlarmUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AlarmUtils.java index b313c74d3..31c730016 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AlarmUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AlarmUtils.java @@ -48,8 +48,8 @@ public class AlarmUtils { * @param calendar * @return */ - public static nodomain.freeyourgadget.gadgetbridge.model.Alarm createSingleShot(int index, boolean smartWakeup, Calendar calendar) { - return new Alarm(-1, -1, index, true, smartWakeup, Alarm.ALARM_ONCE, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), false); + public static nodomain.freeyourgadget.gadgetbridge.model.Alarm createSingleShot(int index, boolean smartWakeup, boolean snooze, Calendar calendar) { + return new Alarm(-1, -1, index, true, smartWakeup, snooze, Alarm.ALARM_ONCE, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), false); } /** @@ -128,7 +128,7 @@ public class AlarmUtils { int hour = Integer.parseInt(tokens[4]); int minute = Integer.parseInt(tokens[5]); - return new Alarm(device.getId(), user.getId(), index, enabled, smartWakeup, repetition, hour, minute, false); + return new Alarm(device.getId(), user.getId(), index, enabled, smartWakeup, false, repetition, hour, minute, false); } private static Comparator createComparator() { diff --git a/app/src/main/res/layout/activity_alarm_details.xml b/app/src/main/res/layout/activity_alarm_details.xml index 4610a3430..8a449e905 100644 --- a/app/src/main/res/layout/activity_alarm_details.xml +++ b/app/src/main/res/layout/activity_alarm_details.xml @@ -33,6 +33,16 @@ android:text="@string/alarm_smart_wakeup" android:textAppearance="?android:attr/textAppearanceSmall" /> + + Fri Sat Smart wakeup + Snooze There was an error setting the alarms, please try again. Alarms sent to device. No data. Synchronize device?