Le fournisseur d'agendas est un dépôt pour les événements d'agenda d'un utilisateur. L'API Calendar Provider vous permet d'effectuer des requêtes, d'insérer, de mettre à jour et de supprimer des agendas, des événements, des participants, des rappels, etc.
L'API Calendar Provider peut être utilisée par les applications et les adaptateurs de synchronisation. Les règles varient en fonction du type de programme qui effectue les appels. Ce document porte principalement sur l'utilisation de l'API Calendar Provider en tant qu'application. Pour en savoir plus sur les différences entre les adaptateurs de synchronisation, consultez la section Adaptateurs de synchronisation.
Normalement, pour lire ou écrire des données d'agenda, le fichier manifeste d'une application doit inclure les autorisations appropriées, décrites dans la section Autorisations de l'utilisateur. Pour faciliter la réalisation des opérations courantes, le fournisseur d'Agenda propose un ensemble d'intents, comme décrit dans la section Intents d'agenda. Ces intents redirigent les utilisateurs vers l'application Agenda pour qu'ils puissent insérer, afficher et modifier des événements. L'utilisateur interagit avec l'application Agenda, puis revient à l'application d'origine. Votre application n'a donc pas besoin de demander d'autorisations, ni de fournir une interface utilisateur pour afficher ou créer des événements.
Principes de base
Les fournisseurs de contenu stockent des données et les rendent accessibles aux applications. Les fournisseurs de contenu proposés par la plate-forme Android (y compris le fournisseur d'agenda) présentent généralement les données sous la forme d'un ensemble de tables basé sur un modèle de base de données relationnelle, dans lequel chaque ligne correspond à un enregistrement, et chaque colonne correspond à des données d'un type et d'une signification spécifiques. Grâce à l'API Calendar Provider, les applications et les adaptateurs de synchronisation peuvent obtenir un accès en lecture/écriture aux tables de base de données qui contiennent les données d'agenda d'un utilisateur.
Chaque fournisseur de contenu expose un URI public (encapsulé en tant qu'objet Uri
) qui identifie de manière unique son ensemble de données. Un fournisseur de contenu qui contrôle plusieurs ensembles de données (plusieurs tables) expose un URI distinct pour chacun. Tous les URI des fournisseurs commencent par la chaîne "content://". Cela permet de déterminer que les données sont contrôlées par un fournisseur de contenu. Calendar Provider définit des constantes pour les URI de chacune de ses classes (tables). Ces URI sont au format <class>.CONTENT_URI
. Exemple : Events.CONTENT_URI
.
La figure 1 présente une représentation graphique du modèle de données du fournisseur d'agendas. Elle affiche les tables principales et les champs qui les lient les unes aux autres.
![Modèle de données du fournisseur d'agenda](https://developer.android.com/static/images/providers/datamodel.png?authuser=6&hl=fr)
Figure 1 : Modèle de données du fournisseur d'agenda.
Un utilisateur peut disposer de plusieurs agendas, et plusieurs agendas peuvent être associés à différents types de comptes (Google Agenda, Exchange, etc.).
CalendarContract
définit le modèle de données des informations liées à l'agenda et aux événements. Ces données sont stockées dans plusieurs tables, répertoriées ci-dessous.
Table (classe) | Description |
---|---|
Cette table contient les informations spécifiques à l'agenda. Chaque ligne de ce tableau contient les détails d'un seul agenda, tels que le nom, la couleur, les informations de synchronisation, etc. | |
CalendarContract.Events |
Cette table contient les informations spécifiques à l'événement. Chaque ligne de cette table contient des informations sur un seul événement : titre, lieu, heure de début, heure de fin, etc. L'événement peut se produire une seule fois ou se répéter plusieurs fois. Les participants, les rappels et les propriétés étendues sont stockés dans des tables distinctes.
Chacun d'entre eux possède un EVENT_ID qui fait référence au _ID de la table "Événements". |
CalendarContract.Instances |
Cette table contient les heures de début et de fin de chaque occurrence d'un événement. Chaque ligne de ce tableau représente une seule occurrence d'événement. Pour les événements ponctuels, il existe un mappage 1:1 des instances avec les événements. Pour les événements récurrents, plusieurs lignes correspondant à plusieurs occurrences de cet événement sont générées automatiquement. |
CalendarContract.Attendees |
Cette table contient les informations sur les participants à l'événement (invités). Chaque ligne représente un seul invité d'un événement. Il spécifie le type d'invité et la réponse de participation de l'invité à l'événement. |
CalendarContract.Reminders |
Cette table contient les données d'alerte/notification. Chaque ligne représente une alerte spécifique pour un événement. Un événement peut avoir plusieurs rappels. Le nombre maximal de rappels par événement est spécifié dans MAX_REMINDERS , qui est défini par l'adaptateur de synchronisation propriétaire de l'agenda donné. Les rappels sont spécifiés en minutes avant l'événement et disposent d'une méthode qui détermine la manière dont l'utilisateur sera alerté. |
L'API Calendar Provider est conçue pour être flexible et puissante. Dans le même temps, il est important d'offrir une bonne expérience utilisateur, et de protéger l'intégrité de l'agenda et de ses données. À cette fin, voici quelques points à garder à l'esprit lorsque vous utilisez l'API:
- Insérer, mettre à jour et afficher des événements d'agenda Pour insérer, modifier et lire directement des événements à partir du fournisseur d'agendas, vous devez disposer des autorisations appropriées. Toutefois, si vous ne créez pas une application d'agenda complète ni un adaptateur de synchronisation, il n'est pas nécessaire de demander ces autorisations. À la place, vous pouvez utiliser des intents compatibles avec l'application Agenda d'Android pour transférer les opérations de lecture et d'écriture vers cette application. Lorsque vous utilisez les intents, votre application redirige les utilisateurs vers l'application Agenda pour qu'ils effectuent l'opération souhaitée sous forme de formulaire prérempli. Une fois terminées, ils sont renvoyés à votre application. En concevant une application pour effectuer des opérations courantes via Agenda, vous offrez aux utilisateurs une interface cohérente et robuste. Il s'agit de l'approche recommandée. Pour en savoir plus, consultez Intents Agenda.
- Adaptateurs de synchronisation. Un adaptateur de synchronisation synchronise les données d'agenda de l'appareil d'un utilisateur avec un autre serveur ou une autre source de données. Dans les tables
CalendarContract.Calendars
etCalendarContract.Events
, des colonnes sont réservées aux adaptateurs de synchronisation. Le fournisseur et les applications ne doivent pas les modifier. En fait, ils ne sont visibles que s'ils sont accessibles en tant qu'adaptateur de synchronisation. Pour en savoir plus sur les adaptateurs de synchronisation, consultez la section Adaptateurs de synchronisation.
Autorisations utilisateur
Pour lire les données d'agenda, une application doit inclure l'autorisation READ_CALENDAR
dans son fichier manifeste. Il doit inclure l'autorisation WRITE_CALENDAR
pour supprimer, insérer ou mettre à jour des données d'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>
Tableau des agendas
La table CalendarContract.Calendars
contient les détails de chaque agenda. Les colonnes d'agendas suivantes sont accessibles en écriture par une application et un adaptateur de synchronisation.
Pour obtenir la liste complète des champs acceptés, consultez la documentation de référence sur CalendarContract.Calendars
.
Constante | Description |
---|---|
NAME |
Nom de l'agenda. |
CALENDAR_DISPLAY_NAME |
Nom de cet agenda, tel qu'il est présenté à l'utilisateur. |
VISIBLE |
Booléen indiquant si l'agenda est sélectionné pour être affiché. La valeur 0 indique que les événements associés à cet agenda ne doivent pas être affichés. La valeur 1 indique que les événements associés à cet agenda doivent s'afficher. Cette valeur affecte la génération de lignes dans la table CalendarContract.Instances . |
SYNC_EVENTS |
Booléen indiquant si l'agenda doit être synchronisé et ses événements stockés sur l'appareil. La valeur 0 indique de ne pas synchroniser cet agenda ou de ne pas stocker ses événements sur l'appareil. La valeur 1 indique les événements de synchronisation de cet agenda et les stocke sur l'appareil. |
Inclure un type de compte pour toutes les opérations
Si vous interrogez un Calendars.ACCOUNT_NAME
, vous devez également inclure Calendars.ACCOUNT_TYPE
dans la sélection. En effet, un compte donné n'est considéré comme unique que pour ses ACCOUNT_NAME
et ses ACCOUNT_TYPE
. ACCOUNT_TYPE
est la chaîne correspondant à l'authentificateur de compte utilisé lorsque le compte a été enregistré auprès de AccountManager
. Il existe également un type de compte spécial, appelé ACCOUNT_TYPE_LOCAL
, pour les agendas qui ne sont pas associés à un compte d'appareil.
Les comptes ACCOUNT_TYPE_LOCAL
ne sont pas synchronisés.
Interroger un agenda
Voici un exemple illustrant comment obtenir les agendas appartenant à un utilisateur donné. Par souci de simplicité, dans cet exemple, l'opération de requête est illustrée dans le thread de l'interface utilisateur ("thread principal"). En pratique, cette opération doit être effectuée dans un thread asynchrone plutôt que sur le thread principal. Pour en savoir plus, consultez la section Chargeurs. Si vous ne vous contentez pas de lire des données, mais de les modifier, consultez 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;
Dans la partie suivante de l'exemple, vous allez construire votre requête. La sélection spécifie les critères de la requête. Dans cet exemple, la requête recherche des agendas ayant les valeurs ACCOUNT_NAME
"hera@example.com", ACCOUNT_TYPE
"com.example" et OWNER_ACCOUNT
"hera@example.com". Si vous souhaitez afficher tous les agendas qu'un utilisateur a consultés, et pas seulement ceux dont il est propriétaire, ne renseignez pas l'élément OWNER_ACCOUNT
.
La requête renvoie un objet Cursor
que vous pouvez utiliser pour parcourir l'ensemble de résultats renvoyé par la requête de base de données. Pour en savoir plus sur l'utilisation des requêtes dans les fournisseurs de contenu, consultez la section Fournisseurs de contenu.
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);
La section suivante utilise le curseur pour parcourir l'ensemble de résultats. Il utilise les constantes configurées au début de l'exemple pour renvoyer les valeurs de chaque champ.
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... ... }
Modifier un agenda
Pour mettre à jour un agenda, vous pouvez fournir son _ID
en tant qu'ID ajouté à l'URI (withAppendedId()
) ou en tant que premier élément de sélection. La sélection doit commencer par "_id=?"
, et le premier selectionArg
doit correspondre au _ID
de l'agenda.
Vous pouvez également effectuer des mises à jour en encodant l'ID dans l'URI. Cet exemple modifie le nom à afficher d'un agenda à l'aide de l'approche (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);
Insérer un agenda
Les agendas sont conçus pour être principalement gérés par un adaptateur de synchronisation. Vous ne devez donc insérer de nouveaux agendas que comme adaptateur de synchronisation. Dans la plupart des cas, les applications ne peuvent apporter que des modifications superficielles aux agendas, comme modifier le nom à afficher. Si une application doit créer un agenda local, elle peut le faire en effectuant l'insertion de l'agenda en tant qu'adaptateur de synchronisation, avec un ACCOUNT_TYPE
défini sur ACCOUNT_TYPE_LOCAL
.
ACCOUNT_TYPE_LOCAL
est un type de compte spécial pour les agendas qui ne sont pas associés à un compte sur l'appareil. Les agendas de ce type ne sont pas synchronisés avec un serveur. Pour en savoir plus sur les adaptateurs de synchronisation, consultez Adaptateurs de synchronisation.
Tableau des événements
La table CalendarContract.Events
contient des détails sur des événements individuels. Pour ajouter, mettre à jour ou supprimer des événements, une application doit inclure l'autorisation WRITE_CALENDAR
dans son fichier manifeste.
Les colonnes d'événements suivantes sont accessibles en écriture par une application et un adaptateur de synchronisation. Pour obtenir la liste complète des champs acceptés, consultez la documentation de référence sur CalendarContract.Events
.
Constante | Description |
---|---|
CALENDAR_ID |
_ID de l'agenda auquel l'événement appartient. |
ORGANIZER |
Adresse e-mail de l'organisateur (propriétaire) de l'événement. |
TITLE |
Titre de l'événement. |
EVENT_LOCATION |
Lieu de l'événement. |
DESCRIPTION |
Description de l'événement. |
DTSTART |
Heure à laquelle l'événement commence, en millisecondes UTC depuis l'epoch. |
DTEND |
Heure de fin de l'événement en millisecondes UTC depuis l'epoch. |
EVENT_TIMEZONE |
Fuseau horaire de l'événement. |
EVENT_END_TIMEZONE |
Fuseau horaire de l'heure de fin de l'événement. |
DURATION |
Durée de l'événement au format RFC5545.
Par exemple, la valeur "PT1H" indique que l'événement doit durer une heure, tandis que la valeur "P2W" indique une durée de deux semaines. |
ALL_DAY |
La valeur 1 indique que cet événement occupe la journée entière, tel que défini par le fuseau horaire local. Une valeur de 0 indique qu'il s'agit d'un événement standard qui peut commencer et se terminer à n'importe quel moment de la journée. |
RRULE |
Règle de récurrence pour le format d'événement. Exemple : "FREQ=WEEKLY;COUNT=10;WKST=SU" . Pour consulter d'autres exemples, cliquez ici. |
RDATE |
Dates de récurrence de l'événement.
Généralement, utilisez RDATE conjointement avec RRULE pour définir un ensemble agrégé d'occurrences récurrentes. Pour en savoir plus, consultez la spécification RFC5545. |
AVAILABILITY |
Indique s'il s'agit d'un moment occupé ou d'un temps libre pouvant être programmé. |
GUESTS_CAN_MODIFY |
si les invités peuvent modifier l'événement ; |
GUESTS_CAN_INVITE_OTHERS |
si les invités peuvent convier d'autres personnes. |
GUESTS_CAN_SEE_GUESTS |
Indique si les invités peuvent voir la liste des participants. |
Ajout d'événements
Lorsque votre application insère un nouvel événement, nous vous recommandons d'utiliser un intent INSERT
, comme décrit dans la section Utiliser un intent pour insérer un événement. Toutefois, si nécessaire, vous pouvez insérer des événements directement. Cette section explique comment procéder.
Pour insérer un événement, procédez comme suit:
- Vous devez inclure
CALENDAR_ID
etDTSTART
. - Vous devez inclure un
EVENT_TIMEZONE
. Pour obtenir la liste des ID de fuseau horaire installés dans le système, utilisezgetAvailableIDs()
. Notez que cette règle ne s'applique pas si vous insérez un événement via l'intentINSERT
, décrit dans la section Utiliser un intent pour insérer un événement. Dans ce cas, un fuseau horaire par défaut est fourni. - Pour les événements non récurrents, vous devez inclure
DTEND
. - Pour les événements périodiques, vous devez inclure un
DURATION
en plus deRRULE
ouRDATE
. Notez que cette règle ne s'applique pas si vous insérez un événement via l'intentINSERT
, décrit dans la section Utiliser un intent pour insérer un événement. Dans ce cas, vous pouvez utiliserRRULE
avecDTSTART
etDTEND
. L'application Agenda le convertit automatiquement en durée.
Voici un exemple d'insertion d'un événement. Cette opération s'effectue dans le thread UI par souci de simplicité. En pratique, les insertions et les mises à jour doivent être effectuées dans un thread asynchrone pour déplacer l'action dans un thread d'arrière-plan. Pour en savoir plus, consultez 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 // //
Remarque:Découvrez comment cet exemple capture l'ID d'événement une fois l'événement créé. Il s'agit de la méthode la plus simple pour obtenir un ID d'événement. Vous avez souvent besoin de cet ID pour effectuer d'autres opérations d'agenda, par exemple pour ajouter des participants ou des rappels à un événement.
Événements de mise à jour
Lorsque votre application souhaite autoriser l'utilisateur à modifier un événement, nous vous recommandons d'utiliser un intent EDIT
, comme décrit dans la section Utiliser un intent pour modifier un événement.
Toutefois, si nécessaire, vous pouvez modifier les événements directement. Pour effectuer la mise à jour d'un événement, vous pouvez fournir l'_ID
de l'événement en tant qu'ID ajouté à l'URI (withAppendedId()
) ou en tant que premier élément de sélection.
La sélection doit commencer par "_id=?"
, et le premier selectionArg
doit être la _ID
de l'événement. Vous pouvez également effectuer des mises à jour à l'aide d'une sélection sans ID. Voici un exemple de mise à jour d'un événement. Elle modifie le titre de l'événement à l'aide de l'approche 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);
Supprimer des événements
Vous pouvez supprimer un événement soit par son _ID
en tant qu'ID ajouté à l'URI, soit en utilisant la sélection standard. Si vous utilisez un ID ajouté, vous ne pouvez pas effectuer de sélection.
Il existe deux versions de la fonction de suppression: en tant qu'application et en tant qu'adaptateur de synchronisation. Une suppression d'application définit la colonne deleted sur 1. Cet indicateur indique à l'adaptateur de synchronisation que la ligne a été supprimée et que cette suppression doit être propagée au serveur. La suppression d'un adaptateur de synchronisation supprime l'événement de la base de données, ainsi que toutes les données associées. Voici un exemple d'application qui supprime un événement via son _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);
Table des participants
Chaque ligne de la table CalendarContract.Attendees
représente un seul participant ou invité à un événement. L'appel de query()
renvoie la liste des participants à l'événement avec l'élément EVENT_ID
donné.
Cet EVENT_ID
doit correspondre au _ID
d'un événement particulier.
Le tableau suivant répertorie les champs accessibles en écriture. Lorsque vous insérez un nouveau participant, vous devez tous les inclure, sauf ATTENDEE_NAME
.
Constante | Description |
---|---|
EVENT_ID |
ID de l'événement. |
ATTENDEE_NAME |
Nom du participant. |
ATTENDEE_EMAIL |
Adresse e-mail du participant. |
ATTENDEE_RELATIONSHIP |
Lien entre le participant et l'événement. Choisissez l'une des options suivantes: |
ATTENDEE_TYPE |
Type de participant. Choisissez l'une des options suivantes: |
ATTENDEE_STATUS |
État de participation du participant. Choisissez l'une des options suivantes: |
Ajouter des participants
Dans l'exemple ci-dessous, un seul participant est ajouté à un événement. Notez que le EVENT_ID
est obligatoire:
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);
Tableau des rappels
Chaque ligne de la table CalendarContract.Reminders
représente un rappel unique pour un événement. L'appel de query()
renvoie une liste de rappels pour l'événement avec le EVENT_ID
donné.
Le tableau suivant liste les champs accessibles en écriture pour les rappels. Tous doivent être inclus lorsque vous insérez un nouveau rappel. Notez que les adaptateurs de synchronisation spécifient les types de rappels qu'ils acceptent dans le tableau CalendarContract.Calendars
. Pour en savoir plus, consultez ALLOWED_REMINDERS
.
Constante | Description |
---|---|
EVENT_ID |
ID de l'événement. |
MINUTES |
Minutes précédant l'événement pendant lesquelles le rappel doit se déclencher. |
METHOD |
Méthode d'alarme, telle qu'elle est définie sur le serveur. Choisissez l'une des options suivantes: |
Ajoutez des rappels
Dans cet exemple, un rappel est ajouté à un événement. Le rappel se déclenche 15 minutes avant l'événement.
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);
Table des instances
La table CalendarContract.Instances
contient les heures de début et de fin des occurrences d'un événement. Chaque ligne de ce tableau représente une seule occurrence d'événement. La table des instances n'est pas accessible en écriture et permet uniquement d'interroger les occurrences d'événements.
Le tableau suivant répertorie certains des champs que vous pouvez interroger pour une instance. Notez que le fuseau horaire est défini par KEY_TIMEZONE_TYPE
et KEY_TIMEZONE_INSTANCES
.
Constante | Description |
---|---|
BEGIN |
Heure de début de l'instance, en millisecondes UTC. |
END |
Heure de fin de l'instance, en millisecondes UTC. |
END_DAY |
Jour julien de l'instance par rapport au fuseau horaire du calendrier. |
END_MINUTE |
Minute de fin de l'instance mesurée à partir de minuit dans le fuseau horaire de l'agenda. |
EVENT_ID |
_ID de l'événement pour cette instance. |
START_DAY |
Jour julien de l'instance par rapport au fuseau horaire de l'agenda. |
START_MINUTE |
Minute de début de l'instance mesurée à partir de minuit par rapport au fuseau horaire de l'agenda. |
Interroger la table des instances
Pour interroger la table "Instances", vous devez spécifier une plage horaire pour la requête dans l'URI. Dans cet exemple, CalendarContract.Instances
obtient l'accès au champ TITLE
via son implémentation de l'interface CalendarContract.EventsColumns
.
En d'autres termes, TITLE
est renvoyé via une vue de base de données, et non via une requête sur la table CalendarContract.Instances
brute.
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 d'agenda
Votre application ne nécessite pas d'autorisations pour lire et écrire des données d'agenda. À la place, il peut utiliser des intents compatibles avec l'application Agenda d'Android pour transférer les opérations de lecture et d'écriture vers cette application. Le tableau suivant liste les intents compatibles avec le fournisseur d'agendas:
Action | URI | Description | Bonus |
---|---|---|---|
VIEW |
CalendarContract.CONTENT_URI .
Pour obtenir un exemple d'utilisation de cet intent, consultez Utiliser des intents pour afficher les données d'agenda.
|
Ouvrir l'agenda à l'heure spécifiée par <ms_since_epoch> . |
Aucune |
Events.CONTENT_URI .
Pour obtenir un exemple d'utilisation de cet intent, consultez Utiliser des intents pour afficher les données d'agenda.
|
Affichez l'événement spécifié par <event_id> . |
CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME |
|
EDIT |
Events.CONTENT_URI .
Pour obtenir un exemple d'utilisation de cet intent, consultez la section Utiliser un intent pour modifier un événement.
|
Modifiez l'événement spécifié par <event_id> . |
CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME |
EDIT INSERT |
Events.CONTENT_URI .
Pour obtenir un exemple d'utilisation de cet intent, consultez la section Utiliser un intent pour insérer un événement.
|
Créez un événement. | tous les extras répertoriés dans le tableau ci-dessous. |
Le tableau suivant liste les extras d'intent compatibles avec le fournisseur d'agendas:
Intent supplémentaire | Description |
---|---|
Events.TITLE |
Nom de l'événement. |
CalendarContract.EXTRA_EVENT_BEGIN_TIME |
Heure de début de l'événement, en millisecondes, à partir de l'epoch. |
CalendarContract.EXTRA_EVENT_END_TIME |
Heure de fin de l'événement en millisecondes depuis l'epoch. |
CalendarContract.EXTRA_EVENT_ALL_DAY |
Booléen qui indique que l'événement dure toute la journée. La valeur peut être true ou false . |
Events.EVENT_LOCATION |
Lieu de l'événement. |
Events.DESCRIPTION |
Description de l'événement. |
Intent.EXTRA_EMAIL |
Adresses e-mail des personnes à inviter sous forme de liste d'éléments séparés par une virgule. |
Events.RRULE |
Règle de récurrence de l'événement. |
Events.ACCESS_LEVEL |
Indique si l'événement est privé ou public. |
Events.AVAILABILITY |
Indique s'il s'agit d'un créneau occupé ou d'un temps libre qui peut être programmé. |
Les sections suivantes décrivent comment utiliser ces intents.
Utiliser un intent pour insérer un événement
L'utilisation de l'intent INSERT
permet à votre application de transmettre la tâche d'insertion d'événements à Agenda lui-même.
Avec cette approche, votre application n'a même pas besoin d'inclure l'autorisation WRITE_CALENDAR
dans son fichier manifeste.
Lorsque les utilisateurs exécutent une application utilisant cette approche, celle-ci les envoie à Agenda pour finaliser l'ajout de l'événement. L'intent INSERT
utilise des champs supplémentaires pour préremplir un formulaire avec les détails de l'événement dans Agenda. Les utilisateurs peuvent ensuite annuler l'événement, modifier le formulaire selon leurs besoins ou l'enregistrer dans leur agenda.
Voici un extrait de code permettant de planifier un événement le 19 janvier 2012, de 7 h 30 à 8 h 30. Notez les points suivants à propos de cet extrait de code :
- Il spécifie
Events.CONTENT_URI
comme URI. - Elle utilise les champs supplémentaires
CalendarContract.EXTRA_EVENT_BEGIN_TIME
etCalendarContract.EXTRA_EVENT_END_TIME
pour préremplir le formulaire avec l'heure de l'événement. Les valeurs de ces heures doivent être exprimées en millisecondes UTC à partir de l'epoch. - Il utilise le champ supplémentaire
Intent.EXTRA_EMAIL
pour fournir une liste d'invités séparés par une virgule, spécifiés par leur adresse 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);
Modifier un événement à l'aide d'un intent
Vous pouvez mettre à jour un événement directement, comme indiqué dans Mettre à jour des événements. Toutefois, l'utilisation de l'intent EDIT
permet à une application qui n'est pas autorisée de transmettre la modification des événements à l'application Agenda.
Lorsque les utilisateurs ont fini de modifier leur événement dans Agenda, ils sont renvoyés à l'application d'origine.
Voici un exemple d'intent qui définit un nouveau titre pour un événement spécifié et permet aux utilisateurs de le modifier dans 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);
Utiliser des intents pour afficher les données d'agenda
Le fournisseur d'agendas propose deux façons d'utiliser l'intent VIEW
:
- Pour ouvrir le calendrier à une date spécifique.
- Pour afficher un événement :
Voici un exemple montrant comment ouvrir l'agenda à une date précise:
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);
Voici un exemple illustrant comment ouvrir un événement pour l'afficher:
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);
Adaptateurs de synchronisation
Il n'existe que des différences mineures dans la manière dont une application et un adaptateur de synchronisation accèdent au fournisseur d'agendas:
- Un adaptateur de synchronisation doit spécifier qu'il s'agit d'un adaptateur de synchronisation en définissant
CALLER_IS_SYNCADAPTER
surtrue
. - Un adaptateur de synchronisation doit fournir
ACCOUNT_NAME
etACCOUNT_TYPE
comme paramètres de requête dans l'URI. - Un adaptateur de synchronisation dispose d'un accès en écriture à plus de colonnes qu'une application ou un widget.
Par exemple, une application ne peut modifier que quelques caractéristiques d'un agenda, telles que son nom, son nom à afficher, ses paramètres de visibilité et si l'agenda est synchronisé ou non. En comparaison, un adaptateur de synchronisation peut accéder non seulement à ces colonnes, mais aussi à bien d'autres colonnes (couleur de l'agenda, fuseau horaire, niveau d'accès, lieu, etc.).
Toutefois, un adaptateur de synchronisation est limité aux paramètres
ACCOUNT_NAME
etACCOUNT_TYPE
qu'il a spécifiés.
Voici une méthode d'assistance que vous pouvez utiliser pour renvoyer un URI à utiliser avec un adaptateur de synchronisation:
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(); }