El proveedor de calendario es un repositorio para los eventos de calendario de un usuario. La API de Calendar Provider te permite realizar operaciones de consulta, inserción, actualización y eliminación en elementos como calendarios, eventos, asistentes y recordatorios.
Las aplicaciones y los adaptadores de sincronización pueden usar la API de Calendar Provider. Las reglas varían según el tipo de programa que realiza las llamadas. Este documento se enfoca principalmente en el uso de la API de Calendar Provider como una aplicación. Para obtener información sobre las diferencias entre los adaptadores de sincronización, consulta Adaptadores de sincronización.
Normalmente, para leer o escribir datos del calendario, el manifiesto de una aplicación debe incluir los permisos adecuados, que se describen en Permisos del usuario. Para facilitar la realización de operaciones comunes, el proveedor de calendario ofrece un conjunto de intents, como se describe en Intents de calendario. Estos intents llevan a los usuarios a la aplicación de Calendario para insertar, ver y editar eventos. El usuario interactúa con la aplicación de Calendario y, luego, regresa a la aplicación original. Por lo tanto, tu aplicación no necesita solicitar permisos ni proporcionar una interfaz de usuario para ver o crear eventos.
Conceptos básicos
Los proveedores de contenido almacenan datos y los ponen a disposición de las aplicaciones. Los proveedores de contenido que ofrece la plataforma de Android (incluido el proveedor de calendario) suelen exponer los datos como un conjunto de tablas basadas en un modelo de base de datos relacional, en el que cada fila es un registro y cada columna contiene datos de un tipo y significado específicos. A través de la API de Calendar Provider, las aplicaciones y los adaptadores de sincronización pueden obtener acceso de lectura y escritura a las tablas de la base de datos que contienen los datos del calendario de un usuario.
Cada proveedor de contenido expone un URI público (unido como un objeto Uri) que identifica de forma única su conjunto de datos. Un proveedor de contenido que controla varios conjuntos de datos (varias tablas) expone un URI independiente para cada uno. Todos los URI de los proveedores comienzan con la cadena "content://". Esto identifica que los datos están controlados por un proveedor de contenido. El proveedor de calendario define constantes para los URI de cada una de sus clases (tablas). Estos
URIs tienen el formato <class>.CONTENT_URI. Por ejemplo, Events.CONTENT_URI.
En la figura 1, se muestra una representación gráfica del modelo de datos del proveedor de calendario. Muestra las tablas principales y los campos que las vinculan entre sí.
Un usuario puede tener varios calendarios, y los diferentes calendarios se pueden asociar con diferentes tipos de cuentas (Calendario de Google, Exchange, etcétera).
El CalendarContract define el modelo de datos de la información relacionada con el calendario y los eventos. Estos datos se almacenan en varias tablas, que se enumeran a continuación.
| Tabla (clase) | Descripción |
|---|---|
| Esta tabla contiene la información específica del calendario. Cada fila de esta tabla contiene los detalles de un solo calendario, como el nombre, el color y la información de sincronización. | |
CalendarContract.Events |
Esta tabla contiene la
información específica del evento. Cada fila de esta tabla tiene la información de un solo
evento, por ejemplo, el título, la ubicación, la hora de inicio y la hora de
finalización. El evento puede ocurrir una sola vez o repetirse varias veces. Los asistentes, los recordatorios y las propiedades extendidas se almacenan en tablas separadas.
Cada uno tiene un EVENT_ID que hace referencia al _ID en la tabla Events. |
CalendarContract.Instances |
Esta tabla contiene la hora de inicio y finalización de cada instancia de un evento. Cada fila de esta tabla representa un solo evento. Para los eventos únicos, hay una asignación de 1:1 de instancias a eventos. En el caso de los eventos recurrentes, se generan automáticamente varias filas que corresponden a las múltiples instancias de ese evento. |
CalendarContract.Attendees |
Esta tabla contiene la información de los asistentes (invitados) al evento. Cada fila representa un solo invitado de un evento. Especifica el tipo de invitado y la respuesta de asistencia del invitado para el evento. |
CalendarContract.Reminders |
Esta tabla contiene los
datos de alertas y notificaciones. Cada fila representa una sola alerta para un evento. Un
evento puede tener varios recordatorios. La cantidad máxima de recordatorios por evento se especifica en MAX_REMINDERS, que establece el adaptador de sincronización que posee el calendario determinado. Los recordatorios se especifican en minutos antes del evento y tienen un método que determina cómo se alertará al usuario. |
La API de Calendar Provider está diseñada para ser flexible y potente. Al mismo tiempo, es importante proporcionar una buena experiencia del usuario final y proteger la integridad del calendario y sus datos. Para ello, ten en cuenta lo siguiente cuando uses la API:
- Insertar, actualizar y ver eventos de calendario Para insertar, modificar y leer eventos directamente desde el proveedor de calendario, necesitas los permisos adecuados. Sin embargo, si no estás creando una aplicación de calendario completa o un adaptador de sincronización, no es necesario que solicites estos permisos. En su lugar, puedes usar intents compatibles con la aplicación de Calendario de Android para transferir operaciones de lectura y escritura a esa aplicación. Cuando usas los intents, tu aplicación envía a los usuarios a la aplicación de Calendario para que realicen la operación elegida en un formulario precompletado. Cuando finalizan, se los devuelve a tu aplicación. Si diseñas tu aplicación para que realice operaciones comunes a través del Calendario, les proporcionarás a los usuarios una interfaz de usuario coherente y sólida. Este es el enfoque recomendado. Para obtener más información, consulta Intents de calendario.
- Adaptadores de sincronización. Un adaptador de sincronización sincroniza los datos del calendario
en el dispositivo de un usuario con otro servidor o fuente de datos. En las tablas
CalendarContract.CalendarsyCalendarContract.Events, hay columnas reservadas para que las usen los adaptadores de sincronización. El proveedor y las aplicaciones no deben modificarlos. De hecho, no son visibles, a menos que se acceda a ellos como un adaptador de sincronización. Para obtener más información sobre los adaptadores de sincronización, consulta Adaptadores de sincronización.
Permisos de usuario
Para leer los datos del calendario, una aplicación debe incluir el permiso READ_CALENDAR en su archivo de manifiesto. Debe incluir el permiso WRITE_CALENDAR para borrar, insertar o actualizar datos del calendario:
<?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>
Tabla Calendars
La tabla CalendarContract.Calendars contiene detalles
de los calendarios individuales. Tanto una aplicación como un adaptador de sincronización pueden escribir en las siguientes columnas de Calendars.
Para obtener una lista completa de los campos admitidos, consulta la
referencia de CalendarContract.Calendars.
| Constante | Descripción |
|---|---|
NAME |
Es el nombre del calendario. |
CALENDAR_DISPLAY_NAME |
Es el nombre de este calendario que se muestra al usuario. |
VISIBLE |
Es un valor booleano que indica si se seleccionó el calendario para mostrarse. Un valor de 0 indica que no se deben mostrar los eventos asociados con este calendario. Un valor de 1 indica que se deben mostrar los eventos asociados con este calendario. Este valor afecta la generación de filas en la tabla CalendarContract.Instances. |
SYNC_EVENTS |
Es un valor booleano que indica si el calendario se debe sincronizar y si sus eventos se deben almacenar en el dispositivo. Un valor de 0 indica que no se debe sincronizar este calendario ni almacenar sus eventos en el dispositivo. Un valor de 1 indica que se deben sincronizar los eventos de este calendario y almacenarlos en el dispositivo. |
Incluye un tipo de cuenta para todas las operaciones
Si consultas un Calendars.ACCOUNT_NAME, también debes incluir
Calendars.ACCOUNT_TYPE
en la selección. Esto se debe a que una cuenta determinada
solo se considera única si se proporcionan su ACCOUNT_NAME y su
ACCOUNT_TYPE. ACCOUNT_TYPE es la cadena correspondiente al autenticador de cuentas que se usó cuando se registró la cuenta con AccountManager. También hay un tipo especial de cuenta
llamada ACCOUNT_TYPE_LOCAL para
los calendarios que no están asociados con una cuenta de dispositivo.
Las cuentas de ACCOUNT_TYPE_LOCAL no se sincronizan.
Cómo consultar un calendario
Este es un ejemplo en el que se muestra cómo obtener los calendarios que pertenecen a un usuario
en particular. Para simplificar, en este ejemplo, la operación de consulta se muestra en el subproceso de la interfaz de usuario ("subproceso principal"). En la práctica, esto se debe hacer en un subproceso asíncrono en lugar del subproceso principal. Para obtener más información, consulta Cargadores. Si no solo estás leyendo datos, sino que también los estás modificando, consulta 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;
En la siguiente parte del ejemplo, crearás tu consulta. La selección
especifica los criterios de la consulta. En este ejemplo, la consulta busca
calendarios que tengan el ACCOUNT_NAME
"hera@example.com", el ACCOUNT_TYPE
"com.example" y el OWNER_ACCOUNT
"hera@example.com". Si deseas ver todos los calendarios que vio un usuario, no solo los que le pertenecen, omite el parámetro OWNER_ACCOUNT.
La consulta devuelve un objeto Cursor que puedes usar para recorrer el conjunto de resultados que devuelve la consulta de la base de datos. Para obtener más información sobre el uso de consultas en proveedores de contenido, consulta Proveedores de contenido.
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);
En la siguiente sección, se usa el cursor para recorrer el conjunto de resultados. Usa las constantes que se configuraron al principio del ejemplo para devolver los 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 un calendario
Para actualizar un calendario, puedes proporcionar el _ID del calendario como un ID adjunto al URI (withAppendedId()) o como el primer elemento de selección. La selección
debe comenzar con "_id=?", y el primer
selectionArg debe ser el _ID del calendario.
También puedes realizar actualizaciones codificando el ID en el URI. En este ejemplo, se cambia el nombre visible de un calendario con el enfoque (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);
Cómo insertar un calendario
Los calendarios están diseñados para que los administre principalmente un adaptador de sincronización, por lo que solo debes insertar calendarios nuevos como un adaptador de sincronización. En su mayor parte,
las aplicaciones solo pueden realizar cambios superficiales en los calendarios, como cambiar el nombre visible. Si una aplicación necesita crear un calendario local, puede hacerlo realizando la inserción del calendario como un adaptador de sincronización, con un ACCOUNT_TYPE de ACCOUNT_TYPE_LOCAL.
ACCOUNT_TYPE_LOCAL
es un tipo de cuenta especial para los calendarios que no están
asociados con una cuenta de dispositivo. Los calendarios de este tipo no se sincronizan con un servidor. Para obtener un análisis de los adaptadores de sincronización, consulta Adaptadores de sincronización.
Tabla de eventos
La tabla CalendarContract.Events contiene detalles
de eventos individuales. Para agregar, actualizar o borrar eventos, una aplicación debe incluir el permiso WRITE_CALENDAR en su archivo de manifiesto.
Tanto una aplicación como un adaptador de sincronización pueden escribir en las siguientes columnas de Events. Para obtener una lista completa de los campos admitidos, consulta la referencia de CalendarContract.Events.
| Constante | Descripción |
|---|---|
CALENDAR_ID |
El _ID del calendario al que pertenece el evento. |
ORGANIZER |
Es el correo electrónico del organizador (propietario) del evento. |
TITLE |
Es el título del evento. |
EVENT_LOCATION |
Dónde se lleva a cabo el evento |
DESCRIPTION |
Es la descripción del evento. |
DTSTART |
La hora en que comienza el evento en milisegundos UTC desde la época. |
DTEND |
La hora a la que termina el evento en milisegundos UTC desde la época. |
EVENT_TIMEZONE |
Es la zona horaria del evento. |
EVENT_END_TIMEZONE |
Es la zona horaria de la hora de finalización del evento. |
DURATION |
Es la duración del evento en formato RFC5545.
Por ejemplo, un valor de "PT1H" indica que el evento
debe durar una hora, y un valor de "P2W" indica una
duración de 2 semanas. |
ALL_DAY |
Un valor de 1 indica que este evento ocupa todo el día, según lo define la zona horaria local. Un valor de 0 indica que es un evento normal que puede comenzar y terminar en cualquier momento del día. |
RRULE |
Es la regla de recurrencia para el formato del evento. Por ejemplo, "FREQ=WEEKLY;COUNT=10;WKST=SU". Para
obtener más ejemplos, consulta la especificación RFC5545. |
RDATE |
Son las fechas de recurrencia del evento.
Por lo general, usas RDATE junto con RRULE para definir un conjunto agregado de ocurrencias repetidas. Para obtener más información, consulta la especificación RFC 5545. |
AVAILABILITY |
Indica si este evento se considera tiempo ocupado o tiempo libre que se puede programar. |
GUESTS_CAN_MODIFY |
Si los invitados pueden modificar el evento |
GUESTS_CAN_INVITE_OTHERS |
Indica si los invitados pueden invitar a otras personas. |
GUESTS_CAN_SEE_GUESTS |
Si los invitados pueden ver la lista de asistentes. |
Agregar eventos
Cuando tu aplicación inserte un evento nuevo, te recomendamos que uses un intent INSERT, como se describe en Cómo usar un intent para insertar un evento. Sin embargo, si es necesario, puedes insertar eventos directamente. En esta sección, se describe cómo hacerlo.
Estas son las reglas para insertar un evento nuevo:
- Debes incluir
CALENDAR_IDyDTSTART. - Debes incluir un
EVENT_TIMEZONE. Para obtener una lista de los IDs de zona horaria instalados en el sistema, usagetAvailableIDs(). Ten en cuenta que esta regla no se aplica si insertas un evento a través del intentINSERT, que se describe en Cómo usar un intent para insertar un evento. En ese caso, se proporciona una zona horaria predeterminada. - En el caso de los eventos no recurrentes, debes incluir
DTEND. - En el caso de los eventos recurrentes, debes incluir un
DURATIONademás deRRULEoRDATE. Ten en cuenta que esta regla no se aplica si insertas un evento a través del intentINSERT, que se describe en Cómo usar un intent para insertar un evento. En ese caso, puedes usar unRRULEjunto conDTSTARTyDTEND, y la aplicación de Calendario lo convierte en una duración automáticamente.
Este es un ejemplo de cómo insertar un evento. Esto se realiza en el subproceso de IU para simplificar. En la práctica, las inserciones y actualizaciones deben realizarse en un subproceso asíncrono para mover la acción a un subproceso en segundo plano. Para obtener más información, consulta 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 // //
Nota: Observa cómo este ejemplo captura el ID del evento después de que se crea. Esta es la forma más fácil de obtener un ID de evento. A menudo, necesitas el ID de evento para realizar otras operaciones de calendario, por ejemplo, para agregar asistentes o recordatorios a un evento.
Eventos de actualización
Cuando tu aplicación quiera permitir que el usuario edite un evento, te recomendamos que uses un intent EDIT, como se describe en Cómo usar un intent para editar un evento.
Sin embargo, si es necesario, puedes editar los eventos directamente. Para actualizar un evento, puedes proporcionar el _ID del evento como un ID adjunto al URI (withAppendedId()) o como el primer elemento de selección.
La selección debe comenzar con "_id=?", y el primer
selectionArg debe ser el _ID del evento. También puedes
realizar actualizaciones con una selección sin ID. Este es un ejemplo de cómo actualizar un
evento. Cambia el título del evento con el enfoque 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);
Borrar eventos
Puedes borrar un evento por su _ID como un ID agregado en el URI o con la selección estándar. Si usas un ID agregado, tampoco puedes realizar una selección.
Existen dos versiones de eliminación: como aplicación y como adaptador de sincronización. La eliminación de una aplicación establece la columna deleted en 1. Esta marca le indica al adaptador de sincronización que se borró la fila y que esta eliminación debe propagarse al servidor. La eliminación de un adaptador de sincronización quita el evento de la base de datos junto con todos sus datos asociados. A continuación, se muestra un ejemplo de una aplicación que borra un evento a través de su _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);
Tabla de asistentes
Cada fila de la tabla CalendarContract.Attendees
representa un solo asistente o invitado de un evento. Cuando se llama a
query(),
se devuelve una lista de asistentes al
evento con el EVENT_ID proporcionado.
Este EVENT_ID
debe coincidir con el _ID de un evento en particular.
En la siguiente tabla, se enumeran los campos que se pueden escribir. Cuando insertes un asistente nuevo, debes incluirlos a todos,
excepto ATTENDEE_NAME.
| Constante | Descripción |
|---|---|
EVENT_ID |
Es el ID del evento. |
ATTENDEE_NAME |
Es el nombre del asistente. |
ATTENDEE_EMAIL |
Es la dirección de correo electrónico del asistente. |
ATTENDEE_RELATIONSHIP |
Es la relación del asistente con el evento. Uno de los siguientes: |
ATTENDEE_TYPE |
Es el tipo de asistente. Uno de los siguientes: |
ATTENDEE_STATUS |
Es el estado de asistencia del participante. Uno de los siguientes: |
Agregar asistentes
Este es un ejemplo en el que se agrega un solo asistente a un evento. Ten en cuenta que
EVENT_ID
es obligatorio:
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);
Tabla de recordatorios
Cada fila de la tabla CalendarContract.Reminders
representa un solo recordatorio de un evento. Si llamas a query(), se muestra una lista de recordatorios para el evento con el EVENT_ID determinado.
En la siguiente tabla, se enumeran los campos que se pueden escribir para los recordatorios. Todos ellos deben
incluirse cuando se inserta un recordatorio nuevo. Ten en cuenta que los adaptadores de sincronización especifican los
tipos de recordatorios que admiten en la tabla CalendarContract.Calendars. Consulta
ALLOWED_REMINDERS
para obtener más información.
| Constante | Descripción |
|---|---|
EVENT_ID |
Es el ID del evento. |
MINUTES |
Son los minutos previos al evento en los que se debe activar el recordatorio. |
METHOD |
Es el método de alarma, como se establece en el servidor. Uno de los siguientes: |
Agregar recordatorio
En este ejemplo, se agrega un recordatorio a un evento. El recordatorio se activa 15 minutos antes del 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);
Tabla de instancias
La tabla CalendarContract.Instances contiene la hora de inicio y finalización de las ocurrencias de un evento. Cada fila de esta tabla
representa un solo evento. No se puede escribir en la tabla de instancias y solo
proporciona una forma de consultar las ocurrencias de eventos.
En la siguiente tabla, se enumeran algunos de los campos que puedes consultar para una instancia. Ten en cuenta que la zona horaria se define con KEY_TIMEZONE_TYPE y KEY_TIMEZONE_INSTANCES.
| Constante | Descripción |
|---|---|
BEGIN |
La hora de inicio de la instancia, en milisegundos UTC. |
END |
Es la hora de finalización de la instancia, en milisegundos UTC. |
END_DAY |
Es el día juliano de finalización de la instancia, en relación con la zona horaria del calendario. |
END_MINUTE |
Es el minuto de finalización de la instancia medido desde la medianoche en la zona horaria del calendario. |
EVENT_ID |
Es el _ID del evento para esta instancia. |
START_DAY |
Es el día de inicio juliano de la instancia, en relación con la zona horaria del calendario. |
START_MINUTE |
Es el minuto de inicio de la instancia medido desde la medianoche, en relación con la zona horaria del calendario. |
Consulta la tabla de instancias
Para consultar la tabla Instances, debes especificar un rango de tiempo para la consulta
en el URI. En este ejemplo, CalendarContract.Instances
obtiene acceso al campo TITLE a través de su
implementación de la interfaz CalendarContract.EventsColumns.
En otras palabras, TITLE se devuelve a través de una
vista de base de datos, no a través de una consulta de la tabla CalendarContract.Instances sin procesar.
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 calendario
Tu aplicación no necesita permisos para leer y escribir datos del calendario. En su lugar, puede usar intents compatibles con la aplicación de Calendario de Android para transferir operaciones de lectura y escritura a esa aplicación. En la siguiente tabla, se enumeran los intents que admite el proveedor de calendario:
| Acción | URI | Descripción | Adicionales |
|---|---|---|---|
VIEW |
CalendarContract.CONTENT_URI.
Para ver un ejemplo de cómo usar este intent, consulta Cómo usar intents para ver datos del calendario.
|
Abre el calendario en la hora especificada por <ms_since_epoch>. |
Ninguno |
Events.CONTENT_URI.
Para ver un ejemplo de cómo usar este intent, consulta Cómo usar intents para ver datos del calendario.
|
Consulta el evento especificado por <event_id>. |
CalendarContract.EXTRA_EVENT_BEGIN_TIMECalendarContract.EXTRA_EVENT_END_TIME |
|
EDIT |
Events.CONTENT_URI.
Para ver un ejemplo de cómo usar este intent, consulta Cómo usar un intent para editar un evento.
|
Edita el evento especificado por <event_id>. |
CalendarContract.EXTRA_EVENT_BEGIN_TIMECalendarContract.EXTRA_EVENT_END_TIME |
EDIT INSERT |
Events.CONTENT_URI.
Para ver un ejemplo de cómo usar este intent, consulta Cómo usar un intent para insertar un evento.
|
Crea un evento. | Cualquiera de los extras que se indican en la siguiente tabla. |
En la siguiente tabla, se enumeran los extras de intents que admite el proveedor de calendario:
| Intent Extra | Descripción |
|---|---|
Events.TITLE |
Es el nombre del evento. |
CalendarContract.EXTRA_EVENT_BEGIN_TIME |
Es la hora de inicio del evento en milisegundos desde el ciclo de entrenamiento. |
CalendarContract.EXTRA_EVENT_END_TIME |
Es la hora de finalización del evento en milisegundos desde la época. |
CalendarContract.EXTRA_EVENT_ALL_DAY |
Es un valor booleano que indica que un evento dura todo el día. El valor puede ser
true o false. |
Events.EVENT_LOCATION |
Ubicación del evento |
Events.DESCRIPTION |
Es la descripción del evento. |
Intent.EXTRA_EMAIL |
Son las direcciones de correo electrónico de las personas a las que se invitará, en una lista separada por comas. |
Events.RRULE |
Es la regla de recurrencia del evento. |
Events.ACCESS_LEVEL |
Si el evento es privado o público |
Events.AVAILABILITY |
Indica si este evento cuenta como tiempo ocupado o si es tiempo libre que se puede programar. |
En las siguientes secciones, se describe cómo usar estos intents.
Usa un intent para insertar un evento
El uso del intent INSERT permite que tu aplicación transfiera la tarea de inserción de eventos al Calendario.
Con este enfoque, tu aplicación ni siquiera necesita tener el permiso WRITE_CALENDAR incluido en su archivo de manifiesto.
Cuando los usuarios ejecutan una aplicación que usa este enfoque, la aplicación los envía al Calendario para que terminen de agregar el evento. El intent INSERT usa campos adicionales para completar previamente un formulario con los detalles del evento en el Calendario. Luego, los usuarios pueden cancelar el evento, editar el formulario según sea necesario o guardar el evento en sus calendarios.
A continuación, se muestra un fragmento de código que programa un evento para el 19 de enero de 2012, que se ejecuta de 7:30 a.m. a 8:30 a.m. Ten en cuenta lo siguiente sobre este fragmento de código:
- Especifica
Events.CONTENT_URIcomo el URI. - Usa los campos adicionales
CalendarContract.EXTRA_EVENT_BEGIN_TIMEyCalendarContract.EXTRA_EVENT_END_TIMEpara completar previamente el formulario con la hora del evento. Los valores de estos horarios deben estar en milisegundos UTC desde el ciclo de entrenamiento. - Usa el campo adicional
Intent.EXTRA_EMAILpara proporcionar una lista de invitados separada por comas, especificada por dirección de correo electrónico.
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);
Cómo usar un intent para editar un evento
Puedes actualizar un evento directamente, como se describe en Actualiza eventos. Sin embargo, el uso del intent EDIT permite que una aplicación que no tiene permiso transfiera la edición de eventos a la aplicación de Calendario.
Cuando los usuarios terminan de editar su evento en el Calendario, regresan a la aplicación original.
Este es un ejemplo de un intent que establece un título nuevo para un evento específico y permite que los usuarios editen el evento en el Calendario.
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);
Usa intents para ver datos del calendario
El proveedor de calendario ofrece dos formas diferentes de usar el intent VIEW:
- Para abrir el Calendario en una fecha específica
- Para ver un evento
Este es un ejemplo en el que se muestra cómo abrir el Calendario en una fecha 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);
Este es un ejemplo en el que se muestra cómo abrir un evento para verlo:
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 sincronización
Solo hay diferencias menores en la forma en que una aplicación y un adaptador de sincronización acceden al proveedor de calendario:
- Un adaptador de sincronización debe especificar que es un adaptador de sincronización configurando
CALLER_IS_SYNCADAPTERcomotrue. - Un adaptador de sincronización debe proporcionar un
ACCOUNT_NAMEy unACCOUNT_TYPEcomo parámetros de consulta en el URI. - Un adaptador de sincronización tiene acceso de escritura a más columnas que una aplicación o un widget.
Por ejemplo, una aplicación solo puede modificar algunas características de un calendario,
como su nombre, nombre visible, configuración de visibilidad y si el calendario está
sincronizado. En comparación, un adaptador de sincronización puede acceder no solo a esas columnas, sino también a muchas otras, como el color del calendario, la zona horaria, el nivel de acceso y la ubicación.
Sin embargo, un adaptador de sincronización está restringido a la
ACCOUNT_NAMEy laACCOUNT_TYPEque especificó.
A continuación, se muestra un método de ayuda que puedes usar para devolver un URI que se use con un adaptador de sincronización:
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(); }