From ccb58f0f3c6dc202c9bb1ff2013bbae7787d80fd Mon Sep 17 00:00:00 2001 From: Daniel Hauck Date: Sun, 16 Apr 2017 12:34:37 +0200 Subject: [PATCH] Basic calendar sync using additional receiver (#654) --- .../externalevents/CalendarReceiver.java | 143 ++++++++++++++++++ .../gadgetbridge/model/CalendarEvents.java | 15 ++ .../service/DeviceCommunicationService.java | 10 ++ 3 files changed, 168 insertions(+) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java new file mode 100644 index 00000000..b09435a0 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java @@ -0,0 +1,143 @@ +/* Copyright (C) 2016-2017 Andreas Shimokawa, 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 . */ +package nodomain.freeyourgadget.gadgetbridge.externalevents; + + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.BuildConfig; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents; + +public class CalendarReceiver extends BroadcastReceiver { + private static final Logger LOG = LoggerFactory.getLogger(CalendarReceiver.class); + private static Hashtable eventState = new Hashtable<>(); + + private class EventSyncState { + private EventState state; + private CalendarEvents.CalendarEvent event; + + public EventSyncState(CalendarEvents.CalendarEvent event, EventState state) { + this.state = state; + this.event = event; + } + + public EventState getState() { + return state; + } + + public void setState(EventState state) { + this.state = state; + } + + public CalendarEvents.CalendarEvent getEvent() { + return event; + } + + public void setEvent(CalendarEvents.CalendarEvent event) { + this.event = event; + } + } + + private enum EventState { + NOT_SYNCED, SYNCED, NEEDS_UPDATE, NEEDS_DELETE + } + + public CalendarReceiver() { + LOG.info("Created calendar receiver."); + Context context = GBApplication.getContext(); + Intent intent = new Intent("CALENDAR_SYNC"); + intent.setPackage(BuildConfig.APPLICATION_ID); + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent("CALENDAR_SYNC"), 0); + AlarmManager am = (AlarmManager) (context.getSystemService(Context.ALARM_SERVICE)); + + am.setInexactRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + 10000, AlarmManager.INTERVAL_HALF_HOUR, pendingIntent); + } + + @Override + public void onReceive(Context context, Intent intent) { + LOG.info("Syncing with calendar."); + List eventList = (new CalendarEvents()).getCalendarEventList(GBApplication.getContext()); + Hashtable eventTable = new Hashtable<>(); + + for (CalendarEvents.CalendarEvent e: eventList) { + eventTable.put(e.getId(), e); + if (!eventState.containsKey(e.getId())) { + eventState.put(e.getId(), new EventSyncState(e, EventState.NOT_SYNCED)); + } + } + + Enumeration ids = eventState.keys(); + while (ids.hasMoreElements()) { + Long i = ids.nextElement(); + EventSyncState es = eventState.get(i); + if (eventTable.containsKey(i)) { + if (es.getState() == EventState.SYNCED) { + if (!es.getEvent().equals(eventTable.get(i))) { + eventState.put(i, new EventSyncState(eventTable.get(i), EventState.NEEDS_UPDATE)); + } + } + } else { + if (es.getState() == EventState.NOT_SYNCED) { + eventState.remove(i); + } else { + es.setState(EventState.NEEDS_DELETE); + eventState.put(i, es); + } + } + } + + updateEvents(); + } + + private void updateEvents() { + Enumeration ids = eventState.keys(); + while (ids.hasMoreElements()) { + Long i = ids.nextElement(); + EventSyncState es = eventState.get(i); + if ((es.getState() == EventState.NOT_SYNCED) || (es.getState() == EventState.NEEDS_UPDATE)) { + CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); + calendarEventSpec.title = es.getEvent().getTitle(); + calendarEventSpec.id = i; + calendarEventSpec.timestamp = es.getEvent().getBeginSeconds(); + calendarEventSpec.description = es.getEvent().getDescription(); + calendarEventSpec.type = CalendarEventSpec.TYPE_UNKNOWN; + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_UNKNOWN, i); + GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); + es.setState(EventState.SYNCED); + eventState.put(i, es); + } else if (es.getState() == EventState.NEEDS_DELETE) { + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_UNKNOWN, i); + eventState.remove(i); + } + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEvents.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEvents.java index 63935aa4..6918eae6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEvents.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEvents.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.List; +import java.util.Objects; public class CalendarEvents { @@ -155,5 +156,19 @@ public class CalendarEvents { return calName; } + @Override public boolean equals(Object other) { + if (other instanceof CalendarEvent) { + CalendarEvent e = (CalendarEvent) other; + return (this.getId() == e.getId()) && + Objects.equals(this.getTitle(), e.getTitle()) && + (this.getBegin() == e.getBegin()) && + Objects.equals(this.getLocation(), e.getLocation()) && + Objects.equals(this.getDescription(), e.getDescription()) && + (this.getEnd() == e.getEnd()) && + Objects.equals(this.getCalName(), e.getCalName()); + } else { + return false; + } + } } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index 7fb8a4d6..9a3f7d63 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -44,6 +44,7 @@ import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmClockReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver; +import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.MusicPlaybackReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.PebbleReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.PhoneCallReceiver; @@ -167,6 +168,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private AlarmClockReceiver mAlarmClockReceiver = null; private AlarmReceiver mAlarmReceiver = null; + private CalendarReceiver mCalendarReceiver = null; private Random mRandom = new Random(); private final String[] mMusicActions = { @@ -613,6 +615,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere mAlarmReceiver = new AlarmReceiver(); registerReceiver(mAlarmReceiver, new IntentFilter("DAILY_ALARM")); } + if (mCalendarReceiver == null) { + mCalendarReceiver = new CalendarReceiver(); + registerReceiver(mCalendarReceiver, new IntentFilter("CALENDAR_SYNC")); + } if (mAlarmClockReceiver == null) { mAlarmClockReceiver = new AlarmClockReceiver(); IntentFilter filter = new IntentFilter(); @@ -649,6 +655,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere unregisterReceiver(mAlarmReceiver); mAlarmReceiver = null; } + if (mCalendarReceiver != null) { + unregisterReceiver(mCalendarReceiver); + mCalendarReceiver = null; + } if (mAlarmClockReceiver != null) { unregisterReceiver(mAlarmClockReceiver); mAlarmClockReceiver = null;