Limit calendar import to 100 events

This commit is contained in:
Herbert Reiter
2023-11-11 20:15:07 +01:00
parent ce344ba55b
commit d3e678ef27
@@ -48,8 +48,10 @@ import net.moasdawiki.util.PathUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
@@ -71,8 +73,21 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
private static final Uri EVENT_URI = CalendarContract.Events. CONTENT_URI; private static final Uri EVENT_URI = CalendarContract.Events. CONTENT_URI;
private static final Uri REMINDER_URI = CalendarContract.Reminders.CONTENT_URI; private static final Uri REMINDER_URI = CalendarContract.Reminders.CONTENT_URI;
/**
* Alert event 4h before it starts, i.e. at 8pm in the evening before the event day.
*/
private static final int REMINDER_BEFORE_EVENT_MINUTES = 4 * 60; private static final int REMINDER_BEFORE_EVENT_MINUTES = 4 * 60;
/**
* Import maximum 100 events. If there are more events found, take the 100 upcoming events
* sorted by date.
*
* Android has a global event limitation of 500 events. If more than 500 events are created,
* Android throws errors with message "Maximum limit of concurrent alarms 500 reached" and
* ignores some events.
*/
private static final int MAX_EVENT_COUNT = 100;
private final ContentResolver contentResolver; private final ContentResolver contentResolver;
@SuppressWarnings("SameParameterValue") @SuppressWarnings("SameParameterValue")
@@ -84,13 +99,19 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
@Override @Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.d(TAG, "Begin of onPerformSync()"); Log.d(TAG, "Begin of onPerformSync()");
List<TerminTransformer.Event> events = getWikiEvents(); // collect and filter events
List<TerminTransformer.Event> rawEvents = getWikiEvents();
fillEmptyDateFields(rawEvents);
List<TerminTransformer.Event> events = filterEvents(rawEvents);
// update Android calendar
String calendarId = createCalendar(); String calendarId = createCalendar();
if (calendarId != null) { if (calendarId != null) {
deleteAllEvents(calendarId); deleteAllEvents(calendarId);
addEvents(calendarId, events); addEvents(calendarId, events);
} }
// inform user about completed update
Handler handler = new Handler(Looper.getMainLooper()); Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> { handler.post(() -> {
Toast toast = Toast.makeText(getContext(), R.string.calendar_sync_finished, Toast.LENGTH_SHORT); Toast toast = Toast.makeText(getContext(), R.string.calendar_sync_finished, Toast.LENGTH_SHORT);
@@ -116,6 +137,65 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
return events; return events;
} }
/**
* Fills empty day, month, and year fields in all events.
*/
private void fillEmptyDateFields(@NotNull List<TerminTransformer.Event> events) {
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance(utc);
for (TerminTransformer.Event event : events) {
if (event.dateFields.day == null) {
event.dateFields.day = 1;
}
if (event.dateFields.month == null) {
event.dateFields.month = 1;
}
if (event.dateFields.year == null) {
event.dateFields.year = calendar.get(Calendar.YEAR);
}
}
}
/**
* Reduces the number of events if more than MAX_EVENT_COUNT, only keep events in the near future.
*/
@NotNull
private List<TerminTransformer.Event> filterEvents(@NotNull List<TerminTransformer.Event> rawEvents) {
if (rawEvents.size() <= MAX_EVENT_COUNT) {
return rawEvents;
}
// sort by month and day;
// ignore year because events repeat every year
List<TerminTransformer.Event> sortedEvents = new ArrayList<>(rawEvents);
sortedEvents.sort(Comparator.comparingInt((TerminTransformer.Event event) -> event.dateFields.month).thenComparingInt(event -> event.dateFields.day));
// keep next MAX_EVENT_COUNT events from today onwards
List<TerminTransformer.Event> result = new ArrayList<>(MAX_EVENT_COUNT);
// find first event in future
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance(utc);
int index = 0;
while (index < sortedEvents.size() - 1
&& (sortedEvents.get(index).dateFields.month < calendar.get(Calendar.MONTH) + 1
|| sortedEvents.get(index).dateFields.month == calendar.get(Calendar.MONTH) + 1
&& sortedEvents.get(index).dateFields.day < calendar.get(Calendar.DAY_OF_MONTH))) {
index++;
}
// copy events until end of year
while (result.size() < MAX_EVENT_COUNT && index < sortedEvents.size() - 1) {
result.add(sortedEvents.get(index));
index++;
}
// copy events in new year
index = 0;
while (result.size() < MAX_EVENT_COUNT && index < sortedEvents.size() - 1) {
result.add(sortedEvents.get(index));
index++;
}
return result;
}
@NotNull @NotNull
private Uri buildUri(@NotNull Uri uri) { private Uri buildUri(@NotNull Uri uri) {
return uri.buildUpon() return uri.buildUpon()
@@ -155,7 +235,6 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
cv.put(CalendarContract.Calendars.NAME, CALENDAR_NAME); cv.put(CalendarContract.Calendars.NAME, CALENDAR_NAME);
String displayName = getContext().getString(R.string.calendar_display_name); String displayName = getContext().getString(R.string.calendar_display_name);
cv.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, displayName); cv.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, displayName);
//cv.put(CalendarContract.Calendars.CALENDAR_COLOR, 0xEA8561);
cv.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_READ); cv.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_READ);
cv.put(CalendarContract.Calendars.OWNER_ACCOUNT, ACCOUNT_NAME); cv.put(CalendarContract.Calendars.OWNER_ACCOUNT, ACCOUNT_NAME);
cv.put(CalendarContract.Calendars.VISIBLE, 1); cv.put(CalendarContract.Calendars.VISIBLE, 1);
@@ -191,8 +270,8 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
} }
/** /**
* Adds all events from the event list. The first occurrence is in the current year, the events * Adds up to 100 events from the event list.
* are repeated every year. * The first occurrence is in the current year, the events are repeated every year.
*/ */
private void addEvents(@NotNull String calendarId, @NotNull List<TerminTransformer.Event> events) { private void addEvents(@NotNull String calendarId, @NotNull List<TerminTransformer.Event> events) {
Log.d(TAG, "Create calendar events"); Log.d(TAG, "Create calendar events");
@@ -214,7 +293,7 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
* Adds a single event to the calendar. * Adds a single event to the calendar.
*/ */
@Nullable @Nullable
private String addEvent(@NotNull String calendarId, @Nullable Integer day, @Nullable Integer month, @Nullable Integer year, @NotNull String title, @NotNull String description) { private String addEvent(@NotNull String calendarId, int day, int month, int year, @NotNull String title, @NotNull String description) {
Log.d(TAG, "Create calendar event: day=" + day + ", month=" + month + ", year=" + year Log.d(TAG, "Create calendar event: day=" + day + ", month=" + month + ", year=" + year
+ ", title=" + title + ", description=" + description); + ", title=" + title + ", description=" + description);
ContentValues cv = new ContentValues(); ContentValues cv = new ContentValues();
@@ -224,18 +303,8 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
TimeZone utc = TimeZone.getTimeZone("UTC"); TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar beginTime = Calendar.getInstance(utc); Calendar beginTime = Calendar.getInstance(utc);
if (day == null) {
day = 1;
}
if (month == null) {
month = 1;
}
if (year == null) {
year = beginTime.get(Calendar.YEAR);
}
beginTime.clear(); beginTime.clear();
beginTime.set(year, month - 1, day); beginTime.set(year, month - 1, day);
cv.put(CalendarContract.Events.DTSTART, beginTime.getTimeInMillis()); cv.put(CalendarContract.Events.DTSTART, beginTime.getTimeInMillis());
cv.put(CalendarContract.Events.DURATION, "PT1D"); cv.put(CalendarContract.Events.DURATION, "PT1D");
cv.put(CalendarContract.Events.ALL_DAY, 1); cv.put(CalendarContract.Events.ALL_DAY, 1);