O Provedor de agenda é um repositório para os eventos da agenda de um usuário. O 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 realiza as chamadas. Este documento se concentra principalmente no uso da API Calendar Provider como um aplicativo. Para uma discussão sobre as diferenças entre adaptadores de sincronização, 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 realização de operações comuns, o Provedor de agenda oferece um conjunto de intents, conforme descrito em Intents de agenda. Esses intents levam os usuários ao aplicativo Agenda para inserir, exibir e editar eventos. O usuário interage com o aplicativo Agenda e, em seguida, retorna ao aplicativo original. Assim, o aplicativo não precisa solicitar permissões, nem a interface do usuário para visualização ou criação de 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 uma de banco de dados relacional, em que cada linha é um registro e cada coluna são dados de um tipo e significado específicos. Por meio da 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 armazenam dados da agenda do 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. Tudo
Os URIs dos provedores começam com a string "content://". Isso
identifica os dados como controlados por um provedor de conteúdo. Agenda
O provedor 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 tabelas principais e os campos que as vinculam entre si.
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 de informações relacionadas a eventos e agendas. Esses dados são armazenados em diversas tabelas, que são listadas a seguir.
Tabela (classe) | Descrição |
---|---|
Essa tabela contém as informações específicas da agenda. Cada linha nessa tabela contém os detalhes de uma única agenda, como nome, cor, informações de sincronização etc. | |
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, por exemplo, título, local, horário de início e término etc. O evento pode ocorrer uma vez ou diversas vezes. Participantes:
lembretes e propriedades estendidas são armazenados em tabelas separadas.
Cada um deles tem um EVENT_ID
que referencia o _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 do evento. Para eventos de ocorrência única, há um mapeamento 1:1 de instâncias para eventos. Para eventos recorrentes, diversas linhas correspondentes a diversas ocorrências daquele 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 quanto à 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
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
detém a agenda em questão. Os lembretes são especificados em minutos antes do evento
e têm um método que determina a forma de alertar o usuário. |
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 seus dados. Para isso, aqui estão algumas coisas que você deve ter em mente 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 apropriadas. No entanto, se o aplicativo em criação não for um aplicativo de agenda totalmente desenvolvido nem um adaptador de sincronização, 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 a esse aplicativo. Ao usar os intents, o aplicativo envia usuários ao aplicativo Agenda para realizar a operação desejada em um formulário pré-preenchido. Após a conclusão, eles são levados de volta ao aplicativo. Ao projetar seu aplicativo para realizar operações comuns pelo Agenda, você fornece aos usuários uma interface do usuário consistente e robusta. Essa é a abordagem recomendada. Para mais informações, consulte Agenda Intents.
- Adaptadores de sincronização. Os adaptadores de sincronização sincronizam os dados da agenda
no dispositivo de um usuário com outro servidor ou fonte de dados. Nas tabelas
CalendarContract.Calendars
eCalendarContract.Events
, há colunas reservadas para os adaptadores de sincronização. O provedor e os aplicativos não devem modificá-las. Na verdade, elas não são ficam 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, o 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 colunas
Agendas a seguir são graváveis tanto por um aplicativo quanto por um adaptador de sincronização.
Para uma lista completa dos campos permitidos, 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 devem ser
exibidos. Um valor de 1 indica que os eventos associados a essa agenda devem
ser mostrados. Esse valor afeta a geração de linhas na tabela CalendarContract.Instances . |
SYNC_EVENTS |
Um booleano que indica se a agenda deve ser sincronizada e ter os eventos armazenados no dispositivo. Um valor de 0 indica a não sincronização dessa agenda e o não armazenamento dos eventos no dispositivo. O valor 1 indica a sincronização dos eventos desta agenda e armazenar os eventos 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ó é considerado exclusivo devido ao ACCOUNT_NAME
e ao
ACCOUNT_TYPE
. ACCOUNT_TYPE
é a string correspondente ao
autenticador da 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 do dispositivo.
ACCOUNT_TYPE_LOCAL
contas não recebem
sincronizado.
Consultar a agenda
Este é um exemplo que mostra como obter as agendas que pertencem a uma
usuário. Para simplificar o exemplo, a operação de consulta é exibida no
encadeamento da interface do usuário ("encadeamento principal"). Na prática, isso deve ser feito de maneira assíncrona,
em vez da principal. Para mais informações, consulte
Carregadores. Se você não é apenas
ler dados, mas modificá-los, 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 procura
agendas com o ACCOUNT_NAME
"hera@example.com", a ACCOUNT_TYPE
"com.example" e o OWNER_ACCOUNT
"hera@exemplo.com". Se você quiser ver todas as agendas visualizadas por um usuário, e não só os que ele tem, omita 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);
Essa próxima seção usa o cursor para avançar pelo conjunto de resultados. Ele usa as constantes definidas 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, é possível fornecer o _ID
da agenda como um ID anexado ao
URI
(withAppendedId()
)
ou como o primeiro item de seleção. A seleção
deve começar com "_id=?"
, e o primeiro
selectionArg
deve 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, para que você
só devem inserir novas agendas como um adaptador de sincronização. Na maioria das vezes,
os aplicativos só podem efetuar mudanças superficiais em agendas, como mudar o nome de exibição. Se
um aplicativo precisa criar uma agenda local, ele pode 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 são
associados a uma conta de dispositivo. As agendas desse tipo não são sincronizadas com um servidor. Para um
sobre adaptadores de sincronização, consulte Adaptadores de sincronização.
Tabela de eventos
A tabela CalendarContract.Events
contém detalhes
para eventos específicos. Para adicionar, atualizar ou excluir eventos, um aplicativo precisa
incluir a permissão WRITE_CALENDAR
no
arquivo de manifesto.
As colunas Eventos a seguir são graváveis tanto por um aplicativo quanto por um adaptador
de sincronização. Para conferir uma lista completa de campos compatíveis, consulte a referência do 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, um valor de "PT1H" declara que o evento
deve durar uma hora, e o valor "P2W" indica um
com duração de 2 semanas. |
ALL_DAY |
Um valor de 1 indica que esse evento ocupa o dia inteiro, conforme definido por no fuso horário local. Um valor de 0 indica que é um evento comum que pode começar e terminar a qualquer momento durante um dia. |
RRULE |
É a regra de recorrência do formato do evento. Para
exemplo: "FREQ=WEEKLY;COUNT=10;WKST=SU" . Confira
mais exemplos aqui. |
RDATE |
Mostra as datas de recorrência do evento.
Normalmente, usa-se RDATE
em conjunto com RRULE
para definir um conjunto agregado de
ocorrências repetidas. Para mais discussões, consulte a especificação RFC5545. |
AVAILABILITY |
Indica 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 o aplicativo inserir um novo evento, recomendamos que você use uma
intent INSERT
, conforme descrito em Uso de um intent para inserir um evento. No entanto, se você
precisa, é possível inserir eventos diretamente. Esta seção descreve como fazer
isso.
Veja as regras para inserção de um novo evento:
- Você precisa incluir
CALENDAR_ID
eDTSTART
. - Você precisa incluir um
EVENT_TIMEZONE
. Para acessar uma lista dos IDs de fuso horário instalados do sistema, usegetAvailableIDs()
. Essa regra não se aplica a inserções de evento pelo intentINSERT
, descrito em Uso de um intent para inserir um evento. Nesse cenário, é fornecido um fuso horário padrão. - Para eventos não recorrentes, é preciso incluir
DTEND
. - Para eventos recorrentes, inclua um
DURATION
, além deRRULE
ouRDATE
. Essa regra não se aplica a inserções de evento pelo intentINSERT
, descrito em Uso de um intent para inserir um evento. Nesse cenário, é possível usar umaRRULE
comDTSTART
eDTEND
. Dessa forma, o aplicativo Agenda a converte automaticamente em uma duração.
Veja um exemplo de inserção de um evento: Isso é feito na interface
para simplificar. Na prática, inserções e atualizações devem ser feitas em um
encadeamento assíncrono para mover a ação para um encadeamento de 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:confira como este exemplo captura o evento. ID após a criação do evento. 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, adicionar participantes ou lembretes a um evento.
Eventos de atualização
Quando o aplicativo quiser permitir que o usuário edite um evento, recomendamos
usar um intent EDIT
, conforme
descrito em Uso de um intent para editar um evento.
Contudo, caso necessário, será possível editar eventos diretamente. Para atualizar
um evento, é possível fornecer o _ID
do
evento como um ID anexado ao URI (withAppendedId()
)
ou como o primeiro item de seleção.
A seleção deve começar com "_id=?"
e a primeira
selectionArg
precisa ser o _ID
do evento. Você também
pode fazer atualizações usando uma seleção sem ID. Confira um exemplo de atualização de um
evento. É possível mudar 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 ao URI ou usando
a seleção padrão. Se você usar um ID anexado, também não poderá 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 excluída como 1. Essa sinalização que informa
ao adaptador de sincronização que a linha foi excluída e que essa exclusão deve ser
propagadas para o servidor. A exclusão por um adaptador de sincronização remove o evento do
banco de dados junto com todos os dados associados. Este é um exemplo de aplicação
excluir 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. Ligando
query()
retorna uma lista de participantes para o
evento com o EVENT_ID
especificado.
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, é necessário incluir 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. Observe que
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. Ligando
query()
retorna uma lista de lembretes para o
com o tipo de evento
EVENT_ID
.
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 o
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 do evento. A tabela de instâncias não é gravável e fornece
somente um modo de consultar ocorrências de eventos.
A tabela a seguir relaciona alguns dos campos passíveis de consulta de 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, relativo ao horário do Google Agenda zona. |
END_MINUTE |
O minuto final da instância calculado 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 inicial do calendário juliano da instância, relativo ao fuso horário do Agenda. |
START_MINUTE |
O minuto inicial da instância calculado a partir de meia-noite, relativo ao fuso horário do Agenda. |
Consultar a tabela de instâncias
Para consultar a tabela de instâncias, é necessário especificar um intervalo de tempo para a consulta
no URI. Neste exemplo, CalendarContract.Instances
tem acesso ao campo TITLE
pela
implementação da interface CalendarContract.EventsColumns
.
Em outras palavras, TITLE
é retornado por uma
visualização do 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 do Agenda
O app não precisa de permissões para ler e gravar dados de 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 |
CalendarContract.CONTENT_URI .
Para conferir um exemplo de uso dessa intent, consulte Como usar intents para exibir dados de agenda.
|
Abre a agenda no horário especificado por <ms_since_epoch> . |
Nenhum. |
Events.CONTENT_URI .
Para ver um exemplo do uso dessa intent, consulte Como usar intents para exibir dados da agenda.
|
Exibe o evento especificado por <event_id> . |
CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME |
|
EDIT |
Events.CONTENT_URI .
Para conferir um exemplo de uso desse intent, consulte Como usar um intent para editar um evento.
|
Edita o evento especificado por <event_id> . |
CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME |
EDIT INSERT |
Events.CONTENT_URI .
Para conferir 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 nem mesmo 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 Agenda para finalizar a adição do evento. A intent INSERT
usa campos extras para
preencherá um formulário com os detalhes do evento no Google Agenda. Assim, os usuários poderão
cancelar o evento, editar o formulário conforme necessário ou salvar o evento na
agenda.
Veja 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 esse snippet de código:
- Ele especifica
Events.CONTENT_URI
. como o URI. - Ela usa os campos extras
CalendarContract.EXTRA_EVENT_BEGIN_TIME
eCalendarContract.EXTRA_EVENT_END_TIME
para preencher previamente o formulário. com o horário do evento. Os valores desses horários precisam estar em milissegundos UTC da época. - Ela usa
Intent.EXTRA_EMAIL
. campo extra para fornecer uma lista de convidados separados por vírgulas, 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 um intent para editar um evento
É possível atualizar um evento diretamente, conforme descrito em Como atualizar eventos. Porém, o uso do intent EDIT
permite que um aplicativo
sem permissão entregue a edição de eventos ao aplicativo Agenda.
Quando os usuários terminam de editar o evento no Google Agenda, eles voltam para a
da aplicação original.
Confira um exemplo de intent que define um novo título para um evento especificado e permite que os usuários editem o evento na 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 diferentes 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á apenas pequenas diferenças na forma como um aplicativo e um adaptador de sincronização acessar o Provedor de Agenda:
- Um adaptador de sincronização precisa especificar que é um adaptador de sincronização definindo
CALLER_IS_SYNCADAPTER
comotrue
. - Um adaptador de sincronização precisa fornecer um
ACCOUNT_NAME
e umACCOUNT_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 aplicativo só pode modificar algumas características de uma agenda,
como nome, nome de exibição, configurações de visibilidade e se a agenda está
sincronizada. Por comparação, um adaptador de sincronização pode acessar não só essas colunas, mas muitas outras,
como cor da agenda, fuso horário, nível de acesso, local etc.
No entanto, os adaptadores de sincronização são restritos às
ACCOUNT_NAME
eACCOUNT_TYPE
especificado.
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(); }