page.title=Поставщик календаря @jd:body
Поставщик календаря представляет собой репозиторий для событий календаря пользователя. API поставщика календаря позволяет запрашивать, вставлять, обновлять и удалять календари, события, участников, напоминания и т. д.
API поставщика календаря может использоваться как приложениями, так и адаптерами синхронизации. Правила зависят от типа программы, которая выполняет вызовы. В этой статье главным образом рассматривается использование API поставщика календаря в качестве приложения. Сведения о различиях между адаптерами синхронизации представлены в разделе Адаптеры синхронизации.
Обычно, чтобы считать или записать данные календаря, в манифесте приложения должны быть включены надлежащие разрешения, которые описываются в разделе Разрешения пользователей. Чтобы упростить выполнение часто используемых операций, в поставщике календаря предусмотрен набор намерений, как описано в разделе Намерения календаря. Эти намерения позволяют пользователям переходить в приложение календаря для вставки, просмотра и редактирования событий. После взаимодействия пользователя с календарем он возвращается в исходное приложение. Поэтому вашему приложению не нужно запрашивать разрешения, а также предоставлять пользовательский интерфейс для просмотра или создания событий.
Поставщики контента хранят в себе данные и предоставляют к ним доступ для приложений. Поставщики контента, предлагаемые платформой Android (включая поставщик календаря) обычно представляют данные в виде набора таблиц, в основе которых лежит модель реляционной базы данных. Каждая строка в такой таблице представляет собой запись, а каждый столбец — данные определенного типа и значения. Благодаря API поставщика календаря приложения и адаптеры синхронизации получают доступ на чтение/запись к таблицам в базе данных, в которых представлены данные календаря пользователя.
Каждый поставщик календаря предоставляет общедоступный URI (упакованный в объект
{@link android.net.Uri}),
который служит уникальным идентификатором своего набора данных. Поставщик контента, который управляет
несколькими наборами данных (несколькими таблицами), предоставляет отдельный URI для каждого набора. Все
URI поставщиков начинаются со строки content://. Она
определяет данные, которые находятся под управлением поставщика контента. Поставщик календаря
задает константы для URI каждого из своих классов (таблиц). Такие
URI имеют формат <class>.CONTENT_URI
. Например,
{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
На рисунке 1 изображено графическое представление модели данных поставщика календаря. На нем представлены основные таблицы и поля, которые связывают их друг с другом.
Рисунок 1. Модель данных поставщика календаря.
У пользователя может быть несколько календарей, причем они могут быть связаны с аккаунтами разных типов (Google Календарь, Exchange и т. д.).
Класс {@link android.provider.CalendarContract} определяет модель данных календаря и информацию, относящуюся к событиям. Эти данные хранятся в различных таблицах, указанных ниже.
Таблица (класс) | Описание |
---|---|
{@link android.provider.CalendarContract.Calendars} |
В этой таблице находится информация о календарях. В каждой строке этой таблицы представлены сведения об отдельном календаре, например, его название, цвет, информация о синхронизации и т. д. |
{@link android.provider.CalendarContract.Events} | В этой таблице находится информация о событиях. В каждой строке этой таблицы содержится информация об отдельном событии —например, заголовок события, место проведения, время начала, время завершения и т. д. Событие может быть однократным или повторяющимся. Сведения об участниках, напоминаниях и расширенные свойства хранятся в отдельных таблицах. В каждой из них имеется целочисленная переменная {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}, которая ссылается на объект {@link android.provider.BaseColumns#_ID} в таблице событий. |
{@link android.provider.CalendarContract.Instances} | В этой таблице содержатся данные о времени начала и окончания каждого повторения события. В каждой строке этой таблицы представлено одно повторение события. Однократные события сопоставляются с повторениями один к одному. Для повторяющихся событий автоматически создаются несколько строк, которые соответствуют нескольким повторениям события. |
{@link android.provider.CalendarContract.Attendees} | В этой таблице находится информация об участниках (гостях). В каждой строке этой таблицы указан один гость. В ней указываются тип гостя и информация о том, посетит ли он событие. |
{@link android.provider.CalendarContract.Reminders} | В этой таблице находятся данные уведомлений или оповещений. В каждой строке этой таблицы указано одно уведомление или оповещение. Для одного события можно создать несколько напоминаний. Максимальное количество таких напоминаний для события задается с помощью целочисленной переменной {@link android.provider.CalendarContract.CalendarColumns#MAX_REMINDERS}, значение которой задает адаптер синхронизации, владеющий указанным календарем. Напоминания задаются в минутах до начала события и имеют метод, который определяет порядок уведомления пользователя. |
API поставщика календаря обеспечивает достаточную гибкость и эффективность. В то же время важно предоставить интерфейс, который будет удобным для пользователя, и обеспечить защиту целостности календаря и его данных. Поэтому существует ряд моментов, которые следует учитывать при использовании этого API.
Чтобы считать данные календаря, в файл манифеста приложения необходимо включить разрешение {@link android.Manifest.permission#READ_CALENDAR}. Также в него следует включить разрешение {@link android.Manifest.permission#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>
В таблице {@link android.provider.CalendarContract.Calendars} содержатся подробные сведения о каждом отдельном календаре. Выполнять запись в указанные ниже столбцы этой таблицы могут и приложение, и адаптер синхронизации. Полный список поддерживаемых полей представлен в справке по классу {@link android.provider.CalendarContract.Calendars}.
Константа | Описание |
---|---|
{@link android.provider.CalendarContract.Calendars#NAME} | Название календаря. |
{@link android.provider.CalendarContract.Calendars#CALENDAR_DISPLAY_NAME} | Название этого календаря, которое отображается для пользователя. |
{@link android.provider.CalendarContract.Calendars#VISIBLE} | Логическое значение, обозначающее, выбран ли календарь для отображения. Значение «0» указывает на то, что события, связанные с этим календарем, не отображаются. Значение «1» указывает на то, что события, связанные с этим календарем, отображаются. Это значение влияет на создание строк в таблице {@link android.provider.CalendarContract.Instances}. |
{@link android.provider.CalendarContract.CalendarColumns#SYNC_EVENTS} | Логическое значение, обозначающее, следует ли синхронизировать календарь и хранить имеющиеся в нем события на устройстве. Значение «0» указывает, что не следует синхронизировать этот календарь или хранить имеющиеся в нем события на устройстве. Значение «1» указывает, что этот календарь следует синхронизировать и хранить имеющиеся в нем события на устройстве. |
Ниже представлен пример того, как получить календари, которыми владеет определенный пользователь. Для простоты демонстрации операция запроса в этом примере находится в потоке пользовательского интерфейса («основной поток»). На практике это следует делать в асинхронном потоке, а не в основном. Дополнительные сведения представлены в статье Загрузчики. Если же вы не только считываете данные, но и вносите в них изменения, обратитесь к справке по классу {@link android.content.AsyncQueryHandler}.
// 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;
При создании запроса {@link
android.provider.CalendarContract.Calendars#ACCOUNT_NAME
Calendars.ACCOUNT_NAME} необходимо также
указать
{@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}. Это необходимо сделать ввиду того, что указанный аккаунт
считается уникальным только тогда, когда для него указаны и параметр ACCOUNT_NAME
, и параметр
ACCOUNT_TYPE
. Параметр ACCOUNT_TYPE
в строке обозначает
структуру проверки подлинности аккаунта, которая использовалась при регистрации аккаунта с помощью
{@link android.accounts.AccountManager}. Существует также особый тип аккаунтов, называемый {@link
android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}. Он используется для календарей,
которые не связаны с аккаунтом устройства. Аккаунты {@link
android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} не
синхронизируются.
В следующей части примера создается запрос. С помощью выбора определяются
критерии для запроса. В этом примере выполняется поиск
календарей со следующими значениями параметров: ACCOUNT_NAME
— sampleuser@google.com, ACCOUNT_TYPE
— com.google и OWNER_ACCOUNT
— sampleuser@google.com. Для просмотра всех просмотренных
пользователем календарей, а не только имеющихся у него, не указывайте параметр OWNER_ACCOUNT
.
Запрос возвращает объект {@link android.database.Cursor},
который можно использовать для перебора результатов, возвращенных запросом к базе
данных. Дополнительные сведения об использовании запросов в поставщиках контента
представлены в статье Поставщики контента.
// 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[] {"sampleuser@gmail.com", "com.google", "sampleuser@gmail.com"}; // Submit the query and get a Cursor object back. cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);
В следующем разделе кода выполняется пошаговый обзор набора результатов с помощью курсора. В нем используются константы, которые были заданы в начале примера, для получения значений для каждого из полей.
// 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... ... }
Чтобы обновить календарь, можно указать {@link
android.provider.BaseColumns#_ID} календаря: либо в виде идентификатора,
добавленного к URI
({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}),
либо в качестве первого элемента выделения. Выделение
должно начинаться с "_id=?"
, а первым аргументом
selectionArg
должен быть {@link
android.provider.BaseColumns#_ID} календаря.
Также для выполнения обновлений можно закодировать идентификатор в URI. В этом примере для
изменения отображаемого имени календаря используется
подход
({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}):
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);
Для управления календарями в основном используются адаптеры синхронизации, поэтому новые календари следует вставлять исключительно как адаптер синхронизации. По большей части приложения могут вносить в календари только поверхностные изменения, такие как изменение отображаемого имени. Если приложению требуется создать локальный календарь, это можно сделать путем вставки календаря в виде адаптера синхронизации с помощью параметра {@link android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} типа {@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}. {@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} представляет собой особый тип аккаунтов для календарей, которые не связаны с аккаунтом устройства. Календари этого типа не синхронизируются с сервером. Дополнительные сведения об адаптерах синхронизации представлены в статье Адаптеры синхронизации.
В таблице {@link android.provider.CalendarContract.Events} содержатся подробные сведения о каждом отдельном событии. Чтобы получить возможность добавлять, обновлять или удалять события, в файл манифеста приложения необходимо включить разрешение {@link android.Manifest.permission#WRITE_CALENDAR}.
Выполнять запись в указанные ниже столбцы этой таблицы могут и приложение, и адаптер синхронизации. Полный список поддерживаемых полей представлен в справке по классу {@link android.provider.CalendarContract.Events}.
Константа | Описание |
---|---|
{@link android.provider.CalendarContract.EventsColumns#CALENDAR_ID} | {@link android.provider.BaseColumns#_ID} календаря, к которому принадлежит событие. |
{@link android.provider.CalendarContract.EventsColumns#ORGANIZER} | Адрес эл. почты организатора (владельца) события. |
{@link android.provider.CalendarContract.EventsColumns#TITLE} | Название события. |
{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION} | Место проведения. |
{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION} | Описание события. |
{@link android.provider.CalendarContract.EventsColumns#DTSTART} | Время начала события по UTC (в миллисекундах) от точки отсчета. |
{@link android.provider.CalendarContract.EventsColumns#DTEND} | Время окончания события по UTC (в миллисекундах) от точки отсчета. |
{@link android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE} | Часовой пояс события. |
{@link android.provider.CalendarContract.EventsColumns#EVENT_END_TIMEZONE} | Часовой пояс для времени окончания события. |
{@link android.provider.CalendarContract.EventsColumns#DURATION} | Продолжительность события в формате RFC5545.
Например, значение "PT1H" обозначает, что событие
должно длиться один час, а значение "P2W" указывает на продолжительность
в 2 недели. |
{@link android.provider.CalendarContract.EventsColumns#ALL_DAY} | Значение «1» обозначает, что это событие занимает весь день по местному часовому поясу. Значение «0» указывает на то, что это регулярное событие, которое может начаться и завершиться в любое время в течение дня. |
{@link android.provider.CalendarContract.EventsColumns#RRULE} | Правило повторения для формата события. Например,
"FREQ=WEEKLY;COUNT=10;WKST=SU" . С другими
примерами можно ознакомиться здесь. |
{@link android.provider.CalendarContract.EventsColumns#RDATE} | Даты повторения события. Обычно {@link android.provider.CalendarContract.EventsColumns#RDATE} используется вместе с {@link android.provider.CalendarContract.EventsColumns#RRULE} для определения агрегированного набора повторяющихся событий. Дополнительные сведения представлены в спецификации RFC5545. |
{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY} | Если событие считается как занятое или как свободное время, доступное для планирования. |
{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_MODIFY} | Указывает, могут ли гости вносить изменения в событие. |
{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_INVITE_OTHERS} | Указывает, могут ли гости приглашать других гостей. |
{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_SEE_GUESTS} | Указывает, могут ли гости просматривать список участников. |
Когда ваше приложение вставляет новое событие, мы рекомендуем использовать намерение {@link android.content.Intent#ACTION_INSERT INSERT}, как описано в разделе Использование намерения для вставки события. Однако при необходимости вы можете вставлять события напрямую. В этом разделе как раз описывается то, как это сделать.
Ниже указаны правила, которыми следует руководствоваться для вставки нового события.
Ниже представлен пример вставки события. Для простоты все это выполняется в потоке пользовательского интерфейса. На практике же все вставки и обновления следует выполнять в асинхронном потоке, чтобы переместить операцию в фоновый поток. Дополнительные сведения представлены в справке по {@link android.content.AsyncQueryHandler}.
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 // //
Примечание. Ниже демонстрируется, как в примере кода выполняется захват идентификатора события после создания этого события. Это самый простой способ получить идентификатор события. Зачастую идентификатор события необходим для выполнения других действий с календарем — например, для добавления участников или напоминаний о событии.
Когда ваше приложение хочет предоставить пользователю возможность изменить событие, мы рекомендуем использовать намерение
{@link android.content.Intent#ACTION_EDIT EDIT}, как описано в разделе
Использование намерения для вставки события.
Однако при необходимости вы можете редактировать события напрямую. Чтобы обновить
событие, можно указать
_ID
события: либо в виде идентификатора, добавленного к URI({@link
android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}),
либо в качестве первого элемента выделения. Выделение
должно начинаться с "_id=?"
, а первым аргументом
selectionArg
должен быть _ID
события. Также можно обновлять
выделения без идентификаторов. Ниже представлен пример обновления
события. Это пример изменения названия события с помощью
метода
{@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}:
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 = getContentResolver().update(updateUri, values, null, null); Log.i(DEBUG_TAG, "Rows updated: " + rows);
Удалить событие можно по его {@link android.provider.BaseColumns#_ID}, который добавлен в качестве идентификатора к URI, или с помощью стандартного выделения. В случае использования добавленного идентификатора невозможно также выполнить и выделение. Существует две версии операции удаления: для приложения и для адаптера синхронизации. При удалении для приложения в столбце deleted устанавливается значение «1». Этот флаг сообщает адаптеру синхронизации о том, что строка была удалена и информацию об удалении следует передать серверу. При удалении для адаптера синхронизации событие удаляется из базы данных вместе со всеми связанными с ним данными. Ниже представлен пример удаления события для приложения по его {@link android.provider.BaseColumns#_ID}.
private static final String DEBUG_TAG = "MyActivity"; ... long eventID = 201; ... ContentResolver cr = getContentResolver(); ContentValues values = new ContentValues(); Uri deleteUri = null; deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); int rows = getContentResolver().delete(deleteUri, null, null); Log.i(DEBUG_TAG, "Rows deleted: " + rows);
В каждой строке таблицы {@link android.provider.CalendarContract.Attendees} указан один участник или гость события. При вызове метода {@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} возвращается список участников для события с заданным {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}. Этот {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} должен соответствовать {@link android.provider.BaseColumns#_ID} определенного события.
В таблице ниже указаны
поля, доступные для записи. При вставке нового участника необходимо указать все эти поля, кроме
ATTENDEE_NAME
.
Константа | Описание |
---|---|
{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} | Идентификатор события. |
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_NAME} | Имя участника. |
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_EMAIL} | Адрес эл. почты участника. |
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_RELATIONSHIP} | Связь участника с событием. Одно из следующего:
|
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_TYPE} | Тип участника. Одно из следующего:
|
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS} | Статус посещения события участником. Одно из следующего:
|
Ниже представлен пример добавления одного участника события. Обратите внимание, что нужно в обязательном порядке указать {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}.
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);
В каждой строке таблицы {@link android.provider.CalendarContract.Reminders} указано одно напоминание о событии. При вызове метода {@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()}возвращается список напоминаний для события с заданным {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}.
В таблице ниже указаны поля, доступные для записи. При вставке нового напоминания необходимо указать все эти поля. Обратите внимание, что адаптеры синхронизации задают типы напоминаний, которые они поддерживают, в таблице {@link android.provider.CalendarContract.Calendars}. Подробные сведения см. в справке по {@link android.provider.CalendarContract.CalendarColumns#ALLOWED_REMINDERS}.
Константа | Описание |
---|---|
{@link android.provider.CalendarContract.RemindersColumns#EVENT_ID} | Идентификатор события. |
{@link android.provider.CalendarContract.RemindersColumns#MINUTES} | Время срабатывания уведомления (в минутах) до начала события. |
{@link android.provider.CalendarContract.RemindersColumns#METHOD} | Метод уведомления, заданный на сервере. Одно из следующего:
|
Ниже представлен пример добавления напоминания в событие. Напоминание срабатывает за 15 минут до начала события.
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);
В таблице {@link android.provider.CalendarContract.Instances} содержатся данные о времени начала и окончания повторений события. В каждой строке этой таблицы представлено одно повторение события. Таблица экземпляров недоступна для записи; она предоставляет только возможность запрашивать повторения событий.
В таблице ниже перечислены некоторые из полей, которые можно запросить для экземпляра. Обратите внимание, что часовой пояс задается параметрами {@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_TYPE} и {@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_INSTANCES}.
Константа | Описание |
---|---|
{@link android.provider.CalendarContract.Instances#BEGIN} | Время начала экземпляра в формате UTC (в миллисекундах). |
{@link android.provider.CalendarContract.Instances#END} | Время окончания экземпляра в формате UTC (в миллисекундах). |
{@link android.provider.CalendarContract.Instances#END_DAY} | День окончания экземпляра по юлианскому календарю относительно часового пояса приложения «Календарь». |
{@link android.provider.CalendarContract.Instances#END_MINUTE} | Минута окончания экземпляра, вычисленная от полуночи по часовому поясу приложения «Календарь». |
{@link android.provider.CalendarContract.Instances#EVENT_ID} | _ID события для этого экземпляра. |
{@link android.provider.CalendarContract.Instances#START_DAY} | День начала экземпляра по юлианскому календарю относительно часового пояса приложения «Календарь». |
{@link android.provider.CalendarContract.Instances#START_MINUTE} | Минута начала экземпляра, вычисленная от полуночи по часовому поясу приложения «Календарь». |
Чтобы запросить таблицу экземпляров, необходимо указать промежуток времени для запроса в URI. В этом примере {@link android.provider.CalendarContract.Instances} получает доступ к полю {@link android.provider.CalendarContract.EventsColumns#TITLE} посредством своей реализации интерфейса {@link android.provider.CalendarContract.EventsColumns}. Другими словами, {@link android.provider.CalendarContract.EventsColumns#TITLE} возвращается посредством обращения к базе данных, а не путем запроса таблицы {@link android.provider.CalendarContract.Instances} с необработанными данными.
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 | Описание | Дополнительные данные |
---|---|---|---|
{@link android.content.Intent#ACTION_VIEW VIEW} |
|
Открытие календаря во время, заданное параметром <ms_since_epoch> . |
Отсутствуют. |
{@link android.content.Intent#ACTION_VIEW VIEW} |
|
Просмотр события, указанного с помощью <event_id> . |
{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} |
{@link android.content.Intent#ACTION_EDIT EDIT} |
|
Редактирование события, указанного с помощью <event_id> . |
{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} |
{@link android.content.Intent#ACTION_EDIT EDIT} {@link android.content.Intent#ACTION_INSERT INSERT} |
|
Создание события. | Любые из дополнительных данных, указанных в таблице ниже. |
В таблице ниже указаны дополнительные данные намерения, которые поддерживаются поставщиком календаря.
Дополнительные данные намерения | Описание |
---|---|
{@link android.provider.CalendarContract.EventsColumns#TITLE Events.TITLE} | Название события. |
{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} | Время начала события (в миллисекундах) от эпохи. |
{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} | Время окончания события (в миллисекундах) от эпохи. |
{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY CalendarContract.EXTRA_EVENT_ALL_DAY} | Логическое значение, обозначающее, что это событие на весь день. Значение может быть
true или false . |
{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION Events.EVENT_LOCATION} | Место проведения события. |
{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION Events.DESCRIPTION} | Описание события. |
{@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL} | Адреса эл. почты приглашенных (через запятую). |
{@link android.provider.CalendarContract.EventsColumns#RRULE Events.RRULE} | Правило повторения для события. |
{@link android.provider.CalendarContract.EventsColumns#ACCESS_LEVEL Events.ACCESS_LEVEL} | Указывает на то, является ли событие общедоступным или закрытым. |
{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY Events.AVAILABILITY} | Если событие считается как занятое или как свободное время, доступное для планирования. |
В разделах ниже указан порядок использования этих намерений.
С помощью намерения {@link android.content.Intent#ACTION_INSERT INSERT} ваше приложение может отправлять задачи вставки события прямо в приложение «Календарь». Благодаря этому в файл манифеста вашего приложения не нужно включать разрешение {@link android.Manifest.permission#WRITE_CALENDAR}.
Когда пользователи работают с приложением, в котором используется такой подход, приложение отправляет их в «Календарь» для завершения добавления события. Намерение {@link android.content.Intent#ACTION_INSERT INSERT} использует дополнительные поля для предварительного указания в форме сведений о событии в приложении «Календарь». После этого пользователи могут отменить событие, отредактировать форму или сохранить событие в своем календаре.
Ниже представлен фрагмент кода, в котором на 19 января 2012 г. планируется событие, которое будет проходить с 7:30 до 8:30. Однако следует учесть некоторые моменты, касающиеся этого примера кода.
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);
Событие можно отредактировать напрямую, как описано в разделе Обновление событий. Благодаря намерению {@link android.content.Intent#ACTION_EDIT EDIT} приложение, у которого нет разрешения, может делегировать редактирование события приложению «Календарь». По завершении редактирования события в приложении «Календарь» пользователи возвращаются в исходное приложение.
Ниже представлен пример намерения, который задает новый заголовок для указанного события и позволяет пользователям редактировать событие в приложении «Календарь».
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);
Поставщик календаря позволяет использовать намерение {@link android.content.Intent#ACTION_VIEW VIEW} двумя различными способами:
Ниже представлен пример открытия приложения «Календарь» на определенной дате.
// 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);
Ниже представлен пример открытия события для его просмотра.
long eventID = 208; ... Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); Intent intent = new Intent(Intent.ACTION_VIEW) .setData(uri); startActivity(intent);
Существуют лишь незначительные различия в том, как приложение и адаптер синхронизации получают доступ к поставщику календаря.
true
.ACCOUNT_NAME
и
ACCOUNT_TYPE
.Ниже представлен метод, который можно использовать, чтобы получить URI для использования вместе с адаптером синхронизации.
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(); }
Пример реализации адаптера синхронизации (который не связан с приложением «Календарь») представлен в статье, посвященной SampleSyncAdapter.