Compare commits

...

8 Commits

Author SHA1 Message Date
Martin.JM
facf87fc59 Limit smart alarm interval to 255 2024-02-24 09:56:56 +01:00
Martin.JM
91dc81d5dd Move snooze checkbox 2024-02-24 09:56:56 +01:00
Martin.JM
5968a04cf7 Change colors 2024-02-24 09:56:56 +01:00
Martin.JM
a4eaf66386 Change strings 2024-02-24 09:56:56 +01:00
Martin.JM
0eb2bf7dfa Fix bugs, cleanup, test device
Implemented the TestDevice, which showed some bugs.
Solved these bugs and cleaned up a bit in the process.
2024-02-24 09:56:56 +01:00
Martin.JM
71ea39efde [Huawei] Hookup smart wakeup interval and update Coordinators 2024-02-24 09:56:56 +01:00
Martin.JM
51024f7b5e Add smart wakeup interval 2024-02-24 09:56:56 +01:00
Martin.JM
37b5d0404a Update alarm unused and enabled states
- Set alarm as used when enabled in the list
- Set alarm as disabled when set as unused in the list
2024-02-24 09:56:56 +01:00
19 changed files with 183 additions and 44 deletions

View File

@ -45,7 +45,7 @@ public class GBDaoGenerator {
public static void main(String[] args) throws Exception {
final Schema schema = new Schema(70, MAIN_PACKAGE + ".entities");
final Schema schema = new Schema(71, MAIN_PACKAGE + ".entities");
Entity userAttributes = addUserAttributes(schema);
Entity user = addUserInfo(schema, userAttributes);
@ -835,6 +835,7 @@ public class GBDaoGenerator {
alarm.addIndex(indexUnique);
alarm.addBooleanProperty("enabled").notNull();
alarm.addBooleanProperty("smartWakeup").notNull();
alarm.addIntProperty("smartWakeupInterval");
alarm.addBooleanProperty("snooze").notNull();
alarm.addIntProperty("repetition").notNull().codeBeforeGetter(
"public boolean isRepetitive() { return getRepetition() != ALARM_ONCE; } " +

View File

@ -1,5 +1,5 @@
/* Copyright (C) 2015-2024 Andreas Shimokawa, Carsten Pfeiffer, Daniel
Dakhno, Daniele Gobbetti, Dmitry Markin, Lem Dulfo, Taavi Eomäe
Dakhno, Daniele Gobbetti, Dmitry Markin, Lem Dulfo, Taavi Eomäe, Martin.JM
This file is part of Gadgetbridge.
@ -19,6 +19,7 @@ package nodomain.freeyourgadget.gadgetbridge.activities;
import android.os.Bundle;
import android.text.InputFilter;
import android.text.Spanned;
import android.text.format.DateFormat;
import android.view.MenuItem;
import android.view.View;
@ -26,6 +27,8 @@ import android.widget.CheckedTextView;
import android.widget.EditText;
import android.widget.TimePicker;
import java.text.NumberFormat;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
@ -50,6 +53,7 @@ public class AlarmDetails extends AbstractGBActivity {
private CheckedTextView cbSunday;
private EditText title;
private EditText description;
private EditText smartWakeupInterval;
private GBDevice device;
@Override
@ -65,6 +69,7 @@ public class AlarmDetails extends AbstractGBActivity {
timePicker = findViewById(R.id.alarm_time_picker);
cbSmartWakeup = findViewById(R.id.alarm_cb_smart_wakeup);
smartWakeupInterval = findViewById(R.id.alarm_cb_smart_wakeup_interval);
cbSnooze = findViewById(R.id.alarm_cb_snooze);
cbMonday = findViewById(R.id.alarm_cb_monday);
cbTuesday = findViewById(R.id.alarm_cb_tuesday);
@ -78,6 +83,7 @@ public class AlarmDetails extends AbstractGBActivity {
cbSmartWakeup.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
((CheckedTextView) v).toggle();
smartWakeupInterval.setEnabled(((CheckedTextView) v).isChecked());
}
});
cbSnooze.setOnClickListener(new View.OnClickListener() {
@ -125,11 +131,50 @@ public class AlarmDetails extends AbstractGBActivity {
timePicker.setCurrentHour(alarm.getHour());
timePicker.setCurrentMinute(alarm.getMinute());
boolean smartAlarmSupported = supportsSmartWakeup(alarm.getPosition());
boolean smartAlarmForced = forcedSmartWakeup(alarm.getPosition());
boolean smartAlarmIntervalSupported = supportsSmartWakeupInterval(alarm.getPosition());
cbSmartWakeup.setChecked(alarm.getSmartWakeup() || smartAlarmForced);
int smartAlarmVisibility = supportsSmartWakeup(alarm.getPosition()) ? View.VISIBLE : View.GONE;
cbSmartWakeup.setVisibility(smartAlarmVisibility);
cbSmartWakeup.setEnabled(!smartAlarmForced);
cbSmartWakeup.setVisibility(smartAlarmSupported ? View.VISIBLE : View.GONE);
if (smartAlarmForced) {
cbSmartWakeup.setEnabled(false);
// Force the text to be visible for the "interval" part
// Enabled or not can still be seen in the checkmark
// TODO: I'd like feedback on this
if (GBApplication.isDarkThemeEnabled())
cbSmartWakeup.setTextColor(getResources().getColor(android.R.color.secondary_text_dark));
else
cbSmartWakeup.setTextColor(getResources().getColor(android.R.color.secondary_text_light));
}
if (smartAlarmIntervalSupported)
cbSmartWakeup.setText(R.string.alarm_smart_wakeup_interval);
smartWakeupInterval.setVisibility(smartAlarmSupported && smartAlarmIntervalSupported ? View.VISIBLE : View.GONE);
smartWakeupInterval.setEnabled(alarm.getSmartWakeup() || smartAlarmForced);
if (alarm.getSmartWakeupInterval() != null)
smartWakeupInterval.setText(NumberFormat.getInstance().format(alarm.getSmartWakeupInterval()));
smartWakeupInterval.setFilters(new InputFilter[] {
new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (dend >= 3) // Limit length
return "";
String strValue = dest.subSequence(0, dstart) + source.subSequence(start, end).toString() + dest.subSequence(dend, dest.length());
try {
int value = Integer.parseInt(strValue);
if (value > 255) {
smartWakeupInterval.setText("255");
smartWakeupInterval.setSelection(3); // Move cursor to end
}
} catch (NumberFormatException e) {
return "";
}
return null;
}
}
});
cbSnooze.setChecked(alarm.getSnooze());
int snoozeVisibility = supportsSnoozing() ? View.VISIBLE : View.GONE;
@ -163,6 +208,14 @@ public class AlarmDetails extends AbstractGBActivity {
return false;
}
private boolean supportsSmartWakeupInterval(int position) {
if (device != null) {
DeviceCoordinator coordinator = device.getDeviceCoordinator();
return coordinator.supportsSmartWakeupInterval(device, position);
}
return false;
}
/**
* The alarm at this position *must* be a smart alarm
*/
@ -224,6 +277,8 @@ public class AlarmDetails extends AbstractGBActivity {
alarm.setEnabled(true);
}
alarm.setSmartWakeup(supportsSmartWakeup(alarm.getPosition()) && cbSmartWakeup.isChecked());
String interval = smartWakeupInterval.getText().toString();
alarm.setSmartWakeupInterval(interval.equals("") ? null : Integer.parseInt(interval));
alarm.setSnooze(supportsSnoozing() && cbSnooze.isChecked());
int repetitionMask = AlarmUtils.createRepetitionMask(cbMonday.isChecked(), cbTuesday.isChecked(), cbWednesday.isChecked(), cbThursday.isChecked(), cbFriday.isChecked(), cbSaturday.isChecked(), cbSunday.isChecked());
alarm.setRepetition(repetitionMask);

View File

@ -147,7 +147,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, false, 0, 6, 30, false, null, null);
return new Alarm(device.getId(), user.getId(), position, false, false, null, false, 0, 6, 30, false, null, null);
}
@Override

View File

@ -88,6 +88,10 @@ public class GBAlarmListAdapter extends RecyclerView.Adapter<GBAlarmListAdapter.
holder.isEnabled.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
alarm.setUnused(false);
holder.container.setAlpha(1.0f);
}
alarm.setEnabled(isChecked);
updateInDB(alarm);
}
@ -104,6 +108,7 @@ public class GBAlarmListAdapter extends RecyclerView.Adapter<GBAlarmListAdapter.
public boolean onLongClick(View v) {
alarm.setUnused(!alarm.getUnused());
holder.container.setAlpha(alarm.getUnused() ? 0.5f : 1.0f);
holder.isEnabled.setChecked(false); // This falls through to the onCheckChanged function
updateInDB(alarm);
return true;
}

View File

@ -0,0 +1,38 @@
/* Copyright (C) 2024 Martin.JM
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 <https://www.gnu.org/licenses/>. */
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_71 implements DBUpdateScript {
@Override
public void upgradeSchema(final SQLiteDatabase db) {
if (!DBHelper.existsColumn(AlarmDao.TABLENAME, AlarmDao.Properties.SmartWakeupInterval.columnName, db)) {
final String statement = "ALTER TABLE " + AlarmDao.TABLENAME + " ADD COLUMN \""
+ AlarmDao.Properties.SmartWakeupInterval.columnName + "\" INTEGER";
db.execSQL(statement);
}
}
@Override
public void downgradeSchema(final SQLiteDatabase db) {
}
}

View File

@ -323,6 +323,11 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
return false;
}
@Override
public boolean supportsSmartWakeupInterval(GBDevice device, int alarmPosition) {
return false;
}
@Override
public boolean forcedSmartWakeup(GBDevice device, int alarmPosition) {
return false;

View File

@ -337,6 +337,12 @@ public interface DeviceCoordinator {
*/
boolean supportsSmartWakeup(GBDevice device, int alarmPosition);
/**
* Returns true if the smart alarm at the specified position supports setting an interval for this device/coordinator
* @param alarmPosition Position of the alarm
*/
boolean supportsSmartWakeupInterval(GBDevice device, int alarmPosition);
/**
* Returns true if the alarm at the specified position *must* be a smart alarm for this device/coordinator
* @param alarmPosition Position of the alarm

View File

@ -116,6 +116,11 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin
return huaweiCoordinator.supportsSmartAlarm(device, position);
}
@Override
public boolean supportsSmartWakeupInterval(GBDevice device, int alarmPosition) {
return supportsSmartWakeup(device, alarmPosition);
}
@Override
public boolean forcedSmartWakeup(GBDevice device, int alarmPosition) {
return huaweiCoordinator.forcedSmartWakeup(device, alarmPosition);
@ -136,12 +141,6 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin
return true;
}
@Override
public boolean supportsAlarmDescription(GBDevice device) {
// TODO: only name is supported
return true;
}
@Override
public boolean supportsWeather() {
return huaweiCoordinator.supportsWeather();

View File

@ -116,6 +116,11 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i
return huaweiCoordinator.supportsSmartAlarm(device, position);
}
@Override
public boolean supportsSmartWakeupInterval(GBDevice device, int alarmPosition) {
return supportsSmartWakeup(device, alarmPosition);
}
@Override
public boolean forcedSmartWakeup(GBDevice device, int alarmPosition) {
return huaweiCoordinator.forcedSmartWakeup(device, alarmPosition);
@ -136,12 +141,6 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i
return true;
}
@Override
public boolean supportsAlarmDescription(GBDevice device) {
// TODO: only name is supported
return true;
}
@Override
public boolean supportsWeather() {
return huaweiCoordinator.supportsWeather();

View File

@ -203,17 +203,29 @@ public class TestDeviceCoordinator extends AbstractDeviceCoordinator {
@Override
public int getAlarmSlotCount(final GBDevice device) {
/*
0: Forced smart, no interval
1: Forced smart, with interval
2: Unforced smart, no interval
3: Unforced smart, with interval
4: Not smart
*/
return 5;
}
@Override
public boolean supportsSmartWakeup(final GBDevice device, int position) {
return supports(getTestDevice(), TestFeature.SMART_WAKEUP) && position <= 2;
return supports(getTestDevice(), TestFeature.SMART_WAKEUP) && position <= 3;
}
@Override
public boolean supportsSmartWakeupInterval(GBDevice device, int alarmPosition) {
return supports(getTestDevice(), TestFeature.SMART_WAKEUP_INTERVAL) && (alarmPosition == 1 || alarmPosition == 3);
}
@Override
public boolean forcedSmartWakeup(final GBDevice device, final int alarmPosition) {
return supports(getTestDevice(), TestFeature.SMART_WAKEUP_FORCED_SLOT) && alarmPosition == 0;
return supports(getTestDevice(), TestFeature.SMART_WAKEUP_FORCED_SLOT) && alarmPosition <= 1;
}
@Override

View File

@ -56,6 +56,7 @@ public enum TestFeature {
SCREENSHOTS,
SLEEP_RESPIRATORY_RATE,
SMART_WAKEUP,
SMART_WAKEUP_INTERVAL,
SMART_WAKEUP_FORCED_SLOT,
SPO2,
STRESS_MEASUREMENT,

View File

@ -44,6 +44,8 @@ public interface Alarm extends Serializable {
boolean getSmartWakeup();
Integer getSmartWakeupInterval();
boolean getSnooze();
int getRepetition();

View File

@ -733,7 +733,7 @@ public class HuaweiSupportProvider {
title = context.getString(R.string.alarm_smart_wakeup);
description = context.getString(R.string.huawei_alarm_smart_description);
}
return new Alarm(device.getId(), user.getId(), position, false, smartWakeup, false, 0, 6, 30, true, title, description);
return new Alarm(device.getId(), user.getId(), position, false, smartWakeup, null, false, 0, 6, 30, true, title, description);
}
private void getAlarms() {

View File

@ -60,6 +60,7 @@ public class AlarmsRequest extends Request {
}
public void buildSmartAlarm(Alarm alarm) {
Integer smartWakeupInterval = alarm.getSmartWakeupInterval();
this.smartAlarmRequest = new SmartAlarmRequest(
paramsProvider,
new Alarms.SmartAlarm(
@ -67,7 +68,7 @@ public class AlarmsRequest extends Request {
(byte) alarm.getHour(),
(byte) alarm.getMinute(),
(byte) alarm.getRepetition(),
(byte) 5 // TODO: setting for ahead time
smartWakeupInterval == null ? 5 : smartWakeupInterval.byteValue()
)
);
}

View File

@ -66,6 +66,7 @@ public class GetEventAlarmList extends Request {
eventAlarm.index + positionOffset,
eventAlarm.status,
false,
null,
false,
eventAlarm.repeat,
eventAlarm.startHour,
@ -86,6 +87,7 @@ public class GetEventAlarmList extends Request {
i + positionOffset,
false,
false,
null,
false,
0,
0,

View File

@ -61,6 +61,7 @@ public class GetSmartAlarmList extends Request {
0,
smartAlarm.status,
true,
(int) smartAlarm.aheadTime,
false,
smartAlarm.repeat,
smartAlarm.startHour,
@ -79,6 +80,7 @@ public class GetSmartAlarmList extends Request {
0,
false,
true,
null,
false,
0,
0,

View File

@ -51,7 +51,8 @@ public class AlarmUtils {
* @return
*/
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, GBApplication.getContext().getString(R.string.quick_alarm), GBApplication.getContext().getString(R.string.quick_alarm_description));
// TODO: add interval setting?
return new Alarm(-1, -1, index, true, smartWakeup, null, snooze, Alarm.ALARM_ONCE, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), false, GBApplication.getContext().getString(R.string.quick_alarm), GBApplication.getContext().getString(R.string.quick_alarm_description));
}
/**
@ -130,7 +131,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, false, repetition, hour, minute, false, null, null);
return new Alarm(device.getId(), user.getId(), index, enabled, smartWakeup, null, false, repetition, hour, minute, false, null, null);
}
private static Comparator<Alarm> createComparator() {

View File

@ -23,26 +23,6 @@
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin">
<androidx.appcompat.widget.AppCompatCheckedTextView
android:id="@+id/alarm_cb_smart_wakeup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:drawableStart="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_smart_wakeup"
android:textAppearance="?android:attr/textAppearanceSmall" />
<androidx.appcompat.widget.AppCompatCheckedTextView
android:id="@+id/alarm_cb_snooze"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:drawableStart="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_snooze"
android:textAppearance="?android:attr/textAppearanceSmall" />
<EditText
android:id="@+id/alarm_title"
android:layout_width="match_parent"
@ -63,6 +43,34 @@
android:maxLength="256"
android:singleLine="false" />
<androidx.appcompat.widget.AppCompatCheckedTextView
android:id="@+id/alarm_cb_snooze"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:drawableStart="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_snooze"
android:textAppearance="?android:attr/textAppearanceSmall" />
<androidx.appcompat.widget.AppCompatCheckedTextView
android:id="@+id/alarm_cb_smart_wakeup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:drawableStart="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_smart_wakeup"
android:textAppearance="?android:attr/textAppearanceSmall" />
<EditText
android:id="@+id/alarm_cb_smart_wakeup_interval"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number"
android:hint="@string/alarm_smart_wakeup_interval_default" />
<TimePicker
android:id="@+id/alarm_time_picker"
android:layout_width="match_parent"

View File

@ -779,6 +779,8 @@
<string name="alarm_fri_short">Fri</string>
<string name="alarm_sat_short">Sat</string>
<string name="alarm_smart_wakeup">Smart wakeup</string>
<string name="alarm_smart_wakeup_interval">Smart wakeup interval:</string>
<string name="alarm_smart_wakeup_interval_default">5 minutes</string>
<string name="alarm_snooze">Snooze</string>
<string name="user_feedback_miband_set_alarms_failed">There was an error setting the alarms, please try again.</string>
<string name="user_feedback_miband_set_alarms_ok">Alarms sent to device.</string>