Présentation de Calendar Provider

Le fournisseur d'agenda est un dépôt des événements d'agenda d'un utilisateur. L'API Calendar Provider vous permet d'exécuter des opérations de requête, d'insertion, de mise à jour et de suppression sur 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 selon le type de programme qui effectue les appels. Ce document se concentre 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 des utilisateurs. Pour faciliter l'exécution d'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 insérer, afficher et modifier des événements. L'utilisateur interagit avec l'application Agenda, puis revient à l'application d'origine. Par conséquent, votre application n'a 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 de calendrier) présentent généralement les données sous la forme d'un ensemble de tables basées sur un modèle de base de données relationnelle, où chaque ligne est un enregistrement et chaque colonne est une donnée d'un type et d'une signification particuliers. Via 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 contenant 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 d'eux. Tous les URI des fournisseurs commencent par la chaîne "content://". Cela indique que les données sont contrôlées par un fournisseur de contenu. Le fournisseur de calendrier définit des constantes pour les URI de chacune de ses classes (tables). Ces URI sont au format <class>.CONTENT_URI. Par exemple, Events.CONTENT_URI.

La figure 1 présente une représentation graphique du modèle de données du fournisseur d'agenda. Il affiche les principales tables et les champs qui les associent entre eux.

Modèle de données du fournisseur d&#39;agenda

Figure 1 : Modèle de données du fournisseur d'agenda.

Un utilisateur peut avoir plusieurs agendas, et différents 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, listées ci-dessous.

Table (classe) Description

CalendarContract.Calendars

Ce tableau contient les informations spécifiques à l’agenda. Chaque ligne de cette table contient les détails d'un seul agenda, tels que son nom, sa couleur, ses informations de synchronisation, etc.
CalendarContract.Events Ce tableau contient les informations spécifiques à l'événement. Chaque ligne de ce tableau contient les informations d'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. Chacune d'elles possède un EVENT_ID qui fait référence à _ID dans la table "Événements".
CalendarContract.Instances Ce tableau contient les heures de début et de fin de chaque occurrence d'un événement. Chaque ligne de ce tableau représente une occurrence d'événement unique. Pour les événements ponctuels, il existe un mappage individuel des instances aux événements. Pour les événements récurrents, plusieurs lignes sont automatiquement générées et correspondent à plusieurs occurrences de cet événement.
CalendarContract.Attendees Ce tableau contient les informations sur les participants à l'événement (invités). Chaque ligne représente un seul invité d'un événement. Elle spécifie le type d'invité et sa réponse de participation à l'événement.
CalendarContract.Reminders Ce tableau contient les données d'alerte/de notification. Chaque ligne représente une seule alerte 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 quelques 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. En même temps, il est important de proposer une bonne expérience utilisateur et de protéger l'intégrité du calendrier et de ses données. Pour ce faire, 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'agenda, vous devez disposer des autorisations appropriées. Toutefois, si vous ne créez pas d'application d'agenda ou d'adaptateur de synchronisation complets, 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 à 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 dans un formulaire prérempli. Une fois qu'il a terminé, il est redirigé vers votre application. En concevant votre application pour effectuer des opérations courantes via Agenda, vous fournissez aux utilisateurs une interface utilisateur cohérente et robuste. Il s'agit de l'approche recommandée. Pour en savoir plus, consultez la section Intents Agenda.
  • Adaptateurs de synchronisation Un adaptateur de synchronisation synchronise les données du calendrier sur l'appareil d'un utilisateur avec un autre serveur ou une autre source de données. Les tables CalendarContract.Calendars et CalendarContract.Events contiennent des colonnes réservées aux adaptateurs de synchronisation. Le fournisseur et les applications ne doivent pas les modifier. En fait, elles ne sont pas visibles, sauf si elles 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 du calendrier, une application doit inclure l'autorisation READ_CALENDAR dans son fichier manifeste. Elle 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'agenda suivantes sont accessibles en écriture à la fois par une application et par un adaptateur de synchronisation. Pour obtenir la liste complète des champs acceptés, consultez la documentation de référence CalendarContract.Calendars.

Constante Description
NAME Nom de l'agenda.
CALENDAR_DISPLAY_NAME Nom de cet agenda affiché à l'utilisateur.
VISIBLE Valeur booléenne indiquant si le calendrier est sélectionné pour être affiché. Une valeur de 0 indique que les événements associés à cet agenda ne doivent pas s'afficher. La valeur 1 indique que les événements associés à cet agenda doivent être affichés. 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 si ses événements doivent être stockés sur l'appareil. Une valeur de 0 indique de ne pas synchroniser cet agenda ni de ne pas stocker ses événements sur l'appareil. Une valeur de 1 indique que les événements de cet agenda doivent être synchronisés et stockés 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 qu'en raison de ses ACCOUNT_NAME et de son ACCOUNT_TYPE. ACCOUNT_TYPE est la chaîne correspondant à l'authentificateur de compte utilisé lors de l'enregistrement du compte 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 montrant comment obtenir les agendas appartenant à un utilisateur particulier. Par souci de simplicité, dans cet exemple, l'opération de requête est affichée dans le thread de l'interface utilisateur ("thread principal"). En pratique, cela doit être effectué dans un thread asynchrone plutôt que sur le thread principal. Pour en savoir plus, consultez la section Chargeurs. Si vous ne lisez pas seulement les données, mais que vous les modifiez, 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 contenant les 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 non seulement ceux qui lui appartiennent, omettez 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 définies 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 être le _ID du calendrier. 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 qu'en tant qu'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 du calendrier en tant qu'adaptateur de synchronisation, à l'aide d'un ACCOUNT_TYPE de ACCOUNT_TYPE_LOCAL. ACCOUNT_TYPE_LOCAL est un type de compte spécial pour les agendas qui ne sont pas associés à un compte d'appareil. Les agendas de ce type ne sont pas synchronisés avec un serveur. Pour en savoir plus sur les adaptateurs de synchronisation, consultez la page Adaptateurs de synchronisation.

Tableau des événements

La table CalendarContract.Events contient les détails de chaque événement. Pour ajouter, mettre à jour ou supprimer des événements, une application doit inclure l'autorisation WRITE_CALENDAR dans son fichier manifeste.

Les colonnes "Événements" suivantes peuvent être écrites à la fois 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 CalendarContract.Events.

Constante Description
CALENDAR_ID _ID de l'agenda auquel appartient l'événement.
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 de début de l'événement 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, une valeur de "PT1H" indique que l'événement doit durer une heure, et une valeur de "P2W" indique une durée de deux semaines.
ALL_DAY Une valeur de 1 indique que cet événement occupe toute la journée, comme 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 à tout moment au cours de la journée.
RRULE Règle de récurrence pour le format de l'événement. Par exemple, "FREQ=WEEKLY;COUNT=10;WKST=SU". Pour en savoir plus, cliquez ici.
RDATE Dates de récurrence de l'événement. Vous utilisez généralement RDATE conjointement avec RRULE pour définir un ensemble agrégé d'occurrences répétées. Pour en savoir plus, consultez la spécification RFC 5545.
AVAILABILITY Indique si cet événement est considéré comme un temps occupé ou s'il s'agit d'un temps libre pouvant être planifié.
GUESTS_CAN_MODIFY Indique si les invités peuvent modifier l'événement.
GUESTS_CAN_INVITE_OTHERS Indique si les invités peuvent inviter 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.

Voici les règles à respecter pour insérer un événement:

Voici un exemple d'insertion d'un événement. Pour plus de simplicité, cette opération est effectuée dans le thread d'UI. 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 de l'événement après sa création. Il s'agit du moyen le plus simple d'obtenir un ID d'événement. Vous avez souvent besoin de l'ID de l'événement pour effectuer d'autres opérations dans l'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 directement les événements. Pour mettre à jour un événement, vous pouvez fournir le _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 le _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. Il 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 à l'aide de son _ID en tant qu'ID ajouté à l'URI ou à l'aide de la sélection standard. Si vous utilisez un ID ajouté, vous ne pouvez pas non plus effectuer de sélection. Il existe deux versions de la suppression: en tant qu'application et en tant qu'adaptateur de synchronisation. Une suppression d'application définit la colonne deleted sur 1. Ce flag indique à l'adaptateur de synchronisation que la ligne a été supprimée et que cette suppression doit être propagée vers le serveur. La suppression d'un adaptateur de synchronisation supprime l'événement de la base de données, ainsi que toutes les données qui lui sont 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);

Tableau des participants

Chaque ligne du tableau CalendarContract.Attendees représente un participant ou un invité à un événement. L'appel de query() renvoie la liste des participants à l'événement avec le EVENT_ID donné. Cet EVENT_ID doit correspondre au _ID d'un événement particulier.

Le tableau suivant liste les champs enregistrables. Lorsque vous insérez un participant, vous devez les inclure tous, à l'exception de ATTENDEE_NAME.

Constante Description
EVENT_ID ID de l'événement.
ATTENDEE_NAME Nom du participant.
ATTENDEE_EMAIL Adresse e-mail de l'participant.
ATTENDEE_RELATIONSHIP

Relation de l'utilisateur avec l'événement. L'un des éléments suivants:

ATTENDEE_TYPE

Type de participant. Au choix:

ATTENDEE_STATUS

État de participation de l'utilisateur. L'un des éléments suivants:

Ajouter des participants

Voici un exemple d'ajout d'un seul participant à un événement. Notez que 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 seul rappel pour un événement. L'appel de query() renvoie une liste de rappels pour l'événement avec l'élément EVENT_ID donné.

Le tableau suivant répertorie les champs accessibles en écriture pour les rappels. Ils doivent tous ê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 la table CalendarContract.Calendars. Pour en savoir plus, consultez ALLOWED_REMINDERS.

Constante Description
EVENT_ID ID de l'événement.
MINUTES Nombre de minutes avant l'événement au cours duquel le rappel doit se déclencher.
METHOD

Méthode d'alarme, telle qu'elle est définie sur le serveur. L'un des éléments suivants:

Ajoutez des rappels

Cet exemple ajoute un rappel à 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);

Tableau 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 occurrence d'événement unique. La table des instances n'est pas accessible en écriture et ne permet que d'interroger des occurrences d'événements.

Le tableau suivant liste certains des champs sur lesquels vous pouvez interroger 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 de fin 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 du calendrier.
EVENT_ID _ID de l'événement pour cette instance.
START_DAY Jour julien de début de l'instance, par rapport au fuseau horaire du calendrier.
START_MINUTE Minute de début de l'instance mesurée à partir de minuit, par rapport au fuseau horaire du calendrier.

Interroger la table des instances

Pour interroger la table des instances, vous devez spécifier une plage horaire pour la requête dans l'URI. Dans cet exemple, CalendarContract.Instances accède 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 en interrogeant le tableau CalendarContract.Instances brut.

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 Agenda

Votre application n'a pas besoin 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 à cette application. Le tableau suivant répertorie les intents compatibles avec le fournisseur de calendrier:

Action URI Description Bonus

VIEW

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

Vous pouvez également faire référence à l'URI avec CalendarContract.CONTENT_URI. Pour obtenir un exemple d'utilisation de cet intent, consultez Utiliser des intents pour afficher les données d'agenda.
Ouvre l'agenda à l'heure spécifiée par <ms_since_epoch>. Aucun.

VIEW

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

Vous pouvez également faire référence à l'URI avec Events.CONTENT_URI. Pour obtenir un exemple d'utilisation de cet intent, consultez Utiliser des intents pour afficher les données d'agenda.
Afficher l'événement spécifié par <event_id>. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

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

Vous pouvez également faire référence à l'URI avec 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

content://com.android.calendar/events

Vous pouvez également faire référence à l'URI avec Events.CONTENT_URI. Pour obtenir un exemple d'utilisation de cet intent, consultez Utiliser un intent pour insérer un événement.
Créez un événement. Tous les extras indiqués dans le tableau ci-dessous.

Le tableau suivant répertorie les extras d'intent compatibles avec le fournisseur d'agenda:

Intent Extra 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 Valeur booléenne indiquant qu'un é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 Si cet événement est considéré comme étant occupé ou s'il s'agit de temps libre, qu'il est possible de planifier.

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énement à Agenda lui-même. Avec cette approche, l'autorisation WRITE_CALENDAR n'a même pas besoin d'être incluse dans le fichier manifeste de votre application.

Lorsque les utilisateurs exécutent une application qui utilise cette approche, l'application les redirige vers Agenda pour qu'ils terminent d'ajouter 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 l'agenda. Les utilisateurs peuvent ensuite annuler l'événement, modifier le formulaire si nécessaire ou l'enregistrer dans leur agenda.

Voici un extrait de code qui planifie un événement le 19 janvier 2012, qui se déroule de 7h30 à 8h30. Notez les points suivants concernant cet extrait de code :

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

Utiliser un intent pour modifier un événement

Vous pouvez modifier un événement directement, comme décrit dans la section Modifier des événements. Toutefois, l'utilisation de l'intent EDIT permet à une application qui n'est pas autorisée à transférer la modification d'é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 l'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 de l'agenda

Le fournisseur de calendrier propose deux méthodes différentes pour utiliser l'intent VIEW:

  • Ouvrir l'agenda à une date précise
  • Pour afficher un événement :

Voici un exemple montrant comment ouvrir l'agenda à une date particulière:

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 le consulter:

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 de légères différences dans la façon dont une application et un adaptateur de synchronisation accèdent au fournisseur de calendrier:

  • Un adaptateur de synchronisation doit spécifier qu'il s'agit d'un adaptateur de synchronisation en définissant CALLER_IS_SYNCADAPTER sur true.
  • Un adaptateur de synchronisation doit fournir les éléments ACCOUNT_NAME et ACCOUNT_TYPE en tant que 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, comme son nom, son nom à afficher, son paramètre de visibilité et si l'agenda est synchronisé. À titre de comparaison, un adaptateur de synchronisation peut accéder non seulement à ces colonnes, mais à de nombreuses autres, telles que la couleur de l'agenda, le fuseau horaire, le niveau d'accès, l'emplacement, etc. Toutefois, un adaptateur de synchronisation est limité aux ACCOUNT_NAME et ACCOUNT_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();
 }