RadCalendarView: Reading events from other calendars

RadCalendarView can be set up to read and display the events from other calendars on the device. The process is managed by the EventReadAdapter which is responsible for connecting to the calendar content provider and reading the requested events. There is no need for the developer to bother using any SQL queries since the default scenarios are provided out of the box. It is however possible for the queries to be fully customized as needed.

Setting the read adapter

The read adapter is rather easy to be set in the default scenario. All that has to be done is to set an instance of the adapter to the calendar and to trigger the reading of events like this:

    EventReadAdapter eventAdapter = new EventReadAdapter(calendarView);
    calendarView.setEventAdapter(eventAdapter);
    eventAdapter.readEventsAsync();
    EventReadAdapter eventAdapter = new EventReadAdapter (calendarView);
    calendarView.EventAdapter = eventAdapter;
    eventAdapter.ReadEventsAsync ();

Please note that since API 23, you need to ensure that your app has the proper permission before attempting to read events. In other words, before calling the readEventsAsync method, ensure that you have READ_CALENDAR permission as shown here.

This will get the events from the calendar with id 1, or the first calendar on the device. This will not be always the desired result, since the first calendar might not be the one that the developer needs.

Setting the query options

The events are being collected by the read adapter using queries. By changing the queries the developer can determine the set of events, that will be red and displayed in the calendar. There is a set of basic queries, that will cover most scenarios. Here is an example for getting the events from today to a week from today for the first three calendars on the device:

    EventQueryToken token = EventQueryToken.getCalendarsById(new String[]{"1", "2", "3"});
    Calendar calendar = Calendar.getInstance();
    long start = calendar.getTimeInMillis();
    calendar.add(Calendar.DATE, 7);
    long end = calendar.getTimeInMillis();
    token.setRange(start, end);

    eventAdapter.setEventsQueryToken(token);
    EventQueryToken token = EventQueryToken.GetCalendarsById(new String[]{"1", "2", "3"});
    Calendar calendar = Calendar.Instance;
    long start = calendar.TimeInMillis;
    calendar.Add(CalendarField.Date, 7);
    long end = calendar.TimeInMillis;
    token.SetRange(start, end);

    eventAdapter.EventsQueryToken = token;

Here is how to get all calendars belonging to a specific user using the provided helper methods:

    final RadCalendarView calendarView = new RadCalendarView(this);
    final EventReadAdapter eventAdapter = new EventReadAdapter(calendarView);
    calendarView.setEventAdapter(eventAdapter);

    EventReadAdapter.getCurrentUserAsync(this, new GenericResultCallback<String>() {
        @Override
        public void onResult(String result) {
            EventQueryToken token = EventQueryToken.getCalendarsByOwner(result);
            eventAdapter.setEventsQueryToken(token);
            eventAdapter.readEventsAsync();
        }
    });
    public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        RadCalendarView calendarView = new RadCalendarView(Activity);
        this.eventAdapter = new EventReadAdapter(calendarView);
        calendarView.EventAdapter = eventAdapter;

        EventReadAdapter.GetCurrentUserAsync (Activity, new CustomAsyncCallback (this.eventAdapter));

        return calendarView;
    }

    private class CustomAsyncCallback : Java.Lang.Object, IAsyncCallback
    {
        EventReadAdapter adapter;

        public CustomAsyncCallback(EventReadAdapter adapter)
        {
            this.adapter = adapter;
        }

        public void OnResult(Java.Lang.Object result)
        {
            EventQueryToken token = EventQueryToken.GetCalendarsByOwner (result.ToString());
            this.adapter.EventsQueryToken = token;
            this.adapter.ReadEventsAsync ();
        }
    }

Please note that since API 23, you need to ensure that your app has the proper permission before attempting to read events. In other words, before calling the getCurrentUserAsync method, ensure that you have GET_ACCOUNTS permission as shown here.

However since there is no standard on the order or the owners of calendars there are some scenarios where the developer must decide what to do with the available calendars manually. There are devices of which the first calendar (with id of 1) is the Outlook calendar and others where there is only one user, which doesn't own the calendar of the device, but the owner is rather something like "Phone".

In these cases there can be a more controlled selection of events as presented in this example:

    final RadCalendarView calendarView = new RadCalendarView(this);
    final EventReadAdapter eventAdapter = new EventReadAdapter(calendarView);
    calendarView.setEventAdapter(eventAdapter);

    EventReadAdapter.getAllCalendarsAsync(this, new GenericResultCallback<EventReadAdapter.CalendarInfo[]>() {
        @Override
        public void onResult(EventReadAdapter.CalendarInfo[] result) {
            List<String> calendarsFromResult = new ArrayList<String>();

            for (EventReadAdapter.CalendarInfo calendar : result) {
                if (true) { // add custom logic here
                    calendarsFromResult.add(calendar.id);
                }
            }

            String[] selectedCalendars = new String[calendarsFromResult.size()];
            for (int i = 0; i < calendarsFromResult.size(); i++) {
                selectedCalendars[i] = calendarsFromResult.get(i);
            }

            EventQueryToken token = EventQueryToken.getCalendarsById(selectedCalendars);
            eventAdapter.setEventsQueryToken(token);
            eventAdapter.readEventsAsync();
        }
    });
    EventReadAdapter eventAdapter;

    public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        RadCalendarView calendarView = new RadCalendarView(Activity);

        this.eventAdapter = new EventReadAdapter(calendarView);
        calendarView.EventAdapter = eventAdapter;

        EventReadAdapter.GetAllCalendarsAsync(Activity, new CustomAsyncCallback(this.eventAdapter));

        return calendarView;
    }

    private class CustomAsyncCallback : Java.Lang.Object, IAsyncCallback {
        EventReadAdapter adapter;

        public CustomAsyncCallback(EventReadAdapter adapter)
        {
            this.adapter = adapter;
        }

        public void OnResult(Java.Lang.Object result)
        {
            List<String> calendarsFromResult = new List<String>();
            EventReadAdapter.CalendarInfo[] calendars = result.ToArray<EventReadAdapter.CalendarInfo>();

            for (int i = 0; i < calendars.Length; i++) {
                if (true) // add custom logic here
                {
                    calendarsFromResult.Add(calendars[i].Id);
                }
            }

            String[] selectedCalendars = calendarsFromResult.ToArray();

            EventQueryToken token = EventQueryToken.GetCalendarsById(selectedCalendars);
            this.adapter.EventsQueryToken = token;
            this.adapter.ReadEventsAsync();
        }
    }

In any case the events are being red after the method for asynchronous reading is being invoked. This will automatically refresh the calendar once the events are loaded.

Please note that you must set everything before calling the method for reading the events asynchronously.

Recurring events

The recurring events are also available for reading and displaying in the RadCalendarView, however the rules are not complete and will be updated with the following releases of the calendar. The recurring events can be stopped or enabled using the setReadingRecurringEvents(boolean) method of the adapter. The functionality can be easily extended by providing manual implementation over the existing one like this:

    public class CustomEventReadAdapter extends EventReadAdapter {

        public CustomEventReadAdapter(RadCalendarView owner) {
            super(owner);
        }

        @Override
        protected boolean eventShouldRecur(RecurringEvent event, long dateStart) {
            // Add custom logic here...

            return super.eventShouldRecur(event, dateStart);
        }
    }
    public class CustomEventReadAdapter : EventReadAdapter
    {
        public CustomEventReadAdapter(RadCalendarView owner) : base (owner){}

        protected override bool EventShouldRecur (RecurringEvent recurringEvent, long date)
        {
            // Add custom logic here...

            return base.EventShouldRecur (recurringEvent, date);
        }
    }

The RecurringEvent class is simply a data holder of all the tokens stored in a RRULE according to the iCalendar specification. It is used for judging the recurrence of the events red from the other calendars. It holds all the fields needed to store the elements of the RRULE: