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.Nullable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
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 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;
/**
* 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;
@SuppressWarnings("SameParameterValue")
@@ -84,13 +99,19 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
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();
if (calendarId != null) {
deleteAllEvents(calendarId);
addEvents(calendarId, events);
}
// inform user about completed update
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> {
Toast toast = Toast.makeText(getContext(), R.string.calendar_sync_finished, Toast.LENGTH_SHORT);
@@ -116,6 +137,65 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
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
private Uri buildUri(@NotNull Uri uri) {
return uri.buildUpon()
@@ -155,7 +235,6 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
cv.put(CalendarContract.Calendars.NAME, CALENDAR_NAME);
String displayName = getContext().getString(R.string.calendar_display_name);
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.OWNER_ACCOUNT, ACCOUNT_NAME);
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
* are repeated every year.
* Adds up to 100 events from the event list.
* 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) {
Log.d(TAG, "Create calendar events");
@@ -214,7 +293,7 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
* Adds a single event to the calendar.
*/
@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
+ ", title=" + title + ", description=" + description);
ContentValues cv = new ContentValues();
@@ -224,18 +303,8 @@ public class CalendarSyncAdapter extends AbstractThreadedSyncAdapter {
TimeZone utc = TimeZone.getTimeZone("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.set(year, month - 1, day);
cv.put(CalendarContract.Events.DTSTART, beginTime.getTimeInMillis());
cv.put(CalendarContract.Events.DURATION, "PT1D");
cv.put(CalendarContract.Events.ALL_DAY, 1);