Fossil/Skagen Hybrids: Add sending calendar items

This commit is contained in:
Arjan Schrijver
2025-06-26 10:00:10 +02:00
parent 73fc8971c8
commit 61e31229d2
3 changed files with 90 additions and 1 deletions
@@ -227,6 +227,11 @@ public class QHybridCoordinator extends AbstractBLEDeviceCoordinator {
return true;
}
@Override
public boolean supportsCalendarEvents() {
return isHybridHR();
}
@Override
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
return new BatteryConfig[]{
@@ -260,6 +265,7 @@ public class QHybridCoordinator extends AbstractBLEDeviceCoordinator {
// Settings applicable to all firmware versions
generic.add(R.xml.devicesettings_fossilhybridhr_calibration);
generic.add(R.xml.devicesettings_fossilhybridhr_navigation);
generic.add(R.xml.devicesettings_sync_calendar);
final List<Integer> health = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.HEALTH);
health.add(R.xml.devicesettings_fossilhybridhr_workout_detection);
health.add(R.xml.devicesettings_inactivity);
@@ -55,6 +55,7 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.NotificationListener;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
@@ -850,4 +851,14 @@ public class QHybridSupport extends QHybridBaseSupport {
public void onSetNavigationInfo(NavigationInfoSpec navigationInfoSpec) {
((FossilHRWatchAdapter) watchAdapter).onSetNavigationInfo(navigationInfoSpec);
}
@Override
public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) {
((FossilHRWatchAdapter) watchAdapter).onSendCalendar();
}
@Override
public void onDeleteCalendarEvent(byte type, long id) {
((FossilHRWatchAdapter) watchAdapter).onSendCalendar();
}
}
@@ -78,7 +78,10 @@ import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -105,9 +108,9 @@ import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HybridHRActivitySamp
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HybridHRSpo2SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationHRConfiguration;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.entities.User;
import nodomain.freeyourgadget.gadgetbridge.entities.HybridHRActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.HybridHRSpo2Sample;
import nodomain.freeyourgadget.gadgetbridge.entities.User;
import nodomain.freeyourgadget.gadgetbridge.externalevents.NotificationListener;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
@@ -181,9 +184,12 @@ import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
import nodomain.freeyourgadget.gadgetbridge.util.Version;
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
public class FossilHRWatchAdapter extends FossilWatchAdapter {
public static final int MESSAGE_WHAT_VOICE_DATA_RECEIVED = 0;
private static final int MAX_CALENDAR_ITEMS = 10;
private byte[] phoneRandomNumber;
private byte[] watchRandomNumber;
@@ -215,6 +221,8 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
private Version cleanFirmwareVersion = null;
private final Set<CalendarEvent> lastSync = new HashSet<>();
ServiceConnection voiceServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -493,6 +501,8 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
updateBuiltinAppsInCache();
onSendCalendar();
queueWrite(new SetDeviceStateRequest(GBDevice.State.INITIALIZED));
}
@@ -1608,6 +1618,68 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
}
}
public void onSendCalendar() {
if (!getDeviceSpecificPreferences().getBoolean("sync_calendar", false)) {
LOG.debug("Ignoring calendar sync request, sync is disabled");
return;
}
final CalendarManager upcomingEvents = new CalendarManager(getContext(), getDeviceSupport().getDevice().getAddress());
final List<CalendarEvent> calendarEvents = upcomingEvents.getCalendarEventList();
final Set<CalendarEvent> thisSync = new HashSet<>();
int nEvents = 0;
for (final CalendarEvent calendarEvent : calendarEvents) {
if (++nEvents > MAX_CALENDAR_ITEMS) {
LOG.warn("Syncing only first {} events of {}", MAX_CALENDAR_ITEMS, calendarEvents.size());
break;
}
thisSync.add(calendarEvent);
}
if (thisSync.equals(lastSync)) {
LOG.debug("Already synced this set of events, won't send to device");
return;
}
lastSync.clear();
lastSync.addAll(thisSync);
List<CalendarEvent> sortedEventList = new ArrayList<>(thisSync);
Collections.sort(sortedEventList, Comparator.comparingLong(CalendarEvent::getBegin));
LOG.debug("Syncing {} calendar events", sortedEventList.size());
try {
JSONArray items = new JSONArray();
for(CalendarEvent event : sortedEventList) {
JSONArray reminders = new JSONArray();
for (long reminder : event.getRemindersAbsoluteTs()) {
reminders.put(reminder / 1000);
}
items.put(new JSONObject()
.put("id", event.getId())
.put("title", event.getTitle())
.put("desc", event.getDescription())
.put("start", event.getBeginSeconds())
.put("end", event.getEndSeconds())
.put("reminders", reminders)
);
}
JSONObject calendarObj = new JSONObject()
.put("res", new JSONObject()
.put("set", new JSONObject()
.put("calendarApp._.config.events", items)
)
);
queueWrite(new JsonPutRequest(calendarObj, this));
} catch (JSONException e) {
LOG.error("Error sending calendar events: ", e);
}
}
@Override
public void factoryReset() {
queueWrite(new FactoryResetRequest());