mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-27 12:26:48 +01:00
Improved DB-based alarms
- got rid of GBAlarm - added migration for prefs-based alarms - various cleanups
This commit is contained in:
parent
e7dc55821d
commit
903b50c2c5
@ -345,6 +345,7 @@ public class GBDaoGenerator {
|
||||
|
||||
private static void addAlarms(Schema schema, Entity user, Entity device) {
|
||||
Entity alarm = addEntity(schema, "Alarm");
|
||||
alarm.implementsInterface("nodomain.freeyourgadget.gadgetbridge.model.Alarm");
|
||||
Property deviceId = alarm.addLongProperty("deviceId").notNull().getProperty();
|
||||
Property userId = alarm.addLongProperty("userId").notNull().getProperty();
|
||||
Property position = alarm.addIntProperty("position").notNull().getProperty();
|
||||
@ -355,8 +356,11 @@ public class GBDaoGenerator {
|
||||
indexUnique.makeUnique();
|
||||
alarm.addIndex(indexUnique);
|
||||
alarm.addBooleanProperty("enabled").notNull();
|
||||
alarm.addBooleanProperty("smartAlarm").notNull();
|
||||
alarm.addIntProperty("repetition").notNull();
|
||||
alarm.addBooleanProperty("smartWakeup").notNull();
|
||||
alarm.addIntProperty("repetition").notNull().codeBeforeGetter(
|
||||
"public boolean isRepetitive() { return getRepetition() != ALARM_ONCE; } " +
|
||||
"public boolean getRepetition(int dow) { return (this.repetition & dow) > 0; }"
|
||||
);
|
||||
alarm.addIntProperty("hour").notNull();
|
||||
alarm.addIntProperty("minute").notNull();
|
||||
alarm.addToOne(user, userId);
|
||||
|
@ -31,7 +31,6 @@ import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
|
@ -26,14 +26,16 @@ import android.widget.TimePicker;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
|
||||
public class AlarmDetails extends AbstractGBActivity {
|
||||
|
||||
private GBAlarm alarm;
|
||||
private Alarm alarm;
|
||||
private TimePicker timePicker;
|
||||
private CheckedTextView cbSmartWakeup;
|
||||
private CheckedTextView cbMonday;
|
||||
@ -50,7 +52,7 @@ public class AlarmDetails extends AbstractGBActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_alarm_details);
|
||||
|
||||
alarm = getIntent().getParcelableExtra("alarm");
|
||||
alarm = (Alarm) getIntent().getSerializableExtra(nodomain.freeyourgadget.gadgetbridge.model.Alarm.EXTRA_ALARM);
|
||||
device = getIntent().getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||
|
||||
timePicker = findViewById(R.id.alarm_time_picker);
|
||||
@ -109,17 +111,17 @@ public class AlarmDetails extends AbstractGBActivity {
|
||||
timePicker.setCurrentHour(alarm.getHour());
|
||||
timePicker.setCurrentMinute(alarm.getMinute());
|
||||
|
||||
cbSmartWakeup.setChecked(alarm.isSmartWakeup());
|
||||
cbSmartWakeup.setChecked(alarm.getSmartWakeup());
|
||||
int smartAlarmVisibility = supportsSmartWakeup() ? View.VISIBLE : View.GONE;
|
||||
cbSmartWakeup.setVisibility(smartAlarmVisibility);
|
||||
|
||||
cbMonday.setChecked(alarm.getRepetition(GBAlarm.ALARM_MON));
|
||||
cbTuesday.setChecked(alarm.getRepetition(GBAlarm.ALARM_TUE));
|
||||
cbWednesday.setChecked(alarm.getRepetition(GBAlarm.ALARM_WED));
|
||||
cbThursday.setChecked(alarm.getRepetition(GBAlarm.ALARM_THU));
|
||||
cbFriday.setChecked(alarm.getRepetition(GBAlarm.ALARM_FRI));
|
||||
cbSaturday.setChecked(alarm.getRepetition(GBAlarm.ALARM_SAT));
|
||||
cbSunday.setChecked(alarm.getRepetition(GBAlarm.ALARM_SUN));
|
||||
cbMonday.setChecked(alarm.getRepetition(Alarm.ALARM_MON));
|
||||
cbTuesday.setChecked(alarm.getRepetition(Alarm.ALARM_TUE));
|
||||
cbWednesday.setChecked(alarm.getRepetition(Alarm.ALARM_WED));
|
||||
cbThursday.setChecked(alarm.getRepetition(Alarm.ALARM_THU));
|
||||
cbFriday.setChecked(alarm.getRepetition(Alarm.ALARM_FRI));
|
||||
cbSaturday.setChecked(alarm.getRepetition(Alarm.ALARM_SAT));
|
||||
cbSunday.setChecked(alarm.getRepetition(Alarm.ALARM_SUN));
|
||||
|
||||
}
|
||||
|
||||
@ -144,10 +146,11 @@ public class AlarmDetails extends AbstractGBActivity {
|
||||
|
||||
private void updateAlarm() {
|
||||
alarm.setSmartWakeup(supportsSmartWakeup() && cbSmartWakeup.isChecked());
|
||||
alarm.setRepetition(cbMonday.isChecked(), cbTuesday.isChecked(), cbWednesday.isChecked(), cbThursday.isChecked(), cbFriday.isChecked(), cbSaturday.isChecked(), cbSunday.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());
|
||||
alarm.setMinute(timePicker.getCurrentMinute());
|
||||
alarm.store();
|
||||
DBHelper.store(alarm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,31 +19,33 @@ package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.GBAlarmListAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AlarmDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
|
||||
public class ConfigureAlarms extends AbstractGBActivity {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ConfigureAlarms.class);
|
||||
|
||||
private static final int REQ_CONFIGURE_ALARM = 1;
|
||||
|
||||
@ -84,42 +86,46 @@ public class ConfigureAlarms extends AbstractGBActivity {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the available alarms from the database and updates the view afterwards.
|
||||
*/
|
||||
private void updateAlarmsFromDB() {
|
||||
Prefs prefs = GBApplication.getPrefs();
|
||||
int reservedSlots = prefs.getInt(MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, 0);
|
||||
|
||||
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
|
||||
int alarmSlots = coordinator.getAlarmSlotCount();
|
||||
|
||||
Long deviceId;
|
||||
List<Alarm> allAlarms = null;
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
AlarmDao alarmDao = db.getDaoSession().getAlarmDao();
|
||||
Device dbDevice = DBHelper.findDevice(gbDevice, db.getDaoSession());
|
||||
deviceId = dbDevice.getId();
|
||||
QueryBuilder<Alarm> qb = alarmDao.queryBuilder();
|
||||
qb.where(AlarmDao.Properties.DeviceId.eq(deviceId)).orderAsc(AlarmDao.Properties.Position).limit(alarmSlots - reservedSlots);
|
||||
allAlarms = qb.build().list();
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
List<Alarm> alarms = DBHelper.getAlarms(getGbDevice());
|
||||
if (alarms.isEmpty()) {
|
||||
alarms = AlarmUtils.readAlarmsFromPrefs(getGbDevice());
|
||||
storeMigratedAlarms(alarms);
|
||||
}
|
||||
addMissingAlarms(alarms);
|
||||
|
||||
List<GBAlarm> gbAlarms = new ArrayList<>();
|
||||
if (allAlarms != null) {
|
||||
for (Alarm alarm : allAlarms) {
|
||||
gbAlarms.add(new GBAlarm(deviceId, alarm.getPosition(), alarm.getEnabled(),
|
||||
alarm.getSmartAlarm(), alarm.getRepetition(), alarm.getHour(), alarm.getMinute()));
|
||||
mGBAlarmListAdapter.setAlarmList(alarms);
|
||||
mGBAlarmListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void storeMigratedAlarms(List<Alarm> alarms) {
|
||||
for (Alarm alarm : alarms) {
|
||||
DBHelper.store(alarm);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMissingAlarms(List<Alarm> alarms) {
|
||||
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(getGbDevice());
|
||||
int supportedNumAlarms = coordinator.getAlarmSlotCount();
|
||||
if (supportedNumAlarms > alarms.size()) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
DaoSession daoSession = db.getDaoSession();
|
||||
Device device = DBHelper.getDevice(getGbDevice(), daoSession);
|
||||
User user = DBHelper.getUser(daoSession);
|
||||
while (supportedNumAlarms > alarms.size()) {
|
||||
alarms.add(createDefaultAlarm(device, user, alarms.size()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error accessing database", e);
|
||||
}
|
||||
}
|
||||
int hour = 5;
|
||||
while (gbAlarms.size() < alarmSlots) {
|
||||
GBAlarm gbAlarm = new GBAlarm(deviceId, gbAlarms.size(), false, false, 31, hour++, 30);
|
||||
gbAlarms.add(gbAlarm);
|
||||
gbAlarm.store();
|
||||
}
|
||||
}
|
||||
|
||||
mGBAlarmListAdapter.setAlarmList(gbAlarms);
|
||||
mGBAlarmListAdapter.notifyDataSetChanged();
|
||||
private Alarm createDefaultAlarm(@NonNull Device device, @NonNull User user, int position) {
|
||||
return new Alarm(device.getId(), user.getId(), position, false, false,0, 6, 30);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -133,10 +139,10 @@ public class ConfigureAlarms extends AbstractGBActivity {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
public void configureAlarm(GBAlarm alarm) {
|
||||
public void configureAlarm(Alarm alarm) {
|
||||
avoidSendAlarmsToDevice = true;
|
||||
Intent startIntent = new Intent(getApplicationContext(), AlarmDetails.class);
|
||||
startIntent.putExtra("alarm", alarm);
|
||||
startIntent.putExtra(Alarm.EXTRA_ALARM, alarm);
|
||||
startIntent.putExtra(GBDevice.EXTRA_DEVICE, getGbDevice());
|
||||
startActivityForResult(startIntent, REQ_CONFIGURE_ALARM);
|
||||
}
|
||||
|
@ -35,33 +35,32 @@ import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
|
||||
/**
|
||||
* Adapter for displaying GBAlarm instances.
|
||||
*/
|
||||
public class GBAlarmListAdapter extends RecyclerView.Adapter<GBAlarmListAdapter.ViewHolder> {
|
||||
|
||||
|
||||
private final Context mContext;
|
||||
private List<GBAlarm> alarmList;
|
||||
private ArrayList<Alarm> alarmList;
|
||||
|
||||
public GBAlarmListAdapter(Context context) {
|
||||
this.mContext = context;
|
||||
}
|
||||
|
||||
public void setAlarmList(List<GBAlarm> alarmList) {
|
||||
this.alarmList = alarmList;
|
||||
public void setAlarmList(List<Alarm> alarms) {
|
||||
this.alarmList = new ArrayList<>(alarms);
|
||||
}
|
||||
|
||||
public ArrayList getAlarmList() {
|
||||
return (ArrayList) alarmList;
|
||||
public ArrayList<Alarm> getAlarmList() {
|
||||
return alarmList;
|
||||
}
|
||||
|
||||
|
||||
public void update(GBAlarm alarm) {
|
||||
alarm.store();
|
||||
private void updateInDB(Alarm alarm) {
|
||||
DBHelper.store(alarm);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -74,7 +73,7 @@ public class GBAlarmListAdapter extends RecyclerView.Adapter<GBAlarmListAdapter.
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
|
||||
|
||||
final GBAlarm alarm = alarmList.get(position);
|
||||
final Alarm alarm = alarmList.get(position);
|
||||
|
||||
holder.alarmDayMonday.setChecked(alarm.getRepetition(Alarm.ALARM_MON));
|
||||
holder.alarmDayTuesday.setChecked(alarm.getRepetition(Alarm.ALARM_TUE));
|
||||
@ -88,7 +87,7 @@ public class GBAlarmListAdapter extends RecyclerView.Adapter<GBAlarmListAdapter.
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
alarm.setEnabled(isChecked);
|
||||
update(alarm);
|
||||
updateInDB(alarm);
|
||||
}
|
||||
});
|
||||
|
||||
@ -98,16 +97,15 @@ public class GBAlarmListAdapter extends RecyclerView.Adapter<GBAlarmListAdapter.
|
||||
((ConfigureAlarms) mContext).configureAlarm(alarm);
|
||||
}
|
||||
});
|
||||
holder.alarmTime.setText(alarm.getTime());
|
||||
holder.isEnabled.setChecked(alarm.isEnabled());
|
||||
if (alarm.isSmartWakeup()) {
|
||||
holder.alarmTime.setText(DateTimeUtils.formatTime(alarm.getHour(), alarm.getMinute()));
|
||||
holder.isEnabled.setChecked(alarm.getEnabled());
|
||||
if (alarm.getSmartWakeup()) {
|
||||
holder.isSmartWakeup.setVisibility(TextView.VISIBLE);
|
||||
} else {
|
||||
holder.isSmartWakeup.setVisibility(TextView.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return alarmList.size();
|
||||
|
@ -21,7 +21,6 @@ import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
@ -33,6 +32,7 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -44,8 +44,11 @@ import de.greenrobot.dao.query.QueryBuilder;
|
||||
import de.greenrobot.dao.query.WhereCondition;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.ActivityDescription;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.ActivityDescriptionDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AlarmDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DeviceAttributes;
|
||||
@ -62,6 +65,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ValidByDate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
|
||||
/**
|
||||
@ -362,6 +366,13 @@ public class DBHelper {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the corresponding Device entity for the given GBDevice.
|
||||
* @param gbDevice
|
||||
* @param session
|
||||
* @return the corresponding Device entity, or null if none
|
||||
*/
|
||||
@Nullable
|
||||
public static Device findDevice(GBDevice gbDevice, DaoSession session) {
|
||||
DeviceDao deviceDao = session.getDeviceDao();
|
||||
Query<Device> query = deviceDao.queryBuilder().where(DeviceDao.Properties.Identifier.eq(gbDevice.getAddress())).build();
|
||||
@ -561,6 +572,49 @@ public class DBHelper {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all user-configurable alarms for the given user and device. The list is sorted by
|
||||
* {@link Alarm#position}. Calendar events that may also be modeled as alarms are not stored
|
||||
* in the database and hence not returned by this method.
|
||||
* @param gbDevice the device for which the alarms shall be loaded
|
||||
* @return the list of alarms for the given device
|
||||
*/
|
||||
@NonNull
|
||||
public static List<Alarm> getAlarms(@NonNull GBDevice gbDevice) {
|
||||
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
|
||||
Prefs prefs = GBApplication.getPrefs();
|
||||
// TODO: this alarm reservation is a device dependent detail
|
||||
int reservedSlots = prefs.getInt(MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, 0);
|
||||
int alarmSlots = coordinator.getAlarmSlotCount();
|
||||
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
DaoSession daoSession = db.getDaoSession();
|
||||
User user = getUser(daoSession);
|
||||
Device dbDevice = DBHelper.findDevice(gbDevice, daoSession);
|
||||
if (dbDevice != null) {
|
||||
AlarmDao alarmDao = daoSession.getAlarmDao();
|
||||
Long deviceId = dbDevice.getId();
|
||||
QueryBuilder<Alarm> qb = alarmDao.queryBuilder();
|
||||
qb.where(
|
||||
AlarmDao.Properties.UserId.eq(user.getId()),
|
||||
AlarmDao.Properties.DeviceId.eq(deviceId)).orderAsc(AlarmDao.Properties.Position).limit(alarmSlots - reservedSlots);
|
||||
return qb.build().list();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Error reading alarms from db", e);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public static void store(Alarm alarm) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
DaoSession daoSession = db.getDaoSession();
|
||||
daoSession.insertOrReplace(alarm);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error acquiring database", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearSession() {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
DaoSession session = dbHandler.getDaoSession();
|
||||
|
@ -1,215 +0,0 @@
|
||||
/* Copyright (C) 2015-2018 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 <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.impl;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Locale;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
|
||||
|
||||
public class GBAlarm implements Alarm {
|
||||
|
||||
private final int index;
|
||||
private boolean enabled;
|
||||
private boolean smartWakeup;
|
||||
private int repetition;
|
||||
private int hour;
|
||||
private int minute;
|
||||
private long deviceId;
|
||||
|
||||
public GBAlarm(Long deviceId, int index, boolean enabled, boolean smartWakeup, int repetition, int hour, int minute) {
|
||||
this.deviceId = deviceId;
|
||||
this.index = index;
|
||||
this.enabled = enabled;
|
||||
this.smartWakeup = smartWakeup;
|
||||
this.repetition = repetition;
|
||||
this.hour = hour;
|
||||
this.minute = minute;
|
||||
}
|
||||
|
||||
public static GBAlarm createSingleShot(long deviceId, int index, boolean smartWakeup, Calendar calendar) {
|
||||
return new GBAlarm(deviceId, index, true, smartWakeup, Alarm.ALARM_ONCE, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE));
|
||||
}
|
||||
|
||||
private static GBAlarm readFromParcel(Parcel pc) {
|
||||
long deviceId = pc.readLong();
|
||||
int index = pc.readInt();
|
||||
boolean enabled = Boolean.parseBoolean(pc.readString());
|
||||
boolean smartWakeup = Boolean.parseBoolean(pc.readString());
|
||||
int repetition = pc.readInt();
|
||||
int hour = pc.readInt();
|
||||
int minute = pc.readInt();
|
||||
return new GBAlarm(deviceId, index, enabled, smartWakeup, repetition, hour, minute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof GBAlarm) {
|
||||
GBAlarm comp = (GBAlarm) o;
|
||||
return comp.getIndex() == getIndex();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(deviceId);
|
||||
dest.writeInt(this.index);
|
||||
dest.writeString(String.valueOf(this.enabled));
|
||||
dest.writeString(String.valueOf(this.smartWakeup));
|
||||
dest.writeInt(this.repetition);
|
||||
dest.writeInt(this.hour);
|
||||
dest.writeInt(this.minute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull Alarm another) {
|
||||
if (this.getIndex() < another.getIndex()) {
|
||||
return -1;
|
||||
} else if (this.getIndex() > another.getIndex()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex() {
|
||||
return this.index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTime() {
|
||||
return String.format(Locale.US, "%02d", this.hour) + ":" + String.format(Locale.US, "%02d", this.minute);
|
||||
}
|
||||
|
||||
public int getHour() {
|
||||
return this.hour;
|
||||
}
|
||||
|
||||
public int getMinute() {
|
||||
return this.minute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar getAlarmCal() {
|
||||
|
||||
Calendar alarm = Calendar.getInstance();
|
||||
Calendar now = Calendar.getInstance();
|
||||
alarm.set(Calendar.HOUR_OF_DAY, this.hour);
|
||||
alarm.set(Calendar.MINUTE, this.minute);
|
||||
if (now.after(alarm) && repetition == ALARM_ONCE) {
|
||||
//if the alarm is in the past set it to tomorrow
|
||||
alarm.add(Calendar.DATE, 1);
|
||||
}
|
||||
return alarm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSmartWakeup() {
|
||||
return this.smartWakeup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRepetition(int dow) {
|
||||
return (this.repetition & dow) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRepetitionMask() {
|
||||
return this.repetition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepetitive() {
|
||||
return getRepetitionMask() != ALARM_ONCE;
|
||||
}
|
||||
|
||||
public void setSmartWakeup(boolean smartWakeup) {
|
||||
this.smartWakeup = smartWakeup;
|
||||
}
|
||||
|
||||
public void setRepetition(boolean mon, boolean tue, boolean wed, boolean thu, boolean fri, boolean sat, boolean sun) {
|
||||
this.repetition = (mon ? ALARM_MON : 0) |
|
||||
(tue ? ALARM_TUE : 0) |
|
||||
(wed ? ALARM_WED : 0) |
|
||||
(thu ? ALARM_THU : 0) |
|
||||
(fri ? ALARM_FRI : 0) |
|
||||
(sat ? ALARM_SAT : 0) |
|
||||
(sun ? ALARM_SUN : 0);
|
||||
}
|
||||
|
||||
public void setHour(int hour) {
|
||||
this.hour = hour;
|
||||
}
|
||||
|
||||
public void setMinute(int minute) {
|
||||
this.minute = minute;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public void store() {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
DaoSession daoSession = db.getDaoSession();
|
||||
Long userId = DBHelper.getUser(daoSession).getId();
|
||||
nodomain.freeyourgadget.gadgetbridge.entities.Alarm alarm = new nodomain.freeyourgadget.gadgetbridge.entities.Alarm(deviceId, userId, index, enabled, smartWakeup, repetition, hour, minute);
|
||||
daoSession.insertOrReplace(alarm);
|
||||
} catch (Exception e) {
|
||||
// LOG.error("Error acquiring database", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Creator CREATOR = new Creator() {
|
||||
@Override
|
||||
public GBAlarm createFromParcel(Parcel in) {
|
||||
return readFromParcel(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GBAlarm[] newArray(int size) {
|
||||
return new GBAlarm[size];
|
||||
}
|
||||
|
||||
};
|
||||
}
|
@ -176,7 +176,7 @@ public class GBDeviceService implements DeviceService {
|
||||
@Override
|
||||
public void onSetAlarms(ArrayList<? extends Alarm> alarms) {
|
||||
Intent intent = createIntent().setAction(ACTION_SET_ALARMS)
|
||||
.putParcelableArrayListExtra(EXTRA_ALARMS, alarms);
|
||||
.putExtra(EXTRA_ALARMS, alarms);
|
||||
invokeService(intent);
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,14 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.Calendar;
|
||||
public interface Alarm extends Serializable {
|
||||
/**
|
||||
* The {@link android.os.Bundle} name for transferring pacreled alarms.
|
||||
*/
|
||||
String EXTRA_ALARM = "alarm";
|
||||
|
||||
public interface Alarm extends Parcelable, Comparable<Alarm> {
|
||||
byte ALARM_ONCE = 0;
|
||||
byte ALARM_MON = 1;
|
||||
byte ALARM_TUE = 2;
|
||||
@ -30,19 +33,19 @@ public interface Alarm extends Parcelable, Comparable<Alarm> {
|
||||
byte ALARM_SAT = 32;
|
||||
byte ALARM_SUN = 64;
|
||||
|
||||
int getIndex();
|
||||
int getPosition();
|
||||
|
||||
Calendar getAlarmCal();
|
||||
boolean getEnabled();
|
||||
|
||||
String getTime();
|
||||
boolean getSmartWakeup();
|
||||
|
||||
boolean isEnabled();
|
||||
|
||||
boolean isSmartWakeup();
|
||||
|
||||
int getRepetitionMask();
|
||||
int getRepetition();
|
||||
|
||||
boolean isRepetitive();
|
||||
|
||||
boolean getRepetition(int dow);
|
||||
}
|
||||
|
||||
int getHour();
|
||||
|
||||
int getMinute();
|
||||
}
|
@ -548,7 +548,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
}
|
||||
break;
|
||||
case ACTION_SET_ALARMS:
|
||||
ArrayList<Alarm> alarms = intent.getParcelableArrayListExtra(EXTRA_ALARMS);
|
||||
ArrayList<? extends Alarm> alarms = (ArrayList<? extends Alarm>) intent.getSerializableExtra(EXTRA_ALARMS);
|
||||
mDeviceSupport.onSetAlarms(alarms);
|
||||
break;
|
||||
case ACTION_ENABLE_REALTIME_STEPS: {
|
||||
|
@ -58,6 +58,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
@ -430,13 +431,13 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
for (Alarm alarm : alarms) {
|
||||
|
||||
if (!alarm.isEnabled())
|
||||
if (!alarm.getEnabled())
|
||||
continue;
|
||||
|
||||
if (alarm.isSmartWakeup()) //Not available
|
||||
if (alarm.getSmartWakeup()) //Not available
|
||||
continue;
|
||||
|
||||
Calendar t = alarm.getAlarmCal();
|
||||
Calendar t = AlarmUtils.toCalendar(alarm);
|
||||
setAlarm(builder, t);
|
||||
builder.queue(getQueue());
|
||||
|
||||
|
@ -72,11 +72,11 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AlarmDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||
@ -113,6 +113,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.Upd
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.RealtimeSamplesSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils;
|
||||
@ -614,7 +615,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
TransactionBuilder builder = performInitialized("Set alarm");
|
||||
boolean anyAlarmEnabled = false;
|
||||
for (Alarm alarm : alarms) {
|
||||
anyAlarmEnabled |= alarm.isEnabled();
|
||||
anyAlarmEnabled |= alarm.getEnabled();
|
||||
queueAlarm(alarm, builder, characteristic);
|
||||
}
|
||||
builder.queue(getQueue());
|
||||
@ -1402,29 +1403,29 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
* @param characteristic
|
||||
*/
|
||||
private void queueAlarm(Alarm alarm, TransactionBuilder builder, BluetoothGattCharacteristic characteristic) {
|
||||
Calendar calendar = alarm.getAlarmCal();
|
||||
Calendar calendar = AlarmUtils.toCalendar(alarm);
|
||||
|
||||
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
|
||||
int maxAlarms = coordinator.getAlarmSlotCount();
|
||||
|
||||
if (alarm.getIndex() >= maxAlarms) {
|
||||
if (alarm.isEnabled()) {
|
||||
if (alarm.getPosition() >= maxAlarms) {
|
||||
if (alarm.getEnabled()) {
|
||||
GB.toast(getContext(), "Only " + maxAlarms + " alarms are currently supported.", Toast.LENGTH_LONG, GB.WARN);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int base = 0;
|
||||
if (alarm.isEnabled()) {
|
||||
if (alarm.getEnabled()) {
|
||||
base = 128;
|
||||
}
|
||||
int daysMask = alarm.getRepetitionMask();
|
||||
int daysMask = alarm.getRepetition();
|
||||
if (!alarm.isRepetitive()) {
|
||||
daysMask = 128;
|
||||
}
|
||||
byte[] alarmMessage = new byte[] {
|
||||
(byte) 0x2, // TODO what is this?
|
||||
(byte) (base + alarm.getIndex()), // 128 is the base, alarm slot is added
|
||||
(byte) (base + alarm.getPosition()), // 128 is the base, alarm slot is added
|
||||
(byte) calendar.get(Calendar.HOUR_OF_DAY),
|
||||
(byte) calendar.get(Calendar.MINUTE),
|
||||
(byte) daysMask,
|
||||
@ -1477,14 +1478,6 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
CalendarEvents upcomingEvents = new CalendarEvents();
|
||||
List<CalendarEvents.CalendarEvent> mEvents = upcomingEvents.getCalendarEventList(getContext());
|
||||
|
||||
Long deviceId;
|
||||
try (DBHandler handler = GBApplication.acquireDB()) {
|
||||
DaoSession session = handler.getDaoSession();
|
||||
deviceId = DBHelper.getDevice(getDevice(), session).getId();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Could not acquire DB", e);
|
||||
return this;
|
||||
}
|
||||
int iteration = 0;
|
||||
|
||||
for (CalendarEvents.CalendarEvent mEvt : mEvents) {
|
||||
@ -1494,7 +1487,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
int slotToUse = 2 - iteration;
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(mEvt.getBegin());
|
||||
Alarm alarm = GBAlarm.createSingleShot(deviceId, slotToUse, false, calendar);
|
||||
Alarm alarm = AlarmUtils.createSingleShot(slotToUse, false, calendar);
|
||||
queueAlarm(alarm, builder, characteristic);
|
||||
iteration++;
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
@ -277,11 +278,11 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
||||
default:
|
||||
return;
|
||||
}
|
||||
Calendar cal = alarms.get(i).getAlarmCal();
|
||||
Calendar cal = AlarmUtils.toCalendar(alarms.get(i));
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
cmd,
|
||||
alarms.get(i).isEnabled() ? cal.get(Calendar.HOUR_OF_DAY) : -1,
|
||||
alarms.get(i).isEnabled() ? cal.get(Calendar.MINUTE) : -1
|
||||
alarms.get(i).getEnabled() ? cal.get(Calendar.HOUR_OF_DAY) : -1,
|
||||
alarms.get(i).getEnabled() ? cal.get(Calendar.MINUTE) : -1
|
||||
));
|
||||
}
|
||||
builder.queue(getQueue());
|
||||
|
@ -56,7 +56,6 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
@ -87,6 +86,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotific
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.FetchActivityOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.UpdateFirmwareOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils;
|
||||
@ -560,7 +560,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
TransactionBuilder builder = performInitialized("Set alarm");
|
||||
boolean anyAlarmEnabled = false;
|
||||
for (Alarm alarm : alarms) {
|
||||
anyAlarmEnabled |= alarm.isEnabled();
|
||||
anyAlarmEnabled |= alarm.getEnabled();
|
||||
queueAlarm(alarm, builder, characteristic);
|
||||
}
|
||||
builder.queue(getQueue());
|
||||
@ -1134,20 +1134,20 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
* @param characteristic
|
||||
*/
|
||||
private void queueAlarm(Alarm alarm, TransactionBuilder builder, BluetoothGattCharacteristic characteristic) {
|
||||
byte[] alarmCalBytes = MiBandDateConverter.calendarToRawBytes(alarm.getAlarmCal());
|
||||
byte[] alarmCalBytes = MiBandDateConverter.calendarToRawBytes(AlarmUtils.toCalendar(alarm));
|
||||
|
||||
byte[] alarmMessage = new byte[]{
|
||||
MiBandService.COMMAND_SET_TIMER,
|
||||
(byte) alarm.getIndex(),
|
||||
(byte) (alarm.isEnabled() ? 1 : 0),
|
||||
(byte) alarm.getPosition(),
|
||||
(byte) (alarm.getEnabled() ? 1 : 0),
|
||||
alarmCalBytes[0],
|
||||
alarmCalBytes[1],
|
||||
alarmCalBytes[2],
|
||||
alarmCalBytes[3],
|
||||
alarmCalBytes[4],
|
||||
alarmCalBytes[5],
|
||||
(byte) (alarm.isSmartWakeup() ? 30 : 0),
|
||||
(byte) alarm.getRepetitionMask()
|
||||
(byte) (alarm.getSmartWakeup() ? 30 : 0),
|
||||
(byte) alarm.getRepetition()
|
||||
};
|
||||
builder.write(characteristic, alarmMessage);
|
||||
}
|
||||
@ -1231,15 +1231,6 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
CalendarEvents upcomingEvents = new CalendarEvents();
|
||||
List<CalendarEvents.CalendarEvent> mEvents = upcomingEvents.getCalendarEventList(getContext());
|
||||
|
||||
Long deviceId;
|
||||
try (DBHandler handler = GBApplication.acquireDB()) {
|
||||
DaoSession session = handler.getDaoSession();
|
||||
deviceId = DBHelper.getDevice(getDevice(), session).getId();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Could not acquire DB", e);
|
||||
return;
|
||||
}
|
||||
|
||||
int iteration = 0;
|
||||
for (CalendarEvents.CalendarEvent mEvt : mEvents) {
|
||||
if (iteration >= availableSlots || iteration > 2) {
|
||||
@ -1248,7 +1239,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
int slotToUse = 2 - iteration;
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(mEvt.getBegin());
|
||||
Alarm alarm = GBAlarm.createSingleShot(deviceId, slotToUse, false, calendar);
|
||||
Alarm alarm = AlarmUtils.createSingleShot(slotToUse, false, calendar);
|
||||
queueAlarm(alarm, builder, characteristic);
|
||||
iteration++;
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
import static org.apache.commons.lang3.math.NumberUtils.min;
|
||||
@ -188,20 +189,20 @@ public class No1F1Support extends AbstractBTLEDeviceSupport {
|
||||
TransactionBuilder builder = performInitialized("Set alarm");
|
||||
boolean anyAlarmEnabled = false;
|
||||
for (Alarm alarm : alarms) {
|
||||
anyAlarmEnabled |= alarm.isEnabled();
|
||||
Calendar calendar = alarm.getAlarmCal();
|
||||
anyAlarmEnabled |= alarm.getEnabled();
|
||||
Calendar calendar = AlarmUtils.toCalendar(alarm);
|
||||
|
||||
int maxAlarms = 3;
|
||||
if (alarm.getIndex() >= maxAlarms) {
|
||||
if (alarm.isEnabled()) {
|
||||
if (alarm.getPosition() >= maxAlarms) {
|
||||
if (alarm.getEnabled()) {
|
||||
GB.toast(getContext(), "Only 3 alarms are supported.", Toast.LENGTH_LONG, GB.WARN);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int daysMask = 0;
|
||||
if (alarm.isEnabled()) {
|
||||
daysMask = alarm.getRepetitionMask();
|
||||
if (alarm.getEnabled()) {
|
||||
daysMask = alarm.getRepetition();
|
||||
// Mask for this device starts from sunday and not from monday.
|
||||
daysMask = (daysMask / 64) + (daysMask >> 1);
|
||||
}
|
||||
@ -210,11 +211,11 @@ public class No1F1Support extends AbstractBTLEDeviceSupport {
|
||||
(byte) daysMask,
|
||||
(byte) calendar.get(Calendar.HOUR_OF_DAY),
|
||||
(byte) calendar.get(Calendar.MINUTE),
|
||||
(byte) (alarm.isEnabled() ? 2 : 0), // vibration duration
|
||||
(byte) (alarm.isEnabled() ? 10 : 0), // vibration count
|
||||
(byte) (alarm.isEnabled() ? 2 : 0), // unknown
|
||||
(byte) (alarm.getEnabled() ? 2 : 0), // vibration duration
|
||||
(byte) (alarm.getEnabled() ? 10 : 0), // vibration count
|
||||
(byte) (alarm.getEnabled() ? 2 : 0), // unknown
|
||||
(byte) 0,
|
||||
(byte) (alarm.getIndex() + 1)
|
||||
(byte) (alarm.getPosition() + 1)
|
||||
};
|
||||
builder.write(ctrlCharacteristic, alarmMessage);
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.watch9.operations.InitOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
|
||||
|
||||
public class Watch9DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
@ -331,7 +332,7 @@ public class Watch9DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("setAlarms");
|
||||
for (Alarm alarm : alarms) {
|
||||
setAlarm(alarm, alarm.getIndex() + 1, builder);
|
||||
setAlarm(alarm, alarm.getPosition() + 1, builder);
|
||||
}
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException e) {
|
||||
@ -352,14 +353,14 @@ public class Watch9DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
private void setAlarm(Alarm alarm, int index, TransactionBuilder builder) {
|
||||
// Shift the GB internal repetition mask to match the device specific one.
|
||||
byte repetitionMask = (byte) ((alarm.getRepetitionMask() << 1) | (alarm.isRepetitive() ? 0x80 : 0x00));
|
||||
byte repetitionMask = (byte) ((alarm.getRepetition() << 1) | (alarm.isRepetitive() ? 0x80 : 0x00));
|
||||
repetitionMask |= (alarm.getRepetition(Alarm.ALARM_SUN) ? 0x01 : 0x00);
|
||||
if (0 < index && index < 4) {
|
||||
byte[] alarmValue = new byte[]{(byte) index,
|
||||
Conversion.toBcd8(alarm.getAlarmCal().get(Calendar.HOUR_OF_DAY)),
|
||||
Conversion.toBcd8(alarm.getAlarmCal().get(Calendar.MINUTE)),
|
||||
Conversion.toBcd8(AlarmUtils.toCalendar(alarm).get(Calendar.HOUR_OF_DAY)),
|
||||
Conversion.toBcd8(AlarmUtils.toCalendar(alarm).get(Calendar.MINUTE)),
|
||||
repetitionMask,
|
||||
(byte) (alarm.isEnabled() ? 0x01 : 0x00),
|
||||
(byte) (alarm.getEnabled() ? 0x01 : 0x00),
|
||||
0x00 // TODO: Unknown
|
||||
};
|
||||
builder.write(getCharacteristic(Watch9Constants.UUID_CHARACTERISTIC_WRITE),
|
||||
|
@ -0,0 +1,131 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.util;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
/**
|
||||
* Some utility methods for dealing with Alarms.
|
||||
*/
|
||||
public class AlarmUtils {
|
||||
/**
|
||||
* Creates an auto-generated (not user-configurable), non-recurring alarm. This alarm
|
||||
* may not be stored in the database. Some features are not available (e.g. device id, user id).
|
||||
* @param index
|
||||
* @param smartWakeup
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Calendar object representing the time of the given alarm (not taking the
|
||||
* day/date into account.
|
||||
* @param alarm
|
||||
* @return
|
||||
*/
|
||||
public static Calendar toCalendar(nodomain.freeyourgadget.gadgetbridge.model.Alarm alarm) {
|
||||
Calendar result = Calendar.getInstance();
|
||||
Calendar now = Calendar.getInstance();
|
||||
result.set(Calendar.HOUR_OF_DAY, alarm.getHour());
|
||||
result.set(Calendar.MINUTE, alarm.getMinute());
|
||||
if (now.after(result) && alarm.getRepetition() == Alarm.ALARM_ONCE) {
|
||||
//if the alarm is in the past set it to tomorrow
|
||||
result.add(Calendar.DATE, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a repetition mask suitable for {@link Alarm#repetition}
|
||||
* @param mon whether the alarm shall repeat every Monday
|
||||
* @param tue whether the alarm shall repeat every Tuesday
|
||||
* @param wed whether the alarm shall repeat every Wednesday
|
||||
* @param thu whether the alarm shall repeat every Thursday
|
||||
* @param fri whether the alarm shall repeat every Friday
|
||||
* @param sat whether the alarm shall repeat every Saturday
|
||||
* @param sun whether the alarm shall repeat every Sunday
|
||||
* @return the created repetition mask
|
||||
*/
|
||||
public static int createRepetitionMassk(boolean mon, boolean tue, boolean wed, boolean thu, boolean fri, boolean sat, boolean sun) {
|
||||
int repetitionMask = (mon ? Alarm.ALARM_MON : 0) |
|
||||
(tue ? Alarm.ALARM_TUE : 0) |
|
||||
(wed ? Alarm.ALARM_WED : 0) |
|
||||
(thu ? Alarm.ALARM_THU : 0) |
|
||||
(fri ? Alarm.ALARM_FRI : 0) |
|
||||
(sat ? Alarm.ALARM_SAT : 0) |
|
||||
(sun ? Alarm.ALARM_SUN : 0);
|
||||
return repetitionMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just for backward compatibility, do not call in new code.
|
||||
* @param gbDevice
|
||||
* @return
|
||||
* @deprecated use {@link DBHelper#getAlarms(GBDevice)} instead
|
||||
*/
|
||||
@NonNull
|
||||
public static List<Alarm> readAlarmsFromPrefs(GBDevice gbDevice) {
|
||||
Prefs prefs = GBApplication.getPrefs();
|
||||
Set<String> stringAlarms = prefs.getStringSet(MiBandConst.PREF_MIBAND_ALARMS, new HashSet<String>());
|
||||
List<Alarm> alarms = new ArrayList<>(stringAlarms.size());
|
||||
|
||||
try {
|
||||
DBHandler db = GBApplication.acquireDB();
|
||||
DaoSession daoSession = db.getDaoSession();
|
||||
User user = DBHelper.getUser(daoSession);
|
||||
Device device = DBHelper.getDevice(gbDevice, daoSession);
|
||||
for (String stringAlarm : stringAlarms) {
|
||||
alarms.add(createAlarmFromPreference(stringAlarm, device, user));
|
||||
}
|
||||
Collections.sort(alarms, AlarmUtils.createComparator());
|
||||
return alarms;
|
||||
} catch (Exception e) {
|
||||
GB.log("Error accessing database", GB.ERROR, e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private static Alarm createAlarmFromPreference(String fromPreferences, Device device, User user) {
|
||||
String[] tokens = fromPreferences.split(",");
|
||||
int index = Integer.parseInt(tokens[0]);
|
||||
boolean enabled = Boolean.parseBoolean(tokens[1]);
|
||||
boolean smartWakeup = Boolean.parseBoolean(tokens[2]);
|
||||
int repetition = Integer.parseInt(tokens[3]);
|
||||
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);
|
||||
}
|
||||
|
||||
private static Comparator<Alarm> createComparator() {
|
||||
return new Comparator<Alarm>() {
|
||||
|
||||
@Override
|
||||
public int compare(Alarm o1, Alarm o2) {
|
||||
int p1 = o1.getPosition();
|
||||
int p2 = o2.getPosition();
|
||||
|
||||
return Integer.compare(p1, p2);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
|
||||
public class DateTimeUtils {
|
||||
private static SimpleDateFormat DAY_STORAGE_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
|
||||
@ -136,6 +137,11 @@ public class DateTimeUtils {
|
||||
return HOURS_MINUTES_FORMAT.format(date);
|
||||
}
|
||||
|
||||
public static String formatTime(int hours, int minutes) {
|
||||
return String.format(Locale.US, "%02d", hours) + ":" + String.format(Locale.US, "%02d", minutes);
|
||||
}
|
||||
|
||||
|
||||
public static Date todayUTC() {
|
||||
Calendar cal = getCalendarUTC();
|
||||
return cal.getTime();
|
||||
|
Loading…
Reference in New Issue
Block a user