Visão geral do provedor de agenda

O Provedor de agenda é um repositório para eventos da agenda de um usuário. A API Calendar Provider permite consultar, inserir, atualizar e excluir operações em agendas, eventos, participantes, lembretes e assim por diante.

Essa API pode ser usada por aplicativos e adaptadores de sincronização. As regras variam de acordo com o tipo de programa que faz as chamadas. Este documento se concentra principalmente no uso da API Calendar Provider como um aplicativo. Para conferir uma discussão sobre as diferenças entre os adaptadores de sincronização, consulte Adaptadores de sincronização.

Normalmente, para ler ou gravar dados da agenda, o manifesto de um aplicativo precisa incluir as permissões adequadas, descritas em Permissões do usuário. Para facilitar a execução de operações comuns, o provedor de calendário oferece um conjunto de intents, conforme descrito em Intents do Agenda. Essas intents levam os usuários ao aplicativo Agenda para inserir, visualizar e editar eventos. O usuário interage com o aplicativo Agenda e retorna ao aplicativo original. Assim, o aplicativo não precisa solicitar permissões nem fornecer uma interface do usuário para visualizar ou criar eventos.

Noções básicas

Os provedores de conteúdo armazenam dados e os disponibilizam para aplicativos. Os provedores de conteúdo oferecidos pela plataforma Android (incluindo o provedor de agenda) geralmente expõem dados como um conjunto de tabelas com base em um modelo de banco de dados relacional, em que cada linha é um registro e cada coluna são dados de um tipo e significado específico. Com a API Calendar Provider, os aplicativos e os adaptadores de sincronização podem ter acesso de leitura/gravação às tabelas do banco de dados que contêm os dados da agenda de um usuário.

Cada provedor de conteúdo expõe um URI público (agrupado como um objeto Uri) que identifica exclusivamente o conjunto de dados. Um provedor de conteúdo que controla vários conjuntos de dados (várias tabelas) expõe um URI separado para cada um. Todos os URIs de provedores começam com a string "content://". Isso identifica os dados como controlados por um provedor de conteúdo. O Provedor de Agenda define constantes para os URIs de cada uma das classes (tabelas). Esses URIs têm o formato <class>.CONTENT_URI. Por exemplo, Events.CONTENT_URI.

A imagem 1 exibe uma representação gráfica do modelo de dados do Provedor de agenda. Ela mostra as tabelas principais e os campos que as vinculam entre si.

Modelo de dados do Provedor de agenda.

Figura 1. Modelo de dados do Provedor de Agenda.

Cada usuário pode ter diversas agendas e associá-las a diferentes tipos de conta (Google Agenda, Exchange etc.).

O CalendarContract define o modelo de dados das informações relacionadas à agenda e aos eventos. Esses dados são armazenados em diversas tabelas, que são listadas a seguir.

Tabela (classe) Descrição

CalendarContract.Calendars

Essa tabela contém as informações específicas da agenda. Cada linha contém os detalhes de uma única agenda, como nome, cor, informações de sincronização e assim por diante.
CalendarContract.Events Essa tabela contém as informações específicas do evento. Cada linha dessa tabela tem as informações de um único evento, por exemplo, título, local, horário de início, horário de término etc. O evento pode ocorrer uma vez ou diversas vezes. Os participantes, lembretes e propriedades estendidas são armazenados em tabelas separadas. Cada um deles tem um EVENT_ID que faz referência ao _ID na tabela "Eventos".
CalendarContract.Instances Essa tabela contém os horários de início e término de cada ocorrência de um evento. Cada linha nessa tabela representa uma única ocorrência de evento. Para eventos únicos, há um mapeamento 1:1 de instâncias para eventos. Para eventos recorrentes, diversas linhas correspondentes a diversas ocorrências desse evento são geradas automaticamente.
CalendarContract.Attendees Essa tabela contém as informações dos participantes (convidados) do evento. Cada linha representa um único convidado de um evento. Ela especifica o tipo de convidado e a resposta de participação do convidado no evento.
CalendarContract.Reminders Essa tabela contém os dados de alerta/notificação. Cada linha representa um único alerta de um evento. Um evento pode ter vários lembretes. O número máximo de lembretes por evento é especificado em MAX_REMINDERS, que é definido pelo adaptador de sincronização que tem a agenda fornecida. Os lembretes são especificados em minutos antes do evento e têm um método que determina como o usuário será alertado.

A API Calendar Provider é projetada para ser flexível e poderosa. Ao mesmo tempo, é importante fornecer uma boa experiência ao usuário final e proteger a integridade da agenda e dos dados dela. Para isso, aqui estão algumas coisas que você deve ter em mente ao usar a API:

  • Inserir, atualizar e ver eventos da agenda. Para inserir, modificar e ler eventos diretamente do provedor de agenda, você precisa das permissões apropriadas. No entanto, se você não estiver criando um aplicativo de agenda ou um adaptador de sincronização completo, não será necessário solicitar essas permissões. Em vez disso, é possível usar intents compatíveis com o aplicativo Agenda do Android para entregar operações de leitura e gravação. Quando você usa as intents, o aplicativo envia usuários ao aplicativo Agenda para realizar a operação desejada em um formulário pré-preenchido. Depois que terminarem, eles vão retornar ao seu aplicativo. Ao projetar seu aplicativo para executar operações comuns no Agenda, você oferece aos usuários uma interface do usuário consistente e robusta. Essa é a abordagem recomendada. Para saber mais, consulte Intents do Agenda.
  • Adaptadores de sincronização. Um adaptador de sincronização sincroniza os dados da agenda no dispositivo de um usuário com outro servidor ou fonte de dados. Nas tabelas CalendarContract.Calendars e CalendarContract.Events, há colunas reservadas para os adaptadores de sincronização usarem. O provedor e os aplicativos não devem modificá-las. Na verdade, elas não são visíveis, a menos que sejam acessadas como um adaptador de sincronização. Para ver mais informações sobre adaptadores de sincronização, consulte Adaptadores de sincronização.

Permissões do usuário

Para ler os dados da agenda, um app precisa incluir a permissão READ_CALENDAR no arquivo de manifesto. Ela precisa incluir a permissão WRITE_CALENDAR para excluir, inserir ou atualizar dados da agenda:

<?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>

Tabela de agendas

A tabela CalendarContract.Calendars contém detalhes de agendas individuais. As colunas Agendas a seguir são graváveis tanto por um aplicativo quanto por um adaptador de sincronização. Para ver uma lista completa de campos compatíveis, consulte a referência do CalendarContract.Calendars.

Constante Descrição
NAME É o nome da agenda.
CALENDAR_DISPLAY_NAME É o nome dessa agenda que será exibido ao usuário.
VISIBLE É um booleano indicando se a agenda foi selecionada para ser exibida. Um valor de 0 indica que eventos associados a essa agenda não podem ser exibidos. Um valor de 1 indica que eventos associados a essa agenda precisam ser exibidos. Esse valor afeta a geração de linhas na tabela CalendarContract.Instances.
SYNC_EVENTS É um booleano indicando se a agenda precisa ser sincronizada e ter os eventos armazenados no dispositivo. Um valor de 0 indica a não sincronização dessa agenda nem o armazenamento dos eventos no dispositivo. Um valor de 1 indica a sincronização dos eventos dessa agenda e o armazenamento dos eventos no dispositivo.

Incluir um tipo de conta para todas as operações

Se você consultar em um Calendars.ACCOUNT_NAME, também vai precisar incluir Calendars.ACCOUNT_TYPE na seleção. Isso ocorre porque uma determinada conta só é considerada única devido aos ACCOUNT_NAME e ao ACCOUNT_TYPE. A ACCOUNT_TYPE é a string correspondente ao autenticador de conta que foi usado quando a conta foi registrada com o AccountManager. Há também um tipo especial de conta chamado ACCOUNT_TYPE_LOCAL para agendas não associadas a uma conta de dispositivo. ACCOUNT_TYPE_LOCAL contas não são sincronizadas.

Consultar a agenda

Este é um exemplo que mostra como conseguir as agendas de um determinado usuário. Para simplificar, neste exemplo, a operação de consulta é mostrada na linha de execução da interface do usuário ("linha de execução principal"). Na prática, isso precisa ser feito em uma linha de execução assíncrona, em vez de na linha de execução principal. Para mais informações, consulte Carregadores. Se você não estiver apenas lendo dados, mas modificando-os, consulte 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

Java

// 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;

Na próxima parte do exemplo, você construirá a consulta. A seleção especifica os critérios da consulta. Neste exemplo, a consulta está procurando agendas que tenham ACCOUNT_NAME "hera@example.com", ACCOUNT_TYPE "com.example" e OWNER_ACCOUNT "hera@example.com". Se você quiser ver todas as agendas visualizadas por um usuário, e não apenas as agendas dele, omita o OWNER_ACCOUNT. A consulta retorna um objeto Cursor que pode ser usado para percorrer o conjunto de resultados retornado pela consulta do banco de dados. Para saber mais sobre o uso de consultas em provedores de conteúdo, consulte Provedores de conteúdo.

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)

Java

// 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);

Essa próxima seção usa o cursor para avançar pelo conjunto de resultados. Ele usa as constantes que foram configuradas no início do exemplo para retornar os valores de cada campo.

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...
}

Java

// 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...

   ...
}

Modificar uma agenda

Para atualizar uma agenda, forneça o _ID da agenda como um ID anexado ao URI (withAppendedId()) ou como o primeiro item de seleção. A seleção precisa começar com "_id=?", e o primeiro selectionArg precisa ser o _ID da agenda. Também é possível realizar atualizações com a codificação no URI. Este exemplo muda o nome de exibição de uma agenda usando a abordagem (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")

Java

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);

Inserir uma agenda

As agendas são projetadas para serem gerenciadas principalmente por um adaptador de sincronização. Portanto, insira novas agendas apenas como um adaptador de sincronização. Na maioria das vezes, os aplicativos só podem fazer mudanças superficiais nas agendas, como mudar o nome de exibição. Caso um aplicativo precise criar uma agenda local, é possível fazer isso realizando a inserção da agenda como um adaptador de sincronização usando um ACCOUNT_TYPE de ACCOUNT_TYPE_LOCAL. ACCOUNT_TYPE_LOCAL é um tipo de conta especial para agendas que não estão associadas a uma conta de dispositivo. As agendas desse tipo não são sincronizadas com um servidor. Para ver uma discussão sobre adaptadores de sincronização, consulte Adaptadores de sincronização.

Tabela de eventos

A tabela CalendarContract.Events contém detalhes de eventos individuais. Para adicionar, atualizar ou excluir eventos, um aplicativo precisa incluir a permissão WRITE_CALENDAR no arquivo de manifesto.

As colunas "Eventos" abaixo são graváveis tanto por um aplicativo quanto por um adaptador de sincronização. Para ver uma lista completa de campos compatíveis, consulte a referência CalendarContract.Events.

Constante Descrição
CALENDAR_ID O _ID da agenda a que o evento pertence.
ORGANIZER É o e-mail do organizador (proprietário) do evento.
TITLE É o título do evento.
EVENT_LOCATION Indica onde o evento acontece.
DESCRIPTION É a descrição do evento.
DTSTART É o horário de início do evento em milissegundos em UTC desde a época.
DTEND É o horário de término do evento em milissegundos em UTC desde a época.
EVENT_TIMEZONE É o fuso horário do evento.
EVENT_END_TIMEZONE É o fuso horário do horário de término do evento.
DURATION A duração do evento no formato RFC5545. Por exemplo, o valor "PT1H" indica que o evento precisa durar uma hora, e o valor "P2W" indica uma duração de duas semanas.
ALL_DAY Um valor de 1 indica que esse evento ocupa o dia inteiro, conforme definido pelo fuso horário local. Um valor de 0 indica que é um evento regular que pode começar e terminar a qualquer momento durante um dia.
RRULE É a regra de recorrência do formato do evento. Por exemplo, "FREQ=WEEKLY;COUNT=10;WKST=SU". Confira mais exemplos aqui.
RDATE Mostra as datas de recorrência do evento. Normalmente, usa-se RDATE com RRULE para definir um conjunto agregado de ocorrências repetidas. Para mais discussão, consulte a especificação RFC5545 (link em inglês).
AVAILABILITY Se esse evento é considerado como tempo ocupado ou como tempo livre que pode ser reagendado.
GUESTS_CAN_MODIFY Indica se os convidados podem modificar o evento.
GUESTS_CAN_INVITE_OTHERS Define se os convidados podem convidar outras pessoas.
GUESTS_CAN_SEE_GUESTS Indica se os convidados podem ver a lista de participantes.

Adicionar eventos

Quando seu app insere um novo evento, recomendamos usar uma intent INSERT, conforme descrito em Como usar uma intent para inserir um evento. No entanto, se necessário, é possível inserir eventos diretamente. Veja nesta seção como fazer isso.

Veja as regras para inserção de um novo evento:

Veja um exemplo de inserção de um evento: Para simplificar, isso está sendo realizado na linha de execução de IU. Na prática, inserções e atualizações precisam ser feitas em uma linha de execução assíncrona para mover a ação para uma linha de execução em segundo plano. Para mais informações, consulte 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
//
//

Java

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
//
//

Observação:veja como este exemplo captura o ID do evento após a criação dele. Esse é o modo mais fácil de conseguir um código de evento. Muitas vezes, o ID do evento é necessário para realizar outras operações de agenda, por exemplo, para adicionar participantes ou lembretes a um evento.

Atualizar eventos

Quando seu app quiser permitir que o usuário edite um evento, recomendamos usar uma intent EDIT, conforme descrito em Como usar uma intent para editar um evento. Contudo, caso necessário, será possível editar eventos diretamente. Para realizar uma atualização de um evento, forneça o _ID do evento como um ID anexado ao URI (withAppendedId()) ou como o primeiro item de seleção. A seleção precisa começar com "_id=?", e o primeiro selectionArg precisa ser o _ID do evento. Também é possível fazer atualizações usando uma seleção sem ID. Veja um exemplo de atualização de um evento. Ele muda o título do evento usando a abordagem 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")

Java

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);

Excluir eventos

É possível excluir um evento pelo _ID como um ID anexado no URI ou usando a seleção padrão. Se você usar um ID anexado, também não vai ser possível fazer uma seleção. Existem duas versões de exclusão: como um aplicativo e como um adaptador de sincronização. Uma exclusão de aplicativo define a coluna deleted como 1. Essa sinalização que informa ao adaptador de sincronização que a linha foi excluída e que essa exclusão precisa ser propagada para o servidor. A exclusão por um adaptador de sincronização remove o evento do banco de dados com todos os dados associados. Confira um exemplo de um aplicativo excluindo um evento pelo _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")

Java

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);

Tabela de participantes

Cada linha da tabela CalendarContract.Attendees representa um único participante ou convidado de um evento. Chamar query() retorna uma lista de participantes para o evento com o EVENT_ID fornecido. Esse EVENT_ID precisa corresponder ao _ID de um evento específico.

A tabela a seguir lista os campos graváveis. Ao inserir um novo participante, inclua todos eles, exceto ATTENDEE_NAME.

Constante Descrição
EVENT_ID É o código do evento.
ATTENDEE_NAME É o nome do participante.
ATTENDEE_EMAIL É o endereço de e-mail do participante.
ATTENDEE_RELATIONSHIP

É a relação do participante com o evento. Pode ser:

ATTENDEE_TYPE

Indica o tipo de participante. Pode ser:

ATTENDEE_STATUS

É o status de participação do participante. Pode ser:

Adicionar participantes

A seguir, há um exemplo que adiciona um único participante a um evento. O EVENT_ID é obrigatório:

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)

Java

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);

Tabela de lembretes

Cada linha da tabela CalendarContract.Reminders representa um único lembrete de um evento. Chamar query() retorna uma lista de lembretes para o evento com o EVENT_ID fornecido.

A tabela a seguir relaciona os campos graváveis de lembretes. Todos eles precisam ser incluídos ao inserir um novo lembrete. Os adaptadores de sincronização especificam os tipos de lembretes compatíveis na tabela CalendarContract.Calendars. Consulte ALLOWED_REMINDERS para mais detalhes.

Constante Descrição
EVENT_ID É o código do evento.
MINUTES Indica os minutos antes do evento para o acionamento do lembrete.
METHOD

É o método de alarme, como definido no servidor. Pode ser:

Adicionar lembretes

Este exemplo adiciona um lembrete para um evento. O lembrete é acionado 15 minutos antes do evento.

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)

Java

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);

Tabela de instâncias

A tabela CalendarContract.Instances contém os horários de início e término das ocorrências de um evento. Cada linha nessa tabela representa uma única ocorrência de evento. A tabela de instâncias não é gravável e fornece apenas uma maneira de consultar ocorrências de eventos.

A tabela a seguir relaciona alguns dos campos passíveis de consulta de uma instância. Observe que o fuso horário é definido por KEY_TIMEZONE_TYPE e KEY_TIMEZONE_INSTANCES.

Constante Descrição
BEGIN É o horário de início da instância, em milissegundos UTC.
END É o horário de término da instância, em milissegundos UTC.
END_DAY O dia final juliano da instância, relativo ao fuso horário do Agenda.
END_MINUTE O minuto final da instância medido a partir de meia-noite no fuso horário do Agenda.
EVENT_ID O _ID do evento para esta instância.
START_DAY O dia de início juliano da instância, relativo ao fuso horário do Agenda.
START_MINUTE O minuto inicial da instância medido a partir de meia-noite, em relação ao fuso horário do Google Agenda.

Consultar a tabela de instâncias

Para consultar a tabela de instâncias, especifique um intervalo de tempo para a consulta no URI. Neste exemplo, CalendarContract.Instances tem acesso ao campo TITLE por meio da implementação da interface CalendarContract.EventsColumns. Em outras palavras, TITLE é retornado por uma visualização do banco de dados, e não pela consulta da tabela CalendarContract.Instances bruta.

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)}")
}

Java

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()));
    }
 }

Intents do Agenda

O aplicativo não precisa de permissões para ler e gravar dados da agenda. Em vez disso, ele pode usar intents compatíveis com o aplicativo Agenda do Android para entregar operações de leitura e gravação. A tabela a seguir lista os intents compatíveis com o Provedor de Agenda.

Ação URI Descrição Extras

VIEW

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

Também é possível fazer referência ao URI com CalendarContract.CONTENT_URI. Para conferir um exemplo do uso dessa intent, consulte Como usar intents para exibir dados de agenda.
Abre a agenda no horário especificado por <ms_since_epoch>. Nenhum.

VIEW

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

Também é possível fazer referência ao URI com Events.CONTENT_URI. Para conferir um exemplo do uso dessa intent, consulte Como usar intents para exibir dados de agenda.
Visualizar o evento especificado por <event_id>. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

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

Também é possível fazer referência ao URI com Events.CONTENT_URI. Para ver um exemplo do uso dessa intent, consulte Como usar uma intent para editar um evento.
Edite o evento especificado por <event_id>. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

INSERT

content://com.android.calendar/events

Também é possível fazer referência ao URI com Events.CONTENT_URI. Para ver um exemplo de uso dessa intent, consulte Como usar uma intent para inserir um evento.
Crie um evento. Qualquer um dos extras listados na tabela abaixo.

A tabela a seguir lista os extras de intent compatíveis com o Provedor de Agenda:

Extra de intent Descrição
Events.TITLE É o nome do evento.
CalendarContract.EXTRA_EVENT_BEGIN_TIME É o horário de início do evento em milissegundos a partir da época.
CalendarContract.EXTRA_EVENT_END_TIME É o horário de término do evento em milissegundos a partir da época.
CalendarContract.EXTRA_EVENT_ALL_DAY É um booleano que indica que um evento acontece o dia inteiro. O valor pode ser true ou false.
Events.EVENT_LOCATION Indica o local do evento.
Events.DESCRIPTION É a descrição do evento.
Intent.EXTRA_EMAIL São os endereços de e-mail das pessoas que serão convidadas em forma de lista, com termos separados por vírgula.
Events.RRULE É a regra de recorrência do evento.
Events.ACCESS_LEVEL Indica se o evento é privado ou público.
Events.AVAILABILITY Indica se esse evento é considerado como tempo ocupado ou como tempo livre que poderá ser reagendado.

As seções a seguir descrevem como usar estes intents.

Usar um intent para inserir um evento

O uso da intent INSERT permite que seu aplicativo entregue a tarefa de inserção de eventos ao próprio Agenda. Com essa abordagem, seu aplicativo não precisa incluir a permissão WRITE_CALENDAR no arquivo de manifesto.

Quando os usuários executam um aplicativo que usa essa abordagem, ele os direciona ao Google Agenda para terminar de adicionar o evento. A intent INSERT usa campos extras para preencher previamente um formulário com os detalhes do evento no Agenda. Os usuários podem cancelar o evento, editar o formulário conforme necessário ou salvar o evento nas agendas.

Este é um snippet de código que programa um evento em 19 de janeiro de 2012, que é executado das 7h30 às 8h30. Observe o seguinte sobre este snippet de código:

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)

Java

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);

Usar um intent para editar um evento

É possível atualizar um evento diretamente, conforme descrito em Como atualizar eventos. No entanto, o uso da intent EDIT permite que um app que não tenha permissão entregue a edição de eventos ao app Agenda. Quando os usuários terminam de editar o evento no Agenda, eles retornam ao aplicativo original.

Este é um exemplo de uma intent que define um novo título para um evento especificado e permite que os usuários editem o evento no Agenda.

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)

Java

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);

Usar intents para exibir dados de agenda

O Provedor de Agenda oferece duas maneiras de usar a intent VIEW:

  • Para abrir o Agenda em uma data específica.
  • Para exibir um evento.

Veja um exemplo que mostra como abrir o Agenda em uma data específica:

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)

Java

// 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);

Veja um exemplo que mostra como abrir um evento para exibição:

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)

Java

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

Adaptadores de sincronização

Há pequenas diferenças na forma como um aplicativo e um adaptador de sincronização acessam o Provedor de agenda:

  • Um adaptador de sincronização precisa especificar que é um adaptador de sincronização definindo CALLER_IS_SYNCADAPTER como true.
  • Um adaptador de sincronização precisa fornecer uma ACCOUNT_NAME e uma ACCOUNT_TYPE como parâmetros de consulta no URI.
  • Os adaptadores de sincronização têm acesso de gravação a mais colunas do que um aplicativo ou widget. Por exemplo, um app só pode modificar algumas características de uma agenda, como nome, nome de exibição, configuração de visibilidade e se a agenda está sincronizada. Por comparação, um adaptador de sincronização pode acessar não apenas essas colunas, mas muitas outras, como cor da agenda, fuso horário, nível de acesso, localização e assim por diante. No entanto, um adaptador de sincronização é restrito ao ACCOUNT_NAME e ao ACCOUNT_TYPE especificados.

Veja um método auxiliar que pode ser usado para retornar um URI para uso com um adaptador de sincronização:

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();
 }