캘린더 제공자 개요

캘린더 제공자는 사용자의 캘린더 일정에 대한 저장소입니다. 이 Calendar Provider API를 사용하면 쿼리, 삽입, 업데이트, 삭제를 수행할 수 있습니다. 캘린더, 일정, 참석자, 알림 등에 대한 작업을 수행할 수 있습니다.

Calendar Provider API는 애플리케이션 및 동기화 어댑터에서 사용할 수 있습니다. 어떤 유형의 프로그램이 호출을 하는 주체인지에 따라 규칙이 각기 다릅니다. 이 문서 주로 Calendar Provider API를 애플리케이션으로 사용하는 데 중점을 둡니다. 동기화 어댑터가 서로 어떻게 다른지 논의한 내용은 동기화 어댑터를 참고하세요.

일반적으로 캘린더 데이터를 읽거나 쓰려면 애플리케이션의 매니페스트가 적절한 권한을 포함해야 합니다. 자세한 내용은 사용자 권한을 참고하세요. 일반적인 작업을 더 쉽게 수행할 수 있도록 Calendar 제공업체는 Calendar에 설명된 대로 인텐트 집합을 제공합니다. 인텐트를 참조하세요. 이러한 인텐트는 사용자를 캘린더 애플리케이션으로 이동시켜 일정을 수정할 수 있습니다 사용자는 캘린더 애플리케이션과 상호작용한 다음 원래 애플리케이션으로 돌아옵니다. 따라서 애플리케이션이 권한을 요청할 필요가 없으며 이벤트를 보거나 만들기 위한 사용자 인터페이스를 제공할 필요도 없습니다.

기본사항

콘텐츠 제공자는 데이터를 저장하여 애플리케이션에서 이 데이터에 액세스할 수 있도록 합니다. Android 플랫폼에서 제공하는 콘텐츠 제공자 (캘린더 제공자 포함)는 일반적으로 관계형 데이터베이스 모델로서 각 행은 레코드이고 각 열은 알 수 있습니다. 애플리케이션과 동기화 어댑터는 Calendar Provider API를 통해 사용자의 캘린더 데이터를 보관하고 있는 데이터베이스 테이블에 대한 읽기/쓰기 액세스 권한을 얻을 수 있습니다.

모든 콘텐츠 제공자는 Uri 데이터 세트를 고유하게 식별합니다. 여러 데이터 세트(여러 테이블)를 제어하는 콘텐츠 제공자는 각 데이터 세트에 별도의 URI를 노출합니다. 전체 제공자의 URI는 문자열 'content://'로 시작합니다. 이 가 콘텐츠 제공자에 의해 제어되고 있음을 식별합니다. 캘린더 제공자가 각각의 클래스(테이블)에 대한 URI의 상수를 정의합니다. 이러한 URI의 형식은 <class>.CONTENT_URI입니다. 예: Events.CONTENT_URI.

그림 1은 캘린더 제공자 데이터 모델을 그림으로 나타낸 것입니다. 이 그림에는 메인 테이블과 이들을 서로 연결하는 필드가 표시되어 있습니다.

캘린더 제공자 데이터 모델

그림 1. 캘린더 제공자 데이터 모델.

한 사용자가 여러 개의 캘린더를 가질 수 있으며, 다양한 캘린더는 각기 다른 유형의 계정(Google 캘린더, Exchange 등)과 연결될 수 있습니다.

CalendarContract는 캘린더의 데이터 모델과 이벤트 관련 정보를 정의합니다. 이 데이터는 아래에 나열한 것과 같은 여러 테이블에 저장됩니다.

테이블(클래스) 설명

CalendarContract.Calendars

이 테이블에는 캘린더별 정보가 담겨 있습니다. 이 테이블의 행마다 한 캘린더의 세부 정보(예: 이름, 색상, 동기화 정보 등)가 포함됩니다.
CalendarContract.Events 이 테이블에는 이벤트별 정보가 담겨 있습니다. 이 테이블의 각 행에는 단일 일정(예: 일정 제목, 위치, 시작 시간, 종료) 할 수 있습니다. 이벤트는 일회성일 수도 있고 여러 번 반복될 수도 있습니다. 참석자, 알림, 확장된 속성 등은 별도의 테이블에 저장됩니다. 이들 테이블에는 각기 이벤트 테이블의 _ID를 참조하는 EVENT_ID가 있습니다.
CalendarContract.Instances 이 테이블에는 각 이벤트 발생의 시작 시간과 종료 시간을 설정합니다. 이 테이블의 각 행은 하나의 이벤트 발생을 나타냅니다. 일회성 이벤트의 경우 1:1 매핑이 있습니다. 이벤트에 추가할 수 있습니다 반복되는 이벤트의 경우, 해당 이벤트가 여러 번 발생하는 것에 맞추어 자동으로 여러 행이 생성됩니다.
CalendarContract.Attendees 이 테이블에는 이벤트 참석자(게스트) 정보가 담겨 있습니다. 각 행은 주어진 이벤트의 게스트 한 사람을 나타냅니다. 게스트 유형과 게스트의 참석 여부 응답을 지정합니다. 정의합니다.
CalendarContract.Reminders 이 테이블에는 경고/알림 데이터가 담겨 있습니다. 각 행이 주어진 이벤트에 대한 경고 하나를 나타냅니다. 일정에는 여러 리마인더를 포함할 수 있습니다. 이벤트당 최대 알림 개수는 MAX_REMINDERS에서 지정되며, 이는 주어진 캘린더를 소유한 동기화 어댑터에 의해 설정됩니다. 알림은 이벤트 몇 분 전에 지정되며 사용자에게 어떻게 경고할 것인지를 결정하는 메서드를 가지고 있습니다.

Calendar Provider API는 유연하고 효과적이도록 설계되었습니다. 그와 동시에 우수한 최종 사용자 환경을 제공하고 캘린더와 그 데이터의 무결성을 보호하는 것 또한 중요합니다. 이와 관련해 다음은 API를 사용할 때 유의해야 할 사항입니다.

  • 캘린더 일정 삽입, 업데이트, 보기. 캘린더 제공자로부터 직접 이벤트를 삽입, 변경하고 읽으려면 적절한 권한이 필요합니다. 그러나 완전한 캘린더 애플리케이션이나 동기화 어댑터를 빌드하지 않는 경우에는 이러한 권한을 요청할 필요가 없습니다. 대신 Android의 캘린더 애플리케이션이 지원하는 인텐트를 사용하여 해당 애플리케이션에 읽기 및 쓰기 작업을 분배하면 됩니다. 인텐트를 사용하면, 애플리케이션이 사용자를 캘린더 애플리케이션으로 보내 사전에 작성된 양식으로 원하는 작업을 수행하게 합니다. 작업이 완료되면 사용자는 애플리케이션으로 돌아옵니다. 캘린더를 통해 일반적인 작업을 수행하도록 애플리케이션을 설계함으로써, 사용자에게 일관되고 강력한 사용자 인터페이스를 제공합니다. 이것은 접근하는 것이 좋습니다 자세한 내용은 캘린더를 참조하세요. 인텐트를 참조하세요.
  • 동기화 어댑터. 동기화 어댑터는 사용자의 기기에 있는 캘린더 데이터를 다른 서버 또는 데이터 소스와 동기화합니다. CalendarContract.CalendarsCalendarContract.Events 테이블에는 동기화 어댑터가 사용하도록 예약된 열이 있습니다. 제공자와 애플리케이션은 이를 수정해서는 안 됩니다. 사실, 동기화 어댑터로 액세스하지 않으면 이 열은 표시되지 않습니다. 자세한 내용은 동기화 어댑터에 관한 자세한 내용은 동기화 어댑터를 참고하세요.

사용자 권한

캘린더 데이터를 읽으려면 애플리케이션의 매니페스트 파일에 READ_CALENDAR 권한이 포함되어 있어야 합니다. 그것은 WRITE_CALENDAR 권한을 포함해야 함 캘린더 데이터를 삭제, 삽입 또는 업데이트하려면 다음 단계를 따르세요.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"...>
    <uses-sdk android:minSdkVersion="14" />
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
    ...
</manifest>

캘린더 테이블

CalendarContract.Calendars 테이블에는 세부정보가 포함되어 있습니다. 개별 캘린더별로 사용 중지할 수 있습니다. 다음 캘린더 열은 애플리케이션과 동기화 어댑터 모두에서 쓸 수 있습니다. 지원되는 필드의 전체 목록은 CalendarContract.Calendars 참조.

상수 설명
NAME 캘린더 이름입니다.
CALENDAR_DISPLAY_NAME 사용자에게 표시되는 이 캘린더의 이름입니다.
VISIBLE 캘린더를 표시하기로 선택했는지를 나타내는 부울입니다. 값이 0인 경우 이 캘린더와 관련된 이벤트를 표시하면 안 된다는 뜻입니다. 값이 1인 경우 이 캘린더와 관련된 이벤트가 표시됩니다. 이 값은 CalendarContract.Instances 테이블의 행 생성에 영향을 미칩니다.
SYNC_EVENTS 캘린더를 동기화해야 하는지 그리고 캘린더를 기기에 저장된 이벤트가 감지될 수 있습니다. 값이 0이면 이 캘린더를 동기화하지 않도록 하거나 기기에 이벤트를 저장합니다. 값이 1인 경우 '이 캘린더의 일정 동기화'를 의미합니다. 이벤트를 기기에 저장합니다.

모든 작업에 대해 계정 유형 포함

Calendars.ACCOUNT_NAME에 대해 쿼리하는 경우 Calendars.ACCOUNT_TYPE 선택할 수 있습니다. 이는 주어진 계정을 고유하다고 간주하는 것은 해당 계정의 ACCOUNT_NAMEACCOUNT_TYPE이 모두 있을 때뿐이기 때문입니다. ACCOUNT_TYPE은 계정이 AccountManager에 등록되었을 때 사용된 계정 인증자에 상응하는 문자열입니다. 특별한 유형의 계정도 있습니다 호출: ACCOUNT_TYPE_LOCAL 기기 계정과 연결되지 않은 캘린더 계정 ACCOUNT_TYPE_LOCAL개에서 동기화되었습니다.

캘린더 쿼리

다음은 특정 사용자가 소유한 캘린더를 가져오는 방법을 보여주는 예입니다. 있습니다. 이 예에서는 단순하게 나타내기 위해 쿼리 작업을 사용자 인터페이스 스레드("기본 스레드")에 표시했습니다. 실제로는 기본 스레드 대신 비동기화 스레드에서 이 작업을 해야 합니다. 자세한 내용은 로더. 데이터를 읽기만 하는 것이 아니라 변경도 하는 경우라면 AsyncQueryHandler를 참고하세요.

Kotlin

// Projection array. Creating indices for this array instead of doing
// dynamic lookups improves performance.
private val EVENT_PROJECTION: Array<String> = arrayOf(
        CalendarContract.Calendars._ID,                     // 0
        CalendarContract.Calendars.ACCOUNT_NAME,            // 1
        CalendarContract.Calendars.CALENDAR_DISPLAY_NAME,   // 2
        CalendarContract.Calendars.OWNER_ACCOUNT            // 3
)

// The indices for the projection array above.
private const val PROJECTION_ID_INDEX: Int = 0
private const val PROJECTION_ACCOUNT_NAME_INDEX: Int = 1
private const val PROJECTION_DISPLAY_NAME_INDEX: Int = 2
private const val PROJECTION_OWNER_ACCOUNT_INDEX: Int = 3

자바

// Projection array. Creating indices for this array instead of doing
// dynamic lookups improves performance.
public static final String[] EVENT_PROJECTION = new String[] {
    Calendars._ID,                           // 0
    Calendars.ACCOUNT_NAME,                  // 1
    Calendars.CALENDAR_DISPLAY_NAME,         // 2
    Calendars.OWNER_ACCOUNT                  // 3
};

// The indices for the projection array above.
private static final int PROJECTION_ID_INDEX = 0;
private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;
private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;

다음 예시에서는 사용자가 직접 나름의 쿼리를 생성해 볼 수 있습니다. 선택 항목 쿼리의 기준을 지정합니다. 이 예시에서 쿼리는 ACCOUNT_NAME 'hera@example.com', ACCOUNT_TYPE 'com.example', OWNER_ACCOUNT 'hera@example.com'을 가지고 있는 캘린더를 찾습니다. 사용자가 사용자가 소유한 캘린더뿐만 아니라 확인한 경우 OWNER_ACCOUNT를 생략합니다. 이 쿼리는 Cursor 객체를 반환하는데, 이를 사용하여 데이터베이스 쿼리가 반환한 결과 집합을 트래버스할 수 있습니다. 콘텐츠 제공자에서 쿼리를 사용하는 방법에 관한 자세한 내용은 콘텐츠 제공자를 참고하세요.

Kotlin

// Run query
val uri: Uri = CalendarContract.Calendars.CONTENT_URI
val selection: String = "((${CalendarContract.Calendars.ACCOUNT_NAME} = ?) AND (" +
        "${CalendarContract.Calendars.ACCOUNT_TYPE} = ?) AND (" +
        "${CalendarContract.Calendars.OWNER_ACCOUNT} = ?))"
val selectionArgs: Array<String> = arrayOf("hera@example.com", "com.example", "hera@example.com")
val cur: Cursor = contentResolver.query(uri, EVENT_PROJECTION, selection, selectionArgs, null)

자바

// Run query
Cursor cur = null;
ContentResolver cr = getContentResolver();
Uri uri = Calendars.CONTENT_URI;
String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND ("
                        + Calendars.ACCOUNT_TYPE + " = ?) AND ("
                        + Calendars.OWNER_ACCOUNT + " = ?))";
String[] selectionArgs = new String[] {"hera@example.com", "com.example",
        "hera@example.com"};
// Submit the query and get a Cursor object back.
cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);

다음 섹션에서는 커서를 사용하여 결과 집합을 단계별로 살펴봅니다. 또한 값을 반환하기 위해 예제의 시작 부분에서 설정된 상수입니다. 확인할 수 있습니다.

Kotlin

// Use the cursor to step through the returned records
while (cur.moveToNext()) {
    // Get the field values
    val calID: Long = cur.getLong(PROJECTION_ID_INDEX)
    val displayName: String = cur.getString(PROJECTION_DISPLAY_NAME_INDEX)
    val accountName: String = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX)
    val ownerName: String = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX)
    // Do something with the values...
}

자바

// Use the cursor to step through the returned records
while (cur.moveToNext()) {
    long calID = 0;
    String displayName = null;
    String accountName = null;
    String ownerName = null;

    // Get the field values
    calID = cur.getLong(PROJECTION_ID_INDEX);
    displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX);
    accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX);
    ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX);

    // Do something with the values...

   ...
}

캘린더 수정

캘린더 업데이트를 실행하려면 캘린더의 _ID를 우리 (withAppendedId()개) 첫 번째 선택 항목으로 사용할 수 있습니다. 선택 항목 "_id=?"로 시작해야 하며 첫 번째는 selectionArg는 캘린더의 _ID여야 합니다. ID를 URI에 인코딩하는 방식으로 업데이트할 수도 있습니다. 이 예에서는 캘린더의 표시 이름 (withAppendedId()) 접근합니다.

Kotlin

const val DEBUG_TAG: String = "MyActivity"
...
val calID: Long = 2
val values = ContentValues().apply {
    // The new display name for the calendar
    put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, "Trevor's Calendar")
}
val updateUri: Uri = ContentUris.withAppendedId(CalendarContract.Calendars.CONTENT_URI, calID)
val rows: Int = contentResolver.update(updateUri, values, null, null)
Log.i(DEBUG_TAG, "Rows updated: $rows")

자바

private static final String DEBUG_TAG = "MyActivity";
...
long calID = 2;
ContentValues values = new ContentValues();
// The new display name for the calendar
values.put(Calendars.CALENDAR_DISPLAY_NAME, "Trevor's Calendar");
Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID);
int rows = getContentResolver().update(updateUri, values, null, null);
Log.i(DEBUG_TAG, "Rows updated: " + rows);

캘린더 삽입

캘린더는 주로 동기화 어댑터에서 관리하도록 설계되어 있으므로 새 캘린더만 동기화 어댑터로 삽입해야 합니다. 대부분의 경우 애플리케이션은 표시 이름 변경과 같은 피상적인 변경만 수행할 수 있습니다. 애플리케이션에서 로컬 캘린더를 만들어야 하는 경우 ACCOUNT_TYPE_LOCALACCOUNT_TYPE를 사용하여 캘린더 삽입을 동기화 어댑터로 실행하면 됩니다. ACCOUNT_TYPE_LOCAL는 기기 계정과 연결되지 않은 캘린더의 특별한 계정 유형입니다. 이 유형의 캘린더는 서버에 동기화되지 않습니다. 동기화 어댑터에 관한 설명은 동기화 어댑터를 참고하세요.

이벤트 테이블

CalendarContract.Events 테이블에는 개별 이벤트에 관한 세부정보가 포함되어 있습니다. 일정을 추가, 업데이트 또는 삭제하려면 애플리케이션이 WRITE_CALENDAR 권한을 매니페스트 파일에 있는지 확인합니다.

다음 이벤트 열은 애플리케이션과 동기화 어댑터 모두 쓸 수 있습니다. 지원되는 필드의 전체 목록은 CalendarContract.Events 참조를 확인하세요.

상수 설명
CALENDAR_ID 일정이 속한 캘린더의 _ID입니다.
ORGANIZER 이벤트 조직자(소유자)의 이메일입니다.
TITLE 이벤트 제목입니다.
EVENT_LOCATION 이벤트가 일어나는 장소입니다.
DESCRIPTION 이벤트 설명입니다.
DTSTART 이벤트가 시작되는 시간을 Epoch 이후 UTC 밀리초 단위로 나타낸 것입니다.
DTEND 이벤트가 종료되는 시간을 Epoch 이후 UTC 밀리초 단위로 나타낸 것입니다.
EVENT_TIMEZONE 이벤트의 표준 시간대입니다.
EVENT_END_TIMEZONE 이벤트 종료 시간의 표준 시간대입니다.
DURATION RFC5545 형식의 이벤트 기간입니다. 예를 들어 값이 "PT1H"이면 이벤트가 1시간 지속되어야 하며 "P2W"은 2주 동안 지속됩니다
ALL_DAY 값이 1인 경우 현지 시간대 값이 0이면 시작할 수 있는 정기 이벤트임을 나타냅니다. 하루 중 아무 때나 종료됩니다.
RRULE 이벤트 형식의 반복 규칙입니다. 예: "FREQ=WEEKLY;COUNT=10;WKST=SU". 자세한 예는 여기에서 확인하세요.
RDATE 이벤트의 반복 날짜입니다. 일반적으로 RDATE를 사용합니다. RRULE과(와) 함께 PersistentVolumeClaim에 포함할 수 있습니다. 자세한 내용은 RFC5545 사양을 참조하세요.
AVAILABILITY 이 이벤트가 사용 중인 시간으로 간주되는지, 아니면 예정되어 있습니다.
GUESTS_CAN_MODIFY 게스트가 이벤트를 수정할 수 있는지를 나타냅니다.
GUESTS_CAN_INVITE_OTHERS 게스트가 다른 게스트를 초대할 수 있는지를 나타냅니다.
GUESTS_CAN_SEE_GUESTS 게스트가 참석자 목록을 볼 수 있는지를 나타냅니다.

이벤트 추가

애플리케이션이 새 이벤트를 추가하는 경우 인텐트를 사용하여 이벤트 삽입에 설명된 대로 INSERT 인텐트를 사용하는 것이 좋습니다. 그러나 필요한 경우 직접 이벤트를 삽입해도 됩니다. 이 섹션에서는 이를 수행하는 방법을 설명합니다.

다음은 새 이벤트를 삽입할 때 지켜야 하는 규칙입니다.

다음은 이벤트 삽입의 예입니다. 단순하게 설명할 수 있도록 UI 스레드에서 수행됩니다. 실제로, 삽입과 업데이트는 비동기화 스레드에서 수행해야 작업을 백그라운드 스레드로 이동시킬 수 있습니다. 자세한 내용은 AsyncQueryHandler를 참고하세요.

Kotlin

val calID: Long = 3
val startMillis: Long = Calendar.getInstance().run {
    set(2012, 9, 14, 7, 30)
    timeInMillis
}
val endMillis: Long = Calendar.getInstance().run {
    set(2012, 9, 14, 8, 45)
    timeInMillis
}
...

val values = ContentValues().apply {
    put(CalendarContract.Events.DTSTART, startMillis)
    put(CalendarContract.Events.DTEND, endMillis)
    put(CalendarContract.Events.TITLE, "Jazzercise")
    put(CalendarContract.Events.DESCRIPTION, "Group workout")
    put(CalendarContract.Events.CALENDAR_ID, calID)
    put(CalendarContract.Events.EVENT_TIMEZONE, "America/Los_Angeles")
}
val uri: Uri = contentResolver.insert(CalendarContract.Events.CONTENT_URI, values)

// get the event ID that is the last element in the Uri
val eventID: Long = uri.lastPathSegment.toLong()
//
// ... do something with event ID
//
//

자바

long calID = 3;
long startMillis = 0;
long endMillis = 0;
Calendar beginTime = Calendar.getInstance();
beginTime.set(2012, 9, 14, 7, 30);
startMillis = beginTime.getTimeInMillis();
Calendar endTime = Calendar.getInstance();
endTime.set(2012, 9, 14, 8, 45);
endMillis = endTime.getTimeInMillis();
...

ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
values.put(Events.DTSTART, startMillis);
values.put(Events.DTEND, endMillis);
values.put(Events.TITLE, "Jazzercise");
values.put(Events.DESCRIPTION, "Group workout");
values.put(Events.CALENDAR_ID, calID);
values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles");
Uri uri = cr.insert(Events.CONTENT_URI, values);

// get the event ID that is the last element in the Uri
long eventID = Long.parseLong(uri.getLastPathSegment());
//
// ... do something with event ID
//
//

참고: 이 예시에서 이벤트를 캡처하는 방법을 확인하세요. 이벤트를 만든 후의 ID입니다. 이것이 가장 쉽게 이벤트 ID를 얻는 방법입니다. 자주 다른 캘린더 작업을 수행하려면 일정 ID가 필요합니다(예: 알림을 전송할 수 있습니다.

업데이트 이벤트

애플리케이션에서 사용자가 이벤트를 수정할 수 있게 하려면 다음과 같이 EDIT 인텐트를 사용하는 것이 좋습니다. 인텐트를 사용하여 이벤트 수정에 설명된 대로 구현합니다. 그러나 필요한 경우 직접 이벤트를 편집해도 됩니다. Cloud Shell의 _ID를 제공할 수 있습니다. 이벤트를 URI에 추가된 ID (withAppendedId())로 사용합니다. 첫 번째 선택 항목으로 지정합니다. 선택은 "_id=?"로 시작하고 첫 번째 selectionArg는 이벤트의 _ID여야 합니다. 다음과 같은 작업을 할 수 있습니다. 또한 ID가 없는 선택을 사용하여 업데이트를 수행합니다. 다음은 이벤트 업데이트의 예입니다. 여기에서는 이벤트 제목을 변경할 때 withAppendedId() 방법을 사용합니다.

Kotlin

val DEBUG_TAG = "MyActivity"
...
val eventID: Long = 188
...
val values = ContentValues().apply {
    // The new title for the event
    put(CalendarContract.Events.TITLE, "Kickboxing")
}
val updateUri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)
val rows: Int = contentResolver.update(updateUri, values, null, null)
Log.i(DEBUG_TAG, "Rows updated: $rows")

자바

private static final String DEBUG_TAG = "MyActivity";
...
long eventID = 188;
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
Uri updateUri = null;
// The new title for the event
values.put(Events.TITLE, "Kickboxing");
updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
int rows = cr.update(updateUri, values, null, null);
Log.i(DEBUG_TAG, "Rows updated: " + rows);

일정 삭제

이벤트를 삭제하려면 이벤트의 _ID를 URI에 추가된 ID로 사용하거나 표준 선택을 사용합니다. 추가된 ID를 사용할 경우 선택도 할 수 없습니다. 삭제하는 방법은 두 가지입니다. 애플리케이션으로서 삭제하는 방법과 동기화 어댑터로서 삭제하는 방법입니다. 애플리케이션 삭제는 삭제됨 열을 1로 설정합니다. 이 플래그는 동기화 어댑터에 행이 삭제되었으며 이 삭제를 서버에 전파해야 한다고 알립니다. 동기화 어댑터 삭제는 모든 관련 데이터가 포함됩니다 이 애플리케이션은 _ID를 통해 이벤트 삭제:

Kotlin

val DEBUG_TAG = "MyActivity"
...
val eventID: Long = 201
...
val deleteUri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)
val rows: Int = contentResolver.delete(deleteUri, null, null)
Log.i(DEBUG_TAG, "Rows deleted: $rows")

자바

private static final String DEBUG_TAG = "MyActivity";
...
long eventID = 201;
...
ContentResolver cr = getContentResolver();
Uri deleteUri = null;
deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
int rows = cr.delete(deleteUri, null, null);
Log.i(DEBUG_TAG, "Rows deleted: " + rows);

참석자 테이블

CalendarContract.Attendees 테이블의 각 행 이벤트의 단일 참석자 또는 참석자를 나타냅니다. 전화 거는 중 query() 는 이벤트를 EVENT_ID합니다. 이 EVENT_ID는 특정 이벤트의 _ID와 일치해야 합니다.

다음 표에는 쓰기 가능한 필드로 구성됩니다. 새 참석자를 삽입하는 경우 ATTENDEE_NAME를 제외한 모든 필드를 포함해야 합니다.

상수 설명
EVENT_ID 이벤트 ID입니다.
ATTENDEE_NAME 참석자 이름입니다.
ATTENDEE_EMAIL 참석자 이메일 주소입니다.
ATTENDEE_RELATIONSHIP

참석자와 이벤트의 관계입니다. 다음 중 하나로 정해집니다.

ATTENDEE_TYPE

참석자 유형입니다. 다음 중 하나로 정해집니다.

ATTENDEE_STATUS

참석자의 참석 상태입니다. 다음 중 하나로 정해집니다.

참석자 추가

다음은 이벤트에 참석자 한 명을 추가하는 예입니다. 참고: EVENT_ID 는 필수 항목입니다.

Kotlin

val eventID: Long = 202
...
val values = ContentValues().apply {
    put(CalendarContract.Attendees.ATTENDEE_NAME, "Trevor")
    put(CalendarContract.Attendees.ATTENDEE_EMAIL, "trevor@example.com")
    put(
        CalendarContract.Attendees.ATTENDEE_RELATIONSHIP,
        CalendarContract.Attendees.RELATIONSHIP_ATTENDEE
    )
    put(CalendarContract.Attendees.ATTENDEE_TYPE, CalendarContract.Attendees.TYPE_OPTIONAL)
    put(
        CalendarContract.Attendees.ATTENDEE_STATUS,
        CalendarContract.Attendees.ATTENDEE_STATUS_INVITED
    )
    put(CalendarContract.Attendees.EVENT_ID, eventID)
}
val uri: Uri = contentResolver.insert(CalendarContract.Attendees.CONTENT_URI, values)

자바

long eventID = 202;
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
values.put(Attendees.ATTENDEE_NAME, "Trevor");
values.put(Attendees.ATTENDEE_EMAIL, "trevor@example.com");
values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL);
values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED);
values.put(Attendees.EVENT_ID, eventID);
Uri uri = cr.insert(Attendees.CONTENT_URI, values);

알림 테이블

CalendarContract.Reminders 테이블의 각 행은 이벤트의 알림 하나를 나타냅니다. query()를 호출하면 주어진 EVENT_ID와 함께 이벤트의 리마인더 목록을 반환합니다.

다음 표는 알림에 대해 쓰기 가능한 필드를 나열한 것입니다. 모두 새 알림을 삽입할 때 포함되어야 합니다. 동기화 어댑터는 CalendarContract.Calendars 테이블에서 지원하는 리마인더 유형입니다. 자세한 내용은 ALLOWED_REMINDERS 참조하세요.

상수 설명
EVENT_ID 이벤트 ID입니다.
MINUTES 이벤트 몇 분 전에 알림을 보내야 하는지 나타냅니다.
METHOD

알람 메서드이며, 서버에서 설정한 대로 따릅니다. 다음 중 하나로 정해집니다.

알림 추가

이 예시는 이벤트에 알림을 추가합니다. 리마인더는 15회 실행됩니다. 일정 분 전

Kotlin

val eventID: Long = 221
...
val values = ContentValues().apply {
    put(CalendarContract.Reminders.MINUTES, 15)
    put(CalendarContract.Reminders.EVENT_ID, eventID)
    put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT)
}
val uri: Uri = contentResolver.insert(CalendarContract.Reminders.CONTENT_URI, values)

자바

long eventID = 221;
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
values.put(Reminders.MINUTES, 15);
values.put(Reminders.EVENT_ID, eventID);
values.put(Reminders.METHOD, Reminders.METHOD_ALERT);
Uri uri = cr.insert(Reminders.CONTENT_URI, values);

인스턴스 테이블

CalendarContract.Instances 테이블에는 이벤트 발생의 시작 및 종료 시간을 설정합니다. 이 테이블의 각 행 단일 이벤트 발생을 나타냅니다. 인스턴스 테이블은 쓰기가 불가능하며 이벤트 어커런스를 쿼리하는 방법을 제공합니다.

다음 표에는 인스턴스에 대해 쿼리할 수 있는 몇 가지 필드를 나열했습니다. 시간대는 KEY_TIMEZONE_TYPEKEY_TIMEZONE_INSTANCES로 정의됩니다.

상수 설명
BEGIN 인스턴스 시작 시간을 UTC 밀리초로 나타낸 것입니다.
END 인스턴스 종료 시간을 UTC 밀리초로 나타낸 것입니다.
END_DAY 인스턴스의 율리우스력 종료일(캘린더 시간 기준) 사용할 수 있습니다
END_MINUTE 인스턴스의 종료 시간(분 단위)을 캘린더 표준 시간대의 자정부터 측정한 것입니다.
EVENT_ID 이 인스턴스에 대한 이벤트의 _ID입니다.
START_DAY 인스턴스의 율리우스력 시작 날짜를 캘린더의 표준 시간대에 비례하여 나타낸 것입니다.
START_MINUTE 인스턴스의 시작 시간(분 단위)을 캘린더 표준 시간대에 비례하여 자정부터 측정한 것입니다.

인스턴스 테이블 쿼리

인스턴스 테이블을 쿼리하려면, 해당 쿼리에 대한 범위 시간을 URI에 지정해야 합니다. 이 예시에서 CalendarContract.InstancesCalendarContract.EventsColumns 인터페이스의 구현을 통해 TITLE 필드에 대한 액세스 권한을 얻습니다. 즉, TITLE는 원시 CalendarContract.Instances 테이블을 쿼리하는 것이 아니라 데이터베이스 보기를 통해 반환됩니다.

Kotlin

const val DEBUG_TAG: String = "MyActivity"
val INSTANCE_PROJECTION: Array<String> = arrayOf(
        CalendarContract.Instances.EVENT_ID, // 0
        CalendarContract.Instances.BEGIN, // 1
        CalendarContract.Instances.TITLE // 2
)

// The indices for the projection array above.
const val PROJECTION_ID_INDEX: Int = 0
const val PROJECTION_BEGIN_INDEX: Int = 1
const val PROJECTION_TITLE_INDEX: Int = 2

// Specify the date range you want to search for recurring
// event instances
val startMillis: Long = Calendar.getInstance().run {
    set(2011, 9, 23, 8, 0)
    timeInMillis
}
val endMillis: Long = Calendar.getInstance().run {
    set(2011, 10, 24, 8, 0)
    timeInMillis
}

// The ID of the recurring event whose instances you are searching
// for in the Instances table
val selection: String = "${CalendarContract.Instances.EVENT_ID} = ?"
val selectionArgs: Array<String> = arrayOf("207")

// Construct the query with the desired date range.
val builder: Uri.Builder = CalendarContract.Instances.CONTENT_URI.buildUpon()
ContentUris.appendId(builder, startMillis)
ContentUris.appendId(builder, endMillis)

// Submit the query
val cur: Cursor = contentResolver.query(
        builder.build(),
        INSTANCE_PROJECTION,
        selection,
        selectionArgs, null
)
while (cur.moveToNext()) {
    // Get the field values
    val eventID: Long = cur.getLong(PROJECTION_ID_INDEX)
    val beginVal: Long = cur.getLong(PROJECTION_BEGIN_INDEX)
    val title: String = cur.getString(PROJECTION_TITLE_INDEX)

    // Do something with the values.
    Log.i(DEBUG_TAG, "Event: $title")
    val calendar = Calendar.getInstance().apply {
        timeInMillis = beginVal
    }
    val formatter = SimpleDateFormat("MM/dd/yyyy")
    Log.i(DEBUG_TAG, "Date: ${formatter.format(calendar.time)}")
}

자바

private static final String DEBUG_TAG = "MyActivity";
public static final String[] INSTANCE_PROJECTION = new String[] {
    Instances.EVENT_ID,      // 0
    Instances.BEGIN,         // 1
    Instances.TITLE          // 2
  };

// The indices for the projection array above.
private static final int PROJECTION_ID_INDEX = 0;
private static final int PROJECTION_BEGIN_INDEX = 1;
private static final int PROJECTION_TITLE_INDEX = 2;
...

// Specify the date range you want to search for recurring
// event instances
Calendar beginTime = Calendar.getInstance();
beginTime.set(2011, 9, 23, 8, 0);
long startMillis = beginTime.getTimeInMillis();
Calendar endTime = Calendar.getInstance();
endTime.set(2011, 10, 24, 8, 0);
long endMillis = endTime.getTimeInMillis();

Cursor cur = null;
ContentResolver cr = getContentResolver();

// The ID of the recurring event whose instances you are searching
// for in the Instances table
String selection = Instances.EVENT_ID + " = ?";
String[] selectionArgs = new String[] {"207"};

// Construct the query with the desired date range.
Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
ContentUris.appendId(builder, startMillis);
ContentUris.appendId(builder, endMillis);

// Submit the query
cur =  cr.query(builder.build(),
    INSTANCE_PROJECTION,
    selection,
    selectionArgs,
    null);

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

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

    // Do something with the values.
    Log.i(DEBUG_TAG, "Event:  " + title);
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(beginVal);
    DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
    Log.i(DEBUG_TAG, "Date: " + formatter.format(calendar.getTime()));
    }
 }

캘린더 인텐트

애플리케이션에 캘린더 데이터를 읽고 쓰는 데 권한은 필요하지 않습니다. 대신 Android의 캘린더 애플리케이션이 지원하는 인텐트를 사용하여 해당 애플리케이션에 읽기 및 쓰기 작업을 분배하면 됩니다. 다음 표는 캘린더 제공자가 지원하는 인텐트를 나열한 것입니다.

작업 URI 설명 추가

VIEW

content://com.android.calendar/time/<ms_since_epoch>

CalendarContract.CONTENT_URI로도 URI를 참조할 수 있습니다. 이 인텐트 사용 방법의 예는 인텐트를 사용하여 캘린더 데이터 보기를 참조하세요.
캘린더를 <ms_since_epoch>에서 지정한 시간으로 엽니다. 없음

VIEW

content://com.android.calendar/events/<event_id>

Events.CONTENT_URI로도 URI를 참조할 수 있습니다. 이 인텐트 사용 방법의 예시는 인텐트를 사용하여 캘린더 데이터 보기를 참고하세요.
<event_id>에서 지정한 이벤트를 봅니다. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

content://com.android.calendar/events/<event_id>

Events.CONTENT_URI로도 URI를 참조할 수 있습니다. 이 인텐트를 사용하는 예를 보려면 인텐트를 사용하여 이벤트 편집을 참조하세요.
<event_id>로 지정된 이벤트를 수정합니다. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

INSERT

content://com.android.calendar/events

Events.CONTENT_URI로도 URI를 참조할 수 있습니다. 이 인텐트 사용 방법의 예시는 인텐트를 사용하여 이벤트 삽입을 참고하세요.
일정을 만듭니다. 아래 테이블에 목록으로 표시된 추가 사항 모두입니다.

다음 표에는 캘린더 제공자가 지원하는 인텐트 엑스트라가 나나열다.

인텐트 추가 사항 설명
Events.TITLE 이벤트의 이름입니다.
CalendarContract.EXTRA_EVENT_BEGIN_TIME 이벤트 시작 시간을 Epoch로부터 밀리초 단위로 나타낸 것입니다.
CalendarContract.EXTRA_EVENT_END_TIME 이벤트 종료 시간을 Epoch로부터 밀리초 단위로 나타낸 것입니다.
CalendarContract.EXTRA_EVENT_ALL_DAY 이벤트가 종일 이벤트인지 나타내는 부울입니다. 값은 true 또는 false
Events.EVENT_LOCATION 이벤트 위치입니다.
Events.DESCRIPTION 이벤트 설명입니다.
Intent.EXTRA_EMAIL 초대할 사람의 이메일 주소를 쉼표로 구분한 목록입니다.
Events.RRULE 이벤트의 반복 규칙입니다.
Events.ACCESS_LEVEL 이벤트가 비공개인지 공개인지 나타냅니다.
Events.AVAILABILITY 이 이벤트가 사용 중인 시간으로 간주되는지, 일정을 예약할 수 있는 자유 시간으로 간주되는지를 나타냅니다.

아래의 섹션에서는 이와 같은 인텐트의 사용법을 설명합니다.

인텐트를 사용하여 이벤트 삽입

INSERT 인텐트 사용 를 사용하면 애플리케이션이 일정 삽입 작업을 캘린더 자체에 전달할 수 있습니다. 이 방법을 사용하면 애플리케이션의 매니페스트 파일WRITE_CALENDAR 권한을 포함할 필요도 없습니다.

사용자가 이 방법을 사용하는 애플리케이션을 실행하면 해당 애플리케이션이 사용자를 캘린더로 보내 이벤트 추가를 완료합니다. INSERT 인텐트는 추가 필드를 사용하여 캘린더의 일정 세부정보로 양식을 미리 채웁니다. 사용자가 할 수 있는 작업 그런 다음 이벤트를 취소하거나, 필요에 따라 양식을 수정하거나, 있습니다.

다음은 2012년 1월 19일에 오전 7:30~오전 8:30까지 실행되는 이벤트 일정을 예약하는 코드 스니펫입니다. 이 스니펫에서 다음 사항에 주목하세요.

Kotlin

val startMillis: Long = Calendar.getInstance().run {
    set(2012, 0, 19, 7, 30)
    timeInMillis
}
val endMillis: Long = Calendar.getInstance().run {
    set(2012, 0, 19, 8, 30)
    timeInMillis
}
val intent = Intent(Intent.ACTION_INSERT)
        .setData(CalendarContract.Events.CONTENT_URI)
        .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, startMillis)
        .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endMillis)
        .putExtra(CalendarContract.Events.TITLE, "Yoga")
        .putExtra(CalendarContract.Events.DESCRIPTION, "Group class")
        .putExtra(CalendarContract.Events.EVENT_LOCATION, "The gym")
        .putExtra(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_BUSY)
        .putExtra(Intent.EXTRA_EMAIL, "rowan@example.com,trevor@example.com")
startActivity(intent)

자바

Calendar beginTime = Calendar.getInstance();
beginTime.set(2012, 0, 19, 7, 30);
Calendar endTime = Calendar.getInstance();
endTime.set(2012, 0, 19, 8, 30);
Intent intent = new Intent(Intent.ACTION_INSERT)
        .setData(Events.CONTENT_URI)
        .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis())
        .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis())
        .putExtra(Events.TITLE, "Yoga")
        .putExtra(Events.DESCRIPTION, "Group class")
        .putExtra(Events.EVENT_LOCATION, "The gym")
        .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY)
        .putExtra(Intent.EXTRA_EMAIL, "rowan@example.com,trevor@example.com");
startActivity(intent);

인텐트를 사용하여 이벤트 편집

이벤트 업데이트에 설명된 대로 이벤트를 직접 업데이트할 수 있습니다. 그러나 EDIT 인텐트를 사용하면 권한이 없는 애플리케이션이 캘린더 애플리케이션에 이벤트 편집을 넘길 수 있습니다. 사용자가 캘린더에서 일정 편집을 마치면 원래 애플리케이션으로 돌아오게 됩니다.

이것은 새 포드를 설정하는 인텐트의 사용자가 Calendar에서 일정을 수정할 수 있도록 합니다.

Kotlin

val eventID: Long = 208
val uri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)
val intent = Intent(Intent.ACTION_EDIT)
        .setData(uri)
        .putExtra(CalendarContract.Events.TITLE, "My New Title")
startActivity(intent)

자바

long eventID = 208;
Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
Intent intent = new Intent(Intent.ACTION_EDIT)
    .setData(uri)
    .putExtra(Events.TITLE, "My New Title");
startActivity(intent);

인텐트를 사용하여 캘린더 데이터 보기

캘린더 제공자는 VIEW 인텐트를 사용하는 두 가지 방식을 제공합니다.

  • 캘린더를 특정 날짜에 여는 방식
  • 이벤트를 보는 방식

다음은 캘린더를 특정 날짜에 여는 방법을 보여주는 예입니다.

Kotlin

val startMillis: Long
...
val builder: Uri.Builder = CalendarContract.CONTENT_URI.buildUpon()
        .appendPath("time")
ContentUris.appendId(builder, startMillis)
val intent = Intent(Intent.ACTION_VIEW)
        .setData(builder.build())
startActivity(intent)

자바

// A date-time specified in milliseconds since the epoch.
long startMillis;
...
Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
builder.appendPath("time");
ContentUris.appendId(builder, startMillis);
Intent intent = new Intent(Intent.ACTION_VIEW)
    .setData(builder.build());
startActivity(intent);

다음은 이벤트를 보기 위해 여는 방법을 나타낸 예입니다.

Kotlin

val eventID: Long = 208
...
val uri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)
val intent = Intent(Intent.ACTION_VIEW).setData(uri)
startActivity(intent)

자바

long eventID = 208;
...
Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
Intent intent = new Intent(Intent.ACTION_VIEW)
   .setData(uri);
startActivity(intent);

동기화 어댑터

애플리케이션과 동기화 어댑터가 캘린더 제공자에 액세스하는 방식에는 사소한 차이만 있을 뿐입니다.

  • 동기화 어댑터는 CALLER_IS_SYNCADAPTERtrue로 설정하여 동기화 어댑터임을 지정해야 합니다.
  • 동기화 어댑터는 URI에서 쿼리 매개변수로 ACCOUNT_NAMEACCOUNT_TYPE을 제공해야 합니다.
  • 동기화 어댑터에는 애플리케이션 또는 위젯에 비해 더 많은 열을 쓸 수 있는 권한이 있습니다. 예를 들어 애플리케이션은 이름, 표시 이름, 가시성 설정, 캘린더 동기화 여부 등과 같이 캘린더의 몇 가지 특성만 수정할 수 있습니다. 이에 비해 동기화 어댑터는 이러한 열뿐만 아니라 다른 많은 열에 액세스할 수 있습니다. 예를 들어 캘린더 색상, 시간대, 액세스 수준, 위치 등입니다. 그러나 동기화 어댑터는 ACCOUNT_NAME 및 지정한 ACCOUNT_TYPE입니다.

다음은 동기화 어댑터와 사용하기 위한 URI를 반환하는 데 쓸 수 있는 도우미 메서드입니다.

Kotlin

fun asSyncAdapter(uri: Uri, account: String, accountType: String): Uri {
    return uri.buildUpon()
            .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
            .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, account)
            .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, accountType).build()
}

Java

static Uri asSyncAdapter(Uri uri, String account, String accountType) {
    return uri.buildUpon()
        .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true")
        .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
        .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
 }