O provedor de agenda é um repositório para os eventos da agenda de um usuário. A API Calendar Provider permite realizar operações de consulta, inserção, atualização e exclusão em itens como agendas, eventos, participantes e lembretes.
A API Calendar Provider pode ser usada por aplicativos e adaptadores de sincronização. As regras variam de acordo com o tipo de programa que está fazendo as chamadas. Este documento se concentra principalmente no uso da API Calendar Provider como um aplicativo. Para uma discussão sobre como os adaptadores de sincronização são diferentes, 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 as operações comuns, o provedor de agenda oferece um conjunto de intents, conforme descrito em Intents de 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, em seguida, retorna ao aplicativo original. Assim, seu 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) normalmente 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 é um dado de um tipo e significado específicos. Com a API Calendar Provider, os aplicativos e 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 (encapsulado 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 sendo 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 Figura 1 mostra uma representação gráfica do modelo de dados do Provedor de Agenda. Ele mostra as tabelas principais e os campos que as vinculam umas às outras.
Um usuário pode ter várias agendas, e agendas diferentes podem ser associadas a diferentes tipos de contas (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 várias tabelas, listadas a seguir.
| Tabela (classe) | Descrição |
|---|---|
| Essa tabela contém as informações específicas do calendário. Cada linha dessa tabela contém os detalhes de uma única agenda, como nome, cor e informações de sincronização. | |
CalendarContract.Events |
Essa tabela contém as
informações específicas do evento. Cada linha nessa tabela tem as informações de um único evento, como título, local, horário de início e de término. O evento pode ocorrer uma vez ou se repetir várias vezes. Os participantes,
os lembretes e as propriedades estendidas são armazenados em tabelas separadas.
Cada um tem um EVENT_ID
que faz referência ao _ID na tabela de 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 de 1:1 de instâncias para eventos. Para eventos recorrentes, várias linhas são geradas automaticamente, correspondendo a várias ocorrências desse evento. |
CalendarContract.Attendees |
Esta tabela contém as informações do convidado do evento. Cada linha representa um único convidado de um evento. Ele especifica o tipo de convidado e a resposta de presença do convidado para o evento. |
CalendarContract.Reminders |
Essa tabela contém os dados de alerta/notificação. Cada linha representa um único alerta para 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
é proprietário da agenda em questão. 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 foi projetada para ser flexível e eficiente. Ao mesmo tempo, é importante oferecer uma boa experiência ao usuário final e proteger a integridade da agenda e dos dados dela. Para isso, veja algumas coisas que você precisa considerar ao usar a API:
- Inserir, atualizar e visualizar eventos da agenda. Para inserir, modificar e ler eventos diretamente do provedor de agenda, você precisa das permissões adequadas. No entanto, se você não estiver criando um aplicativo de agenda completo ou um adaptador de sincronização, não será necessário solicitar essas permissões. Em vez disso, use intents compatíveis com o app Agenda do Android para transferir operações de leitura e gravação para esse app. Quando você usa as intents, seu aplicativo envia os usuários ao aplicativo Agenda para realizar a operação escolhida em um formulário preenchido automaticamente. Depois que eles terminarem, serão retornados ao seu aplicativo. Ao projetar seu aplicativo para realizar operações comuns usando o Agenda, você oferece aos usuários uma interface do usuário consistente e robusta. Essa é a abordagem recomendada. Para mais informações, consulte Intents da 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.CalendarseCalendarContract.Events, há colunas reservadas para uso dos adaptadores de sincronização. O provedor e os aplicativos não devem modificá-los. Na verdade, eles não são visíveis, a menos que sejam acessados como um adaptador de sincronização. Para mais informações sobre adaptadores de sincronização, consulte Adaptadores de sincronização.
Permissões do usuário
Para ler dados da agenda, um aplicativo precisa incluir a permissão READ_CALENDAR no arquivo de manifesto. Ele
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 seguintes
colunas de Calendars podem ser gravadas por um aplicativo e por um adaptador de sincronização.
Para uma lista completa de campos compatíveis, consulte a
referência de CalendarContract.Calendars.
| Constante | Descrição |
|---|---|
NAME |
O nome da agenda. |
CALENDAR_DISPLAY_NAME |
O nome da agenda que aparece para o usuário. |
VISIBLE |
Um booleano que indica se a agenda está selecionada para ser exibida. Um
valor de 0 indica que os eventos associados a essa agenda não devem ser
mostrados. O valor 1 indica que os eventos associados a essa agenda precisam ser mostrados. Esse valor afeta a geração de linhas na tabela CalendarContract.Instances. |
SYNC_EVENTS |
Um booleano que indica se a agenda precisa ser sincronizada e ter os eventos armazenados no dispositivo. O valor 0 indica que essa agenda não deve ser sincronizada nem armazenar os eventos no dispositivo. O valor 1 indica que os eventos dessa agenda devem ser sincronizados e armazenados no dispositivo. |
Incluir um tipo de conta para todas as operações
Se você consultar um Calendars.ACCOUNT_NAME, também precisará incluir
Calendars.ACCOUNT_TYPE
na seleção. Isso ocorre porque uma determinada conta só é considerada exclusiva quando tem ACCOUNT_NAME e ACCOUNT_TYPE. O ACCOUNT_TYPE é a string correspondente ao
autenticador de conta que foi usado quando a conta foi registrada no
AccountManager. Há também um tipo especial de conta
chamado ACCOUNT_TYPE_LOCAL para
agendas não associadas a uma conta de dispositivo.
As contas do ACCOUNT_TYPE_LOCAL não são
sincronizadas.
Consultar uma agenda
Veja um exemplo que mostra como acessar as agendas de um usuário específico. 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 também 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ê vai criar sua consulta. A seleção
especifica os critérios da consulta. Neste exemplo, a consulta procura
agendas que tenham o ACCOUNT_NAME
"hera@example.com", o ACCOUNT_TYPE
"com.example" e o OWNER_ACCOUNT
"hera@example.com". Se você quiser ver todas as agendas que um usuário
visualizou, não apenas as que ele possui, 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 mais informações 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);
A próxima seção usa o cursor para percorrer o 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 dela 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 calendário.
Também é possível fazer atualizações codificando o ID no URI. Este exemplo altera 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, você só deve inserir novas agendas como um adaptador de sincronização. Na maioria das vezes,
os aplicativos só podem fazer mudanças superficiais nas agendas, como alterar o nome de exibição. Se
um aplicativo precisar criar uma agenda local, ele poderá 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 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 seguintes colunas de eventos podem ser gravadas por um aplicativo e um adaptador de
sincronização. Para uma lista completa de campos compatíveis, consulte a referência de CalendarContract.Events.
| Constante | Descrição |
|---|---|
CALENDAR_ID |
O _ID da agenda a que o evento pertence. |
ORGANIZER |
E-mail do organizador (proprietário) do evento. |
TITLE |
O título do evento. |
EVENT_LOCATION |
Onde o evento ocorre. |
DESCRIPTION |
A descrição do evento. |
DTSTART |
O horário de início do evento em milissegundos UTC desde o início da era Unix. |
DTEND |
O horário em que o evento termina em milissegundos UTC desde o início da era Unix. |
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, um valor de "PT1H" indica que o evento
deve durar uma hora, e um valor de "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. O valor 0 indica que é um evento regular que pode começar e terminar a qualquer momento durante o dia. |
RRULE |
A regra de recorrência para o formato do evento. Por exemplo, "FREQ=WEEKLY;COUNT=10;WKST=SU". Para
mais exemplos, consulte a especificação RFC5545. |
RDATE |
As datas de recorrência do evento.
Normalmente, você usa RDATE
em conjunto com RRULE
para definir um conjunto agregado de
ocorrências repetidas. Para mais informações, consulte a especificação RFC5545. |
AVAILABILITY |
Se esse evento conta como horário ocupado ou se é um horário livre que pode ser agendado. |
GUESTS_CAN_MODIFY |
Se os convidados podem modificar o evento. |
GUESTS_CAN_INVITE_OTHERS |
Se os convidados podem convidar outras pessoas. |
GUESTS_CAN_SEE_GUESTS |
Se os convidados podem ver a lista de participantes. |
Adicionar eventos
Quando o aplicativo insere um novo evento, recomendamos que você use uma
INSERT Intent, conforme descrito em Como usar uma intent para inserir um evento. No entanto, se
precisar, você pode inserir eventos diretamente. Nesta seção, descrevemos como fazer
isso.
Confira as regras para inserir um novo evento:
- É necessário incluir
CALENDAR_IDeDTSTART. - É necessário incluir um
EVENT_TIMEZONE. Para ver uma lista dos IDs de fuso horário instalados no sistema, usegetAvailableIDs(). Essa regra não se aplica se você estiver inserindo um evento usando a intentINSERT, descrita em Como usar uma intent para inserir um evento. Nesse cenário, um fuso horário padrão é fornecido. - Para eventos não recorrentes, inclua
DTEND. - Para eventos recorrentes, é necessário incluir um
DURATIONalém deRRULEouRDATE. Essa regra não se aplica se você estiver inserindo um evento usando a intentINSERT, descrita em Como usar uma intent para inserir um evento. Nesse cenário, é possível usar umRRULEem conjunto comDTSTARTeDTEND, e o aplicativo Agenda o converte em uma duração automaticamente.
Veja um exemplo de inserção de um evento. Isso está sendo feito na linha de execução da interface
para simplificar. Na prática, as 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 depois que ele é criado. Essa é a maneira mais fácil de conseguir um ID de evento. Muitas vezes, você precisa do ID do evento para realizar outras operações da agenda, como adicionar convidados ou lembretes a um evento.
Eventos de atualização
Quando o aplicativo quiser permitir que o usuário edite um evento, recomendamos
que você use uma intent EDIT, conforme
descrito em Como usar uma intent para editar um evento.
No entanto, se necessário, você pode editar eventos diretamente. Para atualizar 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, não será possível fazer uma seleção.
Há duas versões de exclusão: como um aplicativo e como um adaptador de sincronização. A exclusão de um aplicativo define a coluna deleted como 1. Essa flag informa
ao adaptador de sincronização que a linha foi excluída e que essa exclusão precisa ser
propagada para o servidor. Uma exclusão do adaptador de sincronização remove o evento do
banco de dados com todos os dados associados. Veja um exemplo de aplicativo
que exclui um evento usando o _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 convidados 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 convidado, é preciso incluir todos eles,
exceto ATTENDEE_NAME.
| Constante | Descrição |
|---|---|
EVENT_ID |
O ID do evento. |
ATTENDEE_NAME |
O nome do convidado. |
ATTENDEE_EMAIL |
O endereço de e-mail do convidado. |
ATTENDEE_RELATIONSHIP |
A relação do convidado com o evento. Uma destas: |
ATTENDEE_TYPE |
O tipo de convidado. Uma destas: |
ATTENDEE_STATUS |
O status de presença do convidado. Uma destas: |
Adicionar convidados
Veja um exemplo que adiciona um único convidado a um evento. Observe que 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 lista os campos graváveis para 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 ID do evento. |
MINUTES |
Os minutos antes do evento em que o lembrete deve ser acionado. |
METHOD |
O método de alarme, conforme definido no servidor. Uma destas: |
Adicionar lembretes
Este exemplo adiciona um lembrete a 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 só
fornece uma maneira de consultar ocorrências de eventos.
A tabela a seguir lista alguns dos campos que podem ser consultados em uma instância. 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, em relação ao fuso horário da agenda. |
END_MINUTE |
O minuto final da instância medido a partir da meia-noite no fuso horário do Google Agenda. |
EVENT_ID |
O _ID do evento para essa instância. |
START_DAY |
O dia de início juliano da instância, em relação ao fuso horário da agenda. |
START_MINUTE |
O minuto de início da instância medido a partir da meia-noite, em relação ao fuso horário da Agenda. |
Consultar a tabela de instâncias
Para consultar a tabela Instances, é preciso especificar um intervalo de tempo para a consulta
no URI. Neste exemplo, CalendarContract.Instances
recebe acesso ao campo TITLE pela
implementação da interface CalendarContract.EventsColumns.
Em outras palavras, TITLE é retornado por uma
visualização de banco de dados, 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 de agenda
Seu 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 app Agenda do Android para transferir operações de leitura e gravação para esse app. A tabela a seguir lista as intents compatíveis com o provedor de agenda:
| Ação | URI | Descrição | Extras |
|---|---|---|---|
VIEW |
CalendarContract.CONTENT_URI.
Para ver um exemplo de como usar essa intent, consulte Como usar intents para visualizar dados da agenda.
|
Abre a agenda no horário especificado por <ms_since_epoch>. |
Nenhum. |
Events.CONTENT_URI.
Para ver um exemplo de como usar essa intent, consulte Como usar intents para visualizar dados da agenda.
|
Ver o evento especificado por <event_id>. |
CalendarContract.EXTRA_EVENT_BEGIN_TIMECalendarContract.EXTRA_EVENT_END_TIME |
|
EDIT |
Events.CONTENT_URI.
Para ver um exemplo de como usar essa intent, consulte Como usar uma intent para editar um evento.
|
Edite o evento especificado por <event_id>. |
CalendarContract.EXTRA_EVENT_BEGIN_TIMECalendarContract.EXTRA_EVENT_END_TIME |
EDIT INSERT |
Events.CONTENT_URI.
Para ver um exemplo de como usar essa intent, consulte Como usar uma intent para inserir um evento.
|
Crie um evento. | Qualquer um dos extras listados na tabela a seguir. |
A tabela a seguir lista os extras de intent compatíveis com o provedor de agenda:
| Intent Extra | Descrição |
|---|---|
Events.TITLE |
Nome do evento. |
CalendarContract.EXTRA_EVENT_BEGIN_TIME |
Horário de início do evento em milissegundos desde a época. |
CalendarContract.EXTRA_EVENT_END_TIME |
Horário de término do evento em milissegundos desde o início. |
CalendarContract.EXTRA_EVENT_ALL_DAY |
Um booleano que indica que um evento dura o dia todo. O valor pode ser
true ou false. |
Events.EVENT_LOCATION |
Localização do evento. |
Events.DESCRIPTION |
Descrição do evento. |
Intent.EXTRA_EMAIL |
Endereços de e-mail das pessoas que serão convidadas como uma lista separada por vírgulas. |
Events.RRULE |
A regra de recorrência do evento. |
Events.ACCESS_LEVEL |
Se o evento é particular ou público. |
Events.AVAILABILITY |
Se este evento conta como horário ocupado ou se é um horário livre que pode ser agendado. |
As seções a seguir descrevem como usar essas intents.
Usar uma intent para inserir um evento
O uso da intent INSERT
permite que o aplicativo transfira a tarefa de inserção de eventos para a própria Agenda.
Com essa abordagem, o aplicativo não precisa nem ter a permissão WRITE_CALENDAR incluída no arquivo de manifesto.
Quando os usuários executam um aplicativo que usa essa abordagem, o aplicativo os envia
para o Agenda para concluir a adição do evento. A intent INSERT usa campos extras para
pré-preencher um formulário com os detalhes do evento na agenda. Os usuários podem
cancelar o evento, editar o formulário conforme necessário ou salvar o evento nas
agendas.
Confira um snippet de código que programa um evento para 19 de janeiro de 2012, das 7h30 às 8h30. Observe o seguinte sobre esse snippet de código:
- Ele especifica
Events.CONTENT_URIcomo o URI. - Ele usa os campos extras
CalendarContract.EXTRA_EVENT_BEGIN_TIMEeCalendarContract.EXTRA_EVENT_END_TIMEpara pré-preencher o formulário com o horário do evento. Os valores desses horários precisam estar em milissegundos UTC desde a época. - Ele usa o campo extra
Intent.EXTRA_EMAILpara fornecer uma lista separada por vírgulas de convidados, especificados por endereço de e-mail.
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 uma 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 aplicativo que
não tem permissão transfira a edição de eventos para o app Agenda.
Quando os usuários terminam de editar o evento no Agenda, eles retornam ao
aplicativo original.
Veja um exemplo de intent que define um novo título para um evento específico e permite que os usuários o editem 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 ver dados da agenda
O provedor de agenda oferece duas maneiras diferentes de usar a intent VIEW:
- Para abrir o Google Agenda em uma data específica.
- Para visualizar um evento.
Veja um exemplo de como abrir a 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 de como abrir um evento para visualizaçã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á apenas 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_SYNCADAPTERcomotrue. - Um adaptador de sincronização precisa fornecer um
ACCOUNT_NAMEe umACCOUNT_TYPEcomo parâmetros de consulta no URI. - Um adaptador de sincronização tem acesso de gravação a mais colunas do que um aplicativo ou widget.
Por exemplo, um aplicativo só pode modificar algumas características de uma agenda,
como o nome, o nome de exibição, a configuração de visibilidade e se a agenda está
sincronizada. Em 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 e local.
No entanto, um adaptador de sincronização é restrito ao
ACCOUNT_NAMEe aoACCOUNT_TYPEque ele especificou.
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(); }