Search code examples
javaandroidandroid-contentprovider

Using a Content Provider to get Calendar instances


I am trying to implement the a calendar instance query https://developer.android.com/guide/topics/providers/calendar-provider#query-instances but when I run the code my cursor returns null. I've removed the selection args so that it should return all instances within the query range but still no luck. I've even set the range to look back 2 years (of which there are plenty events in the calendar) yet it still returns null. Does anyone have the same problem when executing the below code?

package com.strath.keepfitct.utils;

import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CalendarContract;
import android.util.Log;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;

public class CalendarManager
{
    private static final int PERMISSION_REQUEST_CODE = 1;
    private static final String DEBUG_TAG = "CalendarManager";

    private static final String[] INSTANCE_PROJECTION = new String[]
            {
            CalendarContract.Instances.EVENT_ID,      // 0
            CalendarContract.Instances.BEGIN,         // 1
            CalendarContract.Instances.TITLE,          // 2
            CalendarContract.Instances.END,         // 3
    };

    private static final int PROJECTION_ID_INDEX = 0;
    private static final int PROJECTION_BEGIN_INDEX = 1;
    private static final int PROJECTION_TITLE_INDEX = 2;
    private static final int PROJECTION_END_INDEX = 3;


    public static void getEvents(Context context)
    {
        Cursor cursor = null;
        ContentResolver contentResolver = context.getContentResolver();

        long startTime = LocalDateTime.now().minusMonths(24).toEpochSecond(OffsetDateTime.now().getOffset());
        long endTime = LocalDateTime.now().plusHours(24).toEpochSecond(OffsetDateTime.now().getOffset());

        Uri.Builder builder = CalendarContract.Instances.CONTENT_URI.buildUpon();
        ContentUris.appendId(builder, startTime);
        ContentUris.appendId(builder, endTime);

//        String selection = CalendarContract.Instances.EVENT_ID + " = ?";
//        String[] selectionArgs = new String[] {"207"};

        if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALENDAR)
                != PackageManager.PERMISSION_GRANTED)
        {
            Log.d("permission", "permission denied to READ_CALENDAR - requesting it");

            ActivityCompat.requestPermissions((Activity) context, new String[] {Manifest.permission.READ_CALENDAR}, PERMISSION_REQUEST_CODE);
        }
        else
        {
            Log.d("Content URI", builder.build().toString());
            cursor =  contentResolver.query(builder.build(),
                    INSTANCE_PROJECTION,
                    null,
                    null,
                    null);

            while (cursor.moveToNext())
            {
                String title = null;
                long eventID = 0;
                long beginVal = 0;

                // Get the field values
                eventID = cursor.getLong(PROJECTION_ID_INDEX);
                beginVal = cursor.getLong(PROJECTION_BEGIN_INDEX);
                title = cursor.getString(PROJECTION_TITLE_INDEX);

                // Do something with the values.
                Log.i(DEBUG_TAG, "Event:  " + title);
                LocalDateTime date = LocalDateTime.ofInstant(Instant.ofEpochSecond(beginVal), TimeZone.getDefault().toZoneId());
                Log.i(DEBUG_TAG, "Date: " + date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
            }
        }
    }
}

Solution

  • My issue was that after converting the LocalDateTime parameters to a long epoch second, I wasn't converting them to miliseconds as is expected! A quick multiply by 1000 fixed the issue.

    long startTime = LocalDateTime.now().minusMonths(24).toEpochSecond(OffsetDateTime.now().getOffset()) * 1000;