LoginSignup
18
17

More than 5 years have passed since last update.

CalendarProviderを使ってGoogleカレンダーにアクセスする

Last updated at Posted at 2016-10-09

AndroidアプリからCalendarProviderを使って、Googleカレンダーに登録されているイベントを読み取る方法を紹介します。

User Permissions

まず、カレンダーの読み込みに必要なパーミッションを設定します。

AndroidManifets.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.xxx">
    ...
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    ...
</manifest>
  • Android 6.0 (Marshmallow) 以降もサポートする際には、追加でRuntime Permissionへの対応が必要です。

カレンダーの一覧取得

カレンダーから取得可能な情報

個々のカレンダーから取得可能な情報は、下記を参照してください。
- CalendarContract.java
- APIリファレンス: CalendarContract.Calendars

以下に、個々のカレンダーから取得可能な情報のうち、主なものを列挙します。

Constant Type Description
_ID INTEGER (long) unique ID
NAME TEXT カレンダーの名前
ACCOUNT_NAME TEXT 同期の際に使用されるアカウント
ACCOUNT_TYPE TEXT 同期の際に使用されるアカウントの種別
CALENDAR_COLOR INTEGER (color value) カレンダーの色
(イベントのデフォルトの表示色)
CALENDAR_DISPLAY_NAME TEXT ユーザーに表示されるカレンダーの名前
CALENDAR_ACCESS_LEVEL INTEGER
(one of the values below)
カレンダーに対するアクセスレベル
CALENDAR_TIME_ZONE TEXT カレンダーのタイムゾーン
VISIBLE INTEGER (boolean) カレンダーが表示対象か否か
・ 値 0 の場合、このカレンダーのイベントを表示しない
・値 1 の場合、このカレンダーのイベントを表示する
SYNC_EVENTS INTEGER (boolean) カレンダーを同期し、イベントを端末に保存するか否か
・ 値 0 の場合、同期せず、イベントを端末に保存しない
・値 1 の場合、同期してイベントを端末に保存する
OWNER_ACCOUNT TEXT カレンダーの所有者のアカウント

なお、CALENDAR_ACCESS_LEVEL は以下のいずれかの値をとります。

Constant Value Description
CAL_ACCESS_NONE 0 カレンダーにアクセスできない
CAL_ACCESS_FREEBUSY 100 カレンダー内の空きの有無を確認可能
CAL_ACCESS_READ 200 全てのイベントの詳細が確認可能
CAL_ACCESS_RESPOND 300 イベントに対してyes/no/maybeで返信可能
CAL_ACCESS_OVERRIDE 400 ※使用されていない
CAL_ACCESS_CONTRIBUTOR 500 アクセス権以外の全ての編集が可能
CAL_ACCESS_EDITOR 600 アクセス権以外の全ての編集が可能
CAL_ACCESS_OWNER 700 カレンダーに対して全ての操作が可能
CAL_ACCESS_ROOT 800 ドメインの管理者

カレンダーの一覧取得

まず、"android.provider.CalendarContract.Calendars"を static import しておきます。
"CalendarContract.Calendars.xxx"のままでは長いため、"Calendars.xxx"でアクセスできるようにします。

import static android.provider.CalendarContract.Calendars;

次に、個々のカレンダーから取得したいプロパティを列挙します。

    // プロジェクション配列。
    // 取得したいプロパティの一覧を指定する。
    private static final String[] CALENDAR_PROJECTION = new String[] {
            Calendars._ID,
            Calendars.NAME,
            Calendars.ACCOUNT_NAME,
            Calendars.ACCOUNT_TYPE,
            Calendars.CALENDAR_COLOR,
            Calendars.CALENDAR_DISPLAY_NAME,
            Calendars.CALENDAR_ACCESS_LEVEL,
            Calendars.CALENDAR_TIME_ZONE,
            Calendars.VISIBLE,
            Calendars.SYNC_EVENTS,
            Calendars.OWNER_ACCOUNT,
    };

    // プロジェクション配列のインデックス。
    // パフォーマンス向上のために、動的に取得せずに、静的に定義しておく。
    private static final int CALENDAR_PROJECTION_IDX_ID = 0;
    private static final int CALENDAR_PROJECTION_IDX_NAME = 1;
    private static final int CALENDAR_PROJECTION_IDX_ACCOUNT_NAME = 2;
    private static final int CALENDAR_PROJECTION_IDX_ACCOUNT_TYPE = 3;
    private static final int CALENDAR_PROJECTION_IDX_CALENDAR_COLOR = 4;
    private static final int CALENDAR_PROJECTION_IDX_CALENDAR_DISPLAY_NAME = 5;
    private static final int CALENDAR_PROJECTION_IDX_CALENDAR_ACCESS_LEVEL = 6;
    private static final int CALENDAR_PROJECTION_IDX_CALENDAR_TIME_ZONE = 7;
    private static final int CALENDAR_PROJECTION_IDX_VISIBLE = 8;
    private static final int CALENDAR_PROJECTION_IDX_SYNC_EVENTS = 9;
    private static final int CALENDAR_PROJECTION_IDX_OWNER_ACCOUNT = 10;

最後に、クエリを発行してカーソルを取得し、カーソルから個々のカレンダーの情報を取得します。
以下はCSV形式で、logcatに出力します。

        // クエリ条件を設定する
        final Uri uri = CalendarContract.Calendars.CONTENT_URI;
        final String[] projection = CALENDAR_PROJECTION;
        final String selection = null;
        final String[] selectionArgs = null;
        final String sortOrder = null;

        // クエリを発行してカーソルを取得する
        final ContentResolver cr = getContentResolver();
        final Cursor cur = cr.query(uri, projection, selection, selectionArgs, sortOrder);

        // ログ出力 (Header)
        final StringBuilder sbHeader = new StringBuilder();
        for (final String property : CALENDAR_PROJECTION) {
            sbHeader.append(property).append(',');
        }
        Log.d(TAG, sbHeader.toString());

        while (cur.moveToNext()) {
            // カーソルから各プロパティを取得する
            final long id = cur.getLong(CALENDAR_PROJECTION_IDX_ID);
            final String name = cur.getString(CALENDAR_PROJECTION_IDX_NAME);
            final String accountName = cur.getString(CALENDAR_PROJECTION_IDX_ACCOUNT_NAME);
            final String accountType = cur.getString(CALENDAR_PROJECTION_IDX_ACCOUNT_TYPE);
            final int calendarColor = cur.getInt(CALENDAR_PROJECTION_IDX_CALENDAR_COLOR);
            final String calendarDisplayName = cur.getString(CALENDAR_PROJECTION_IDX_CALENDAR_DISPLAY_NAME);
            final int calendarAccessLevel = cur.getInt(CALENDAR_PROJECTION_IDX_CALENDAR_ACCESS_LEVEL);
            final String calendarTimeZone = cur.getString(CALENDAR_PROJECTION_IDX_CALENDAR_TIME_ZONE);
            final int visible = cur.getInt(CALENDAR_PROJECTION_IDX_VISIBLE);
            final int syncEvents = cur.getInt(CALENDAR_PROJECTION_IDX_SYNC_EVENTS);
            final String ownerAccount = cur.getString(CALENDAR_PROJECTION_IDX_OWNER_ACCOUNT);

            // ログ出力 (Body)
            final StringBuilder sbBody = new StringBuilder();
            sbBody.append(id).append(',');
            sbBody.append(name).append(',');
            sbBody.append(accountName).append(',');
            sbBody.append(accountType).append(',');
            sbBody.append(String.format("0x%08X", calendarColor)).append(',');
            sbBody.append(calendarDisplayName).append(',');
            sbBody.append(calendarAccessLevel).append(',');
            sbBody.append(calendarTimeZone).append(',');
            sbBody.append(visible).append(',');
            sbBody.append(syncEvents).append(',');
            sbBody.append(ownerAccount).append(',');
            Log.d(TAG, sbBody.toString());
        }

カレンダーの一覧の取得結果

_id,name,account_name,account_type,calendar_color,calendar_displayName,calendar_access_level,calendar_timezone,visible,sync_events,ownerAccount
1,aaa@gmail.com,aaa@gmail.com,com.google,0xFF9A9CFF,aaa@gmail.com,700,Asia/Tokyo,1,1,aaa@gmail.com
2,共有カレンダー,aaa@gmail.com,com.google,0xFFB99AFF,共有カレンダー,700,Asia/Tokyo,1,1,xxxyyyzzz@group.calendar.google.com
3,Contacts,aaa@gmail.com,com.google,0xFF92E1C0,Contacts,200,Asia/Tokyo,1,1,#contacts@group.v.calendar.google.com
4,日本の祝日,aaa@gmail.com,com.google,0xFF16A765,日本の祝日,200,Asia/Tokyo,1,1,ja.japanese#holiday@group.v.calendar.google.com
5,bbb@gmail.com,bbb@gmail.com,com.google,0xFF9FE1E7,bbb@gmail.com,700,Asia/Tokyo,1,1,bbb@gmail.com
6,Contacts,bbb@gmail.com,com.google,0xFF9A9CFF,Contacts,200,Asia/Tokyo,1,1,#contacts@group.v.calendar.google.com
7,日本の祝日,bbb@gmail.com,com.google,0xFF9A9CFF,日本の祝日,200,Asia/Tokyo,1,1,ja.japanese#holiday@group.v.calendar.google.com
8,docomo,docomo,com.android.nttdocomo,0xFF182C57,com.android.nttdocomo,700,Asia/Tokyo,0,1,docomo

イベントの一覧取得

特定のカレンダーに登録されているイベントの一覧を取得します。

個々のイベントから取得可能な情報は、下記を参照してください。
- CalendarContract.java
- APIリファレンス: CalendarContract.Events

以下に、個々のイベントから取得可能な情報のうち、主なものを列挙します。

Constant Type Description
CALENDAR_ID NTEGER (long) イベントが属するカレンダーの _ID
TITLE TEXT イベントのタイトル
DESCRIPTION TEXT イベントの説明
EVENT_LOCATION TEXT イベントの開催場所
EVENT_COLOR INTEGER (color value) イベントの表示色
DISPLAY_COLOR INTEGER (color value) イベントの実際の表示色
EVENT_COLORが未設定の場合には、CALENDAR_COLORが使用される
DTSTART INTEGER (long; millis since epoch) イベントの開始日時
UTCでの1970/01/01 00:00:00からのミリ秒単位での経過時刻で表現される
DTEND INTEGER (long; millis since epoch) イベントの終了日時
UTCでの1970/01/01 00:00:00からのミリ秒単位での経過時刻で表現される
DURATION TEXT (duration in RFC5545 format) イベントの期間
RFC5545(旧版RFC2445)の形式で表現される
例)"PT1H"⇒1時間、 "P2W"⇒2週間
EVENT_TIMEZONE TEXT イベントのタイムゾーン
EVENT_END_TIMEZONE TEXT イベントの終了日時のタイムゾーン
ALL_DAY INTEGER (boolean) 終日のイベントか否か
RRULE TEXT イベントの繰り返しルール
RFC5545(旧版RFC2445)の形式で表現される
例)"FREQ=WEEKLY;COUNT=10;WKST=SU"
RDATE TEXT イベントの繰り返し発生日
RRULE と組み合わせて、繰り返しのイベント全体を定義するのに使用される
GUESTS_CAN_MODIFY INTEGER (boolean) ゲストがイベントを変更できるか否か
GUESTS_CAN_INVITE_OTHERS INTEGER (boolean) ゲストが他のゲストを招待できるか否か
GUESTS_CAN_SEE_GUESTS INTEGER (boolean) ゲストが他のゲストのリストを参照できるか否か
ORGANIZER STRING イベントの主催者(所有者)のメールアドレス

カレンダー内のイベントの一覧取得

まず、"android.provider.CalendarContract.Events"を static import しておきます。
"CalendarContract.Events.xxx"のままでは長いため、"Events.xxx"でアクセスできるようにします。

import static android.provider.CalendarContract.Events;

次に、個々のイベントから取得したいプロパティを列挙します。

    // プロジェクション配列。
    // 取得したいプロパティの一覧を指定する。
    public static final String[] EVENT_PROJECTION = new String[] {
            Events.CALENDAR_ID,
            Events.TITLE,
            Events.DESCRIPTION,
            Events.EVENT_LOCATION,
            Events.EVENT_COLOR,
            Events.DISPLAY_COLOR,
            Events.DTSTART,
            Events.DTEND,
            Events.DURATION,
            Events.EVENT_TIMEZONE,
            Events.EVENT_END_TIMEZONE,
            Events.ALL_DAY,
            Events.RRULE,
            Events.RDATE,
            Events.GUESTS_CAN_MODIFY,
            Events.GUESTS_CAN_INVITE_OTHERS,
            Events.GUESTS_CAN_SEE_GUESTS,
            Events.ORGANIZER,
    };

    // プロジェクション配列のインデックス。
    // パフォーマンス向上のために、動的に取得せずに、静的に定義しておく。
    private static final int EVENT_PROJECTION_IDX_ID = 0;
    private static final int EVENT_PROJECTION_IDX_CALENDAR_ID = 1;
    private static final int EVENT_PROJECTION_IDX_TITLE = 2;
    private static final int EVENT_PROJECTION_IDX_DESCRIPTION = 3;
    private static final int EVENT_PROJECTION_IDX_EVENT_LOCATION = 4;
    private static final int EVENT_PROJECTION_IDX_EVENT_COLOR = 5;
    private static final int EVENT_PROJECTION_IDX_DISPLAY_COLOR = 6;
    private static final int EVENT_PROJECTION_IDX_DTSTART = 7;
    private static final int EVENT_PROJECTION_IDX_DTEND = 8;
    private static final int EVENT_PROJECTION_IDX_DURATION = 9;
    private static final int EVENT_PROJECTION_IDX_EVENT_TIMEZONE = 10;
    private static final int EVENT_PROJECTION_IDX_EVENT_END_TIMEZONE = 11;
    private static final int EVENT_PROJECTION_IDX_ALL_DAY = 12;
    private static final int EVENT_PROJECTION_IDX_RRULE = 13;
    private static final int EVENT_PROJECTION_IDX_RDATE = 14;
    private static final int EVENT_PROJECTION_IDX_GUESTS_CAN_MODIFY = 15;
    private static final int EVENT_PROJECTION_IDX_GUESTS_CAN_INVITE_OTHERS = 16;
    private static final int EVENT_PROJECTION_IDX_GUESTS_CAN_SEE_GUESTS = 17;
    private static final int EVENT_PROJECTION_IDX_ORGANIZER = 18;

ここで、UNIX time (1970/01/01 00:00:00からの経過時刻[msec])を文字列化するためのメソッドを用意しておきます。

    private static String getDateTimeText(
            final Context context,
            final String timeZone,
            final long dateTimeInMillis
    ) {
        final Calendar calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(dateTimeInMillis);
        return DateUtils.formatDateRange(context, new java.util.Formatter(), calendar.getTimeInMillis(), calendar.getTimeInMillis(),
                DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR, timeZone).toString();
    }

最後に、検索対象のカレンダーの _ID を指定し、クエリを発行してカーソルを取得し、カーソルから個々のイベントの情報を取得します。
以下はCSV形式で、logcatに出力します。

        // 検索対象のカレンダーの _ID
        final long targetCalendarId = 1;

        // クエリ条件を設定する
        final Uri uri = CalendarContract.Events.CONTENT_URI;
        final String[] projection = CALENDAR_PROJECTION;
        final String selection = "(" + CalendarContract.Events.CALENDAR_ID + " = ?)";
        final String[] selectionArgs = new String[] {String.valueOf(targetCalendarId)};
        final String sortOrder = null;

        // クエリを発行してカーソルを取得する
        final ContentResolver cr = getContentResolver();        
        final Cursor cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);

        // ログ出力 (Header)
        final StringBuilder sbEvents = new StringBuilder();
        for (final String property : EVENT_PROJECTION) {
            sbEvents.append(property).append(',');
        }
        Log.d(TAG, sbEvents.toString());

        while (cur.moveToNext()) {
            // カーソルから各プロパティを取得する
            final long id = cur.getLong(EVENT_PROJECTION_IDX_ID);
            final long calendarId = cur.getLong(EVENT_PROJECTION_IDX_CALENDAR_ID);
            final String title = cur.getString(EVENT_PROJECTION_IDX_TITLE);
            final String description = cur.getString(EVENT_PROJECTION_IDX_DESCRIPTION);
            final String eventLocation = cur.getString(EVENT_PROJECTION_IDX_EVENT_LOCATION);
            final int eventColdr = cur.getInt(EVENT_PROJECTION_IDX_EVENT_COLOR);
            final int displayColor = cur.getInt(EVENT_PROJECTION_IDX_DISPLAY_COLOR);
            final long dtStart = cur.getLong(EVENT_PROJECTION_IDX_DTSTART);
            final long dtEnd = cur.getLong(EVENT_PROJECTION_IDX_DTEND);
            final String duration = cur.getString(EVENT_PROJECTION_IDX_DURATION);
            final String eventTimeZone = cur.getString(EVENT_PROJECTION_IDX_EVENT_TIMEZONE);
            final String eventEndTimeZone = cur.getString(EVENT_PROJECTION_IDX_EVENT_END_TIMEZONE);
            final int allDay = cur.getInt(EVENT_PROJECTION_IDX_ALL_DAY);
            final String rRule = cur.getString(EVENT_PROJECTION_IDX_RRULE);
            final String rDate = cur.getString(EVENT_PROJECTION_IDX_RDATE);
            final int guestsCanModify = cur.getInt(EVENT_PROJECTION_IDX_GUESTS_CAN_MODIFY);
            final int guestsCanInviteOthers = cur.getInt(EVENT_PROJECTION_IDX_GUESTS_CAN_INVITE_OTHERS);
            final int guestCanSeeGuests = cur.getInt(EVENT_PROJECTION_IDX_GUESTS_CAN_SEE_GUESTS);
            final String organizer = cur.getString(EVENT_PROJECTION_IDX_ORGANIZER);

            // ログ出力 (Body)
            final StringBuilder sbBody = new StringBuilder();
            sbBody.append(id).append(',');
            sbBody.append(name).append(',');
            sbBody.append(accountName).append(',');
            sbBody.append(accountType).append(',');
            sbBody.append(String.format("0x%08X", calendarColor)).append(',');
            sbBody.append(calendarDisplayName).append(',');
            sbBody.append(calendarAccessLevel).append(',');
            sbBody.append(calendarTimeZone).append(',');
            sbBody.append(visible).append(',');
            sbBody.append(syncEvents).append(',');
            sbBody.append(ownerAccount).append(',');
            Log.d(TAG, sbBody.toString());
        }

イベントの一覧の取得結果

_id,calendar_id,title,description,eventLocation,eventColor,displayColor,dtstart,dtend,duration,eventTimezone,eventEndTimezone,allDay,rrule,rdate,guestsCanModify,guestsCanInviteOthers,guestsCanSeeGuests,organizer,
1,1,Google Developers Summit : Android,,コクヨホール,0x00000000,0xFF9A9CFF,2016年4月25日 13:00,2016年4月25日 17:30,null,Asia/Tokyo,null,0,null,null,0,1,1,aaa@gmail.com,
2,1,日本Androidの会 2016年9月定例会,「クロスプラットフォーム開発最前線」,日本マイクロソフト株式会社,0xFF46D6DB,0xFF46D6DB,2016年9月7日 19:00,2016年9月7日 21:40,null,Asia/Tokyo,null,0,null,null,0,1,1,aaa@gmail.com,
3,1,shibuya.apk #10,,株式会社サイバーエージェント,0xFF46D6DB,0xFF46D6DB,2016年9月16日 19:00,2016年9月16日 21:00,null,Asia/Tokyo,null,0,null,null,0,1,1,aaa@gmail.com,
4,1,daily meeting,,,0x00000000,0xFF9A9CFF,2016年10月11日 10:00,1970年1月1日 9:00,P3600S,Asia/Tokyo,null,0,FREQ=WEEKLY;WKST=SU;BYDAY=MO,TU,WE,TH,FR,null,0,1,1,aaa@gmail.com,

参考情報

18
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
17