/// <summary> /// Gets all events for a calendar within the specified time range. /// </summary> /// <param name="calendar">Calendar containing events</param> /// <param name="start">Start of event range</param> /// <param name="end">End of event range</param> /// <returns>Calendar events</returns> /// <exception cref="System.ArgumentException">Calendar does not exist on device</exception> /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception> /// <exception cref="Plugin.Calendars.Abstractions.PlatformException">Unexpected platform-specific error</exception> public async Task <IList <CalendarEvent> > GetEventsAsync(Calendar calendar, DateTime start, DateTime end) { var deviceCalendar = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false); if (deviceCalendar == null) { throw new ArgumentException("Specified calendar not found on device"); } var eventsUriBuilder = CalendarContract.Instances.ContentUri.BuildUpon(); // Note that this is slightly different from the GetEventById projection // due to the Instances API vs. Event API (specifically, IDs and start/end times) // string[] eventsProjection = { CalendarContract.Events.InterfaceConsts.Title, CalendarContract.Events.InterfaceConsts.Description, CalendarContract.Instances.Begin, CalendarContract.Instances.End, CalendarContract.Events.InterfaceConsts.AllDay, CalendarContract.Events.InterfaceConsts.EventLocation, CalendarContract.Instances.EventId }; ContentUris.AppendId(eventsUriBuilder, DateConversions.GetDateAsAndroidMS(start)); ContentUris.AppendId(eventsUriBuilder, DateConversions.GetDateAsAndroidMS(end)); var eventsUri = eventsUriBuilder.Build(); return(await Task.Run(() => { var cursor = Query(eventsUri, eventsProjection, string.Format("{0} = {1}", CalendarContract.Events.InterfaceConsts.CalendarId, calendar.ExternalID), null, CalendarContract.Events.InterfaceConsts.Dtstart + " ASC"); var events = IterateCursor(cursor, () => { bool allDay = cursor.GetBoolean(CalendarContract.Events.InterfaceConsts.AllDay); var calendarEvent = new CalendarEvent { Name = cursor.GetString(CalendarContract.Events.InterfaceConsts.Title), ExternalID = cursor.GetString(CalendarContract.Instances.EventId), Description = cursor.GetString(CalendarContract.Events.InterfaceConsts.Description), Start = cursor.GetDateTime(CalendarContract.Instances.Begin, allDay), End = cursor.GetDateTime(CalendarContract.Instances.End, allDay), Location = cursor.GetString(CalendarContract.Events.InterfaceConsts.EventLocation), AllDay = allDay }; calendarEvent.Reminders = GetEventReminders(calendarEvent.ExternalID); return calendarEvent; }); return events; }).ConfigureAwait(false)); }
/// <summary> /// Returns the value of the requested column as a DateTime /// </summary> /// <returns>The DateTime.</returns> /// <param name="cursor">Cursor.</param> /// <param name="column">Column name.</param> /// <param name="allDay">Whether the event is all-day</param> public static DateTime GetDateTime(this ICursor cursor, string column, bool allDay) { var ms = cursor.GetLong(cursor.GetColumnIndex(column)); var dt = DateConversions.GetDateFromAndroidMS(ms); // All day events should not be affected by time zones, so we simply take the // UTC time and treat it as local (e.g., Christmas doesn't start on the 24th in California...) // return(allDay ? DateTime.SpecifyKind(dt.ToUniversalTime(), DateTimeKind.Local) : dt.ToLocalTime()); }
/// <summary> /// Add new event to a calendar or update an existing event. /// </summary> /// <param name="calendar">Destination calendar</param> /// <param name="calendarEvent">Event to add or update</param> /// <exception cref="System.ArgumentException">Calendar is not specified, does not exist on device, or is read-only</exception> /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception> /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception> public async Task AddOrUpdateEventAsync(Calendar calendar, CalendarEvent calendarEvent) { if (string.IsNullOrEmpty(calendar.ExternalID)) { throw new ArgumentException("Missing calendar identifier", "calendar"); } else { // Verify calendar exists (Android actually allows using a nonexistent calendar ID...) // var deviceCalendar = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false); if (deviceCalendar == null) { throw new ArgumentException("Specified calendar not found on device"); } } // Validate times if (calendarEvent.End < calendarEvent.Start) { throw new ArgumentException("End time may not precede start time", "calendarEvent"); } bool updateExisting = false; long existingId = -1; await Task.Run(() => { if (long.TryParse(calendarEvent.ExternalID, out existingId)) { var calendarId = GetCalendarIdForEventId(calendarEvent.ExternalID); if (calendarId.HasValue && calendarId.Value.ToString() == calendar.ExternalID) { updateExisting = true; } } var eventValues = new ContentValues(); eventValues.Put(CalendarContract.Events.InterfaceConsts.CalendarId, calendar.ExternalID); eventValues.Put(CalendarContract.Events.InterfaceConsts.Title, calendarEvent.Name); eventValues.Put(CalendarContract.Events.InterfaceConsts.Description, calendarEvent.Description); eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtstart, DateConversions.GetDateAsAndroidMS(calendarEvent.Start)); eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtend, DateConversions.GetDateAsAndroidMS(calendarEvent.End)); eventValues.Put(CalendarContract.Events.InterfaceConsts.AllDay, calendarEvent.AllDay); eventValues.Put(CalendarContract.Events.InterfaceConsts.EventLocation, calendarEvent.Location ?? string.Empty); eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone, Java.Util.TimeZone.Default.ID); if (!updateExisting) { calendarEvent.ExternalID = Insert(_eventsUri, eventValues); } else { Update(_eventsUri, existingId, eventValues); } }); }
/// <summary> /// Gets all events for a calendar within the specified time range. /// </summary> /// <param name="calendar">Calendar containing events</param> /// <param name="start">Start of event range</param> /// <param name="end">End of event range</param> /// <returns>Calendar events</returns> /// <exception cref="System.ArgumentException">Calendar does not exist on device</exception> /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception> /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception> public async Task <IList <CalendarEvent> > GetEventsAsync(Calendar calendar, DateTime start, DateTime end) { var deviceCalendar = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false); if (deviceCalendar == null) { throw new ArgumentException("Specified calendar not found on device"); } var eventsUriBuilder = CalendarContract.Instances.ContentUri.BuildUpon(); // Note that this is slightly different from the GetEventById projection // due to the Instances API vs. Event API (specifically, IDs) // string[] eventsProjection = { // CalendarContract.Events.InterfaceConsts.Id, CalendarContract.Events.InterfaceConsts.Title, CalendarContract.Events.InterfaceConsts.Description, CalendarContract.Events.InterfaceConsts.Dtstart, CalendarContract.Events.InterfaceConsts.Dtend, CalendarContract.Events.InterfaceConsts.AllDay, CalendarContract.Events.InterfaceConsts.EventLocation, CalendarContract.Instances.EventId }; ContentUris.AppendId(eventsUriBuilder, DateConversions.GetDateAsAndroidMS(start)); ContentUris.AppendId(eventsUriBuilder, DateConversions.GetDateAsAndroidMS(end)); var eventsUri = eventsUriBuilder.Build(); var events = new List <CalendarEvent>(); await Task.Run(() => { var cursor = Query(eventsUri, eventsProjection, string.Format("{0} = {1}", CalendarContract.Events.InterfaceConsts.CalendarId, calendar.ExternalID), null, CalendarContract.Events.InterfaceConsts.Dtstart + " ASC"); try { if (cursor.MoveToFirst()) { do { events.Add(new CalendarEvent { Name = cursor.GetString(CalendarContract.Events.InterfaceConsts.Title), ExternalID = cursor.GetString(CalendarContract.Instances.EventId), Description = cursor.GetString(CalendarContract.Events.InterfaceConsts.Description), Start = cursor.GetDateTime(CalendarContract.Events.InterfaceConsts.Dtstart), End = cursor.GetDateTime(CalendarContract.Events.InterfaceConsts.Dtend), Location = cursor.GetString(CalendarContract.Events.InterfaceConsts.EventLocation), AllDay = cursor.GetBoolean(CalendarContract.Events.InterfaceConsts.AllDay) }); } while (cursor.MoveToNext()); } } catch (Java.Lang.Exception ex) { throw new PlatformException(ex.Message, ex); } finally { cursor.Close(); } }); return(events); }
/// <summary> /// Add new event to a calendar or update an existing event. /// If a new event was added, the ExternalID property will be set on the CalendarEvent object, /// to support future queries/updates. /// </summary> /// <param name="calendar">Destination calendar</param> /// <param name="calendarEvent">Event to add or update</param> /// <exception cref="System.ArgumentException">Calendar is not specified, does not exist on device, or is read-only</exception> /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception> /// <exception cref="System.InvalidOperationException">Editing recurring events is not supported</exception> /// <exception cref="Plugin.Calendars.Abstractions.PlatformException">Unexpected platform-specific error</exception> public async Task AddOrUpdateEventAsync(Calendar calendar, CalendarEvent calendarEvent) { if (string.IsNullOrEmpty(calendar.ExternalID)) { throw new ArgumentException("Missing calendar identifier", "calendar"); } else { // Verify calendar exists (Android actually allows using a nonexistent calendar ID...) // var deviceCalendar = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false); if (deviceCalendar == null) { throw new ArgumentException("Specified calendar not found on device"); } } // Validate times if (calendarEvent.End < calendarEvent.Start) { throw new ArgumentException("End time may not precede start time", "calendarEvent"); } bool updateExisting = false; long existingId = -1; CalendarEvent existingEvent = null; await Task.Run(() => { if (long.TryParse(calendarEvent.ExternalID, out existingId)) { if (IsEventRecurring(calendarEvent.ExternalID)) { throw new InvalidOperationException("Editing recurring events is not supported"); } var calendarId = GetCalendarIdForEventId(calendarEvent.ExternalID); if (calendarId.HasValue && calendarId.Value.ToString() == calendar.ExternalID) { updateExisting = true; existingEvent = GetEventById(calendarEvent.ExternalID); } } var eventValues = new ContentValues(); bool allDay = calendarEvent.AllDay; var start = allDay ? DateTime.SpecifyKind(calendarEvent.Start.Date, DateTimeKind.Utc) : calendarEvent.Start; var end = allDay ? DateTime.SpecifyKind(calendarEvent.End.Date, DateTimeKind.Utc) : calendarEvent.End; eventValues.Put(CalendarContract.Events.InterfaceConsts.CalendarId, calendar.ExternalID); eventValues.Put(CalendarContract.Events.InterfaceConsts.Title, calendarEvent.Name); eventValues.Put(CalendarContract.Events.InterfaceConsts.Description, calendarEvent.Description); eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtstart, DateConversions.GetDateAsAndroidMS(start)); eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtend, DateConversions.GetDateAsAndroidMS(end)); eventValues.Put(CalendarContract.Events.InterfaceConsts.AllDay, allDay); eventValues.Put(CalendarContract.Events.InterfaceConsts.EventLocation, calendarEvent.Location ?? string.Empty); // If we're updating an existing event, don't mess with the existing // time zone (since we don't support explicitly setting it yet). // *Unless* we're toggling the "all day" setting // (because that would mean the time zone is UTC rather than local...). // if (!updateExisting || allDay != existingEvent?.AllDay) { eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone, allDay ? Java.Util.TimeZone.GetTimeZone("UTC")?.ID ?? string.Empty : Java.Util.TimeZone.Default.ID); } if (!updateExisting) { calendarEvent.ExternalID = Insert(_eventsUri, eventValues); } else { Update(_eventsUri, existingId, eventValues); } }).ConfigureAwait(false); }
/// <summary> /// Returns the value of the requested column as a DateTime /// </summary> /// <returns>The DateTime.</returns> /// <param name="cursor">Cursor.</param> /// <param name="column">Column name.</param> public static DateTime GetDateTime(this ICursor cursor, string column) { var ms = cursor.GetLong(cursor.GetColumnIndex(column)); return(DateConversions.GetDateFromAndroidMS(ms)); }