Panoramica del fornitore di calendari

Il provider di calendario è un repository per gli eventi nel calendario di un utente. L'API Calendar Provider consente di eseguire operazioni di query, inserimento, aggiornamento ed eliminazione su calendari, eventi, partecipanti, promemoria e così via.

L'API Calendar Provider può essere utilizzata da applicazioni e adattatori di sincronizzazione. Le regole variano a seconda del tipo di programma che effettua le chiamate. Questo documento si concentra principalmente sull'utilizzo dell'API Calendar Provider come applicazione. Per approfondire le differenze tra gli adattatori di sincronizzazione, consulta Adattatori di sincronizzazione.

Normalmente, per leggere o scrivere dati di calendario, il file manifest di un'applicazione deve includere le autorizzazioni appropriate, descritte in Autorizzazioni dell'utente. Per semplificare l'esecuzione di operazioni comuni, CalendarProvider offre un insieme di intent, come descritto in Intent di Calendar. Questi intent indirizzano gli utenti all'applicazione Calendar per inserire, visualizzare e modificare gli eventi. L'utente interagisce con l'applicazione Calendar e poi rientra nell'applicazione originale. Pertanto, la tua applicazione non deve richiedere autorizzazioni né fornire un'interfaccia utente per visualizzare o creare eventi.

Nozioni di base

I fornitori di contenuti archiviano i dati e li rendono accessibili alle applicazioni. I fornitori di contenuti offerti dalla piattaforma Android (incluso il fornitore di calendario) in genere mostrano i dati come un insieme di tabelle basate su un modello di database relazionale, in cui ogni riga è un record e ogni colonna è costituita da dati di un determinato tipo e significato. Tramite l'API Calendar Provider, le applicazioni e gli adattatori di sincronizzazione possono ottenere l'accesso in lettura/scrittura alle tabelle di database che contengono i dati del calendario di un utente.

Ogni fornitore di contenuti espone un URI pubblico (racchiuso in un oggettoUri ) che identifica in modo univoco il suo set di dati. Un fornitore di contenuti che controlla più set di dati (più tabelle) espone un URI separato per ciascuno. Tutti gli URI per i fornitori iniziano con la stringa "content://". Questo indica che i dati sono controllati da un fornitore di contenuti. CalendarProvider definisce le costanti per gli URI di ciascuna delle sue classi (tabelle). Questi URI sono nel formato <class>.CONTENT_URI. Ad esempio, Events.CONTENT_URI.

La Figura 1 mostra una rappresentazione grafica del modello di dati del fornitore di calendario. Mostra le tabelle principali e i campi che le collegano tra loro.

Modello dei dati del fornitore del calendario

Figura 1. Modello di dati del fornitore di calendario.

Un utente può avere più calendari e calendari diversi possono essere associati a tipi diversi di account (Google Calendar, Exchange e così via).

CalendarContract definisce il modello di dati delle informazioni relative a calendari ed eventi. Questi dati vengono archiviati in diverse tabelle, elencate di seguito.

Tabella (classe) Descrizione

CalendarContract.Calendars

Questa tabella contiene le informazioni specifiche del calendario. Ogni riga di questa tabella contiene i dettagli di un singolo calendario, ad esempio il nome, il colore, le informazioni di sincronizzazione e così via.
CalendarContract.Events Questa tabella contiene le informazioni specifiche dell'evento. Ogni riga di questa tabella contiene le informazioni relative a un singolo evento, ad esempio titolo, località, ora di inizio, ora di fine e così via. L'evento può verificarsi una sola volta o più volte. Partecipanti, promemoria e proprietà estese vengono memorizzati in tabelle separate. Ognuno ha un EVENT_ID che fa riferimento a _ID nella tabella Eventi.
CalendarContract.Instances Questa tabella contiene l'ora di inizio e di fine di ogni occorrenza di un evento. Ogni riga di questa tabella rappresenta una singola occorrenza di evento. Per gli eventi una tantum è presente una mappatura 1:1 delle istanze agli eventi. Per gli eventi ricorrenti, vengono generate automaticamente più righe che corrispondono a più occorrenze dell'evento.
CalendarContract.Attendees Questa tabella contiene le informazioni relative ai partecipanti (ospiti) dell'evento. Ogni riga rappresenta un singolo invitato di un evento. Specifica il tipo di ospite e la sua risposta alla partecipazione all'evento.
CalendarContract.Reminders Questa tabella contiene i dati di avviso/notifica. Ogni riga rappresenta un singolo avviso per un evento. Un evento può avere più promemoria. Il numero massimo di promemoria per evento è specificato in MAX_REMINDERS, che viene impostato dall'adattatore di sincronizzazione proprietario del calendario in questione. I promemoria vengono specificati in minuti prima dell'evento e hanno un metodo che determina il modo in cui l'utente verrà avvisato.

L'API Calendar Provider è progettata per essere flessibile e potente. Allo stesso tempo, è importante offrire un'esperienza utente positiva e proteggere l'integrità del calendario e dei relativi dati. A tal fine, ecco alcuni aspetti da tenere presenti quando utilizzi l'API:

  • Inserimento, aggiornamento e visualizzazione di eventi nel calendario. Per inserire, modificare e leggere direttamente gli eventi dal provider di calendario, devi disporre delle autorizzazioni appropriate. Tuttavia, se non stai creando un'applicazione di calendario o un'apposita funzionalità di sincronizzazione, non è necessario richiedere queste autorizzazioni. In alternativa, puoi utilizzare gli intent supportati dall'applicazione Calendar di Android per trasferire le operazioni di lettura e scrittura a quell'applicazione. Quando utilizzi gli intent, la tua applicazione indirizza gli utenti all'applicazione Calendar per eseguire l'operazione desiderata in un modulo precompilato. Al termine, vengono reindirizzati alla tua applicazione. Progettando l'applicazione in modo da eseguire operazioni comuni tramite Calendar, fornisci agli utenti un'interfaccia utente coerente e solida. Questo è l'approccio consigliato. Per ulteriori informazioni, consulta Intent di Calendar.
  • Sincronizza gli adattatori. Un adattatore di sincronizzazione sincronizza i dati del calendario sul dispositivo di un utente con un altro server o un'altra origine dati. Nelle tabelle CalendarContract.Calendars e CalendarContract.Events sono presenti colonne riservate agli adattatori di sincronizzazione. Il provider e le applicazioni non devono modificarli. Infatti, non sono visibili a meno che non venga eseguito l'accesso come adattatore di sincronizzazione. Per ulteriori informazioni sugli adattatori di sincronizzazione, consulta Adattatori di sincronizzazione.

Autorizzazioni utente

Per leggere i dati del calendario, un'applicazione deve includere l'autorizzazione READ_CALENDAR nel file manifest. Deve includere l'autorizzazione WRITE_CALENDAR per eliminare, inserire o aggiornare i dati 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>

Tabella Calendari

La tabella CalendarContract.Calendars contiene i dettagli per i singoli calendari. Le seguenti colonne Calendari sono scrivibili sia da un'applicazione sia da un adattatore di sincronizzazione. Per un elenco completo dei campi supportati, consulta la documentazione di riferimentoCalendarContract.Calendars.

Costante Descrizione
NAME Il nome del calendario.
CALENDAR_DISPLAY_NAME Il nome di questo calendario visualizzato all'utente.
VISIBLE Un valore booleano che indica se il calendario è selezionato per essere visualizzato. Un valore di 0 indica che gli eventi associati a questo calendario non devono essere mostrati. Un valore pari a 1 indica che gli eventi associati a questo calendario devono essere visualizzati. Questo valore influisce sulla generazione di righe nella tabella CalendarContract.Instances.
SYNC_EVENTS Un valore booleano che indica se il calendario deve essere sincronizzato e se i suoi eventi devono essere archiviati sul dispositivo. Un valore pari a 0 indica di non sincronizzare questo calendario o di non memorizzare i relativi eventi sul dispositivo. Un valore pari a 1 indica di sincronizzare gli eventi per questo calendario e di memorizzarli sul dispositivo.

Includi un tipo di account per tutte le operazioni

Se esegui una query su un Calendars.ACCOUNT_NAME, devi includere anche Calendars.ACCOUNT_TYPE nella selezione. Questo perché un determinato account viene considerato unico solo se sono presenti sia ACCOUNT_NAME sia ACCOUNT_TYPE. ACCOUNT_TYPE è la stringa corrispondente all'autenticatore dell'account utilizzato durante la registrazione dell'account con AccountManager. Esiste anche un tipo speciale di account chiamato ACCOUNT_TYPE_LOCAL per i calendari non associati a un account dispositivo. ACCOUNT_TYPE_LOCAL account non vengono sincronizzati.

Eseguire una query su un calendario

Ecco un esempio che mostra come recuperare i calendari di proprietà di un determinato utente. Per semplicità, in questo esempio l'operazione di query viene mostrata nel thread dell'interfaccia utente ("thread principale"). In pratica, questa operazione deve essere eseguita in un thread asincrono anziché nel thread principale. Per ulteriori informazioni, consulta Caricatori. Se non solo leggi i dati, ma li modifichi, 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;

Nella parte successiva dell'esempio, viene costruita la query. La selezione specifica i criteri per la query. In questo esempio, la query cerca i calendari con ACCOUNT_NAME"hera@example.com", ACCOUNT_TYPE"com.example" e OWNER_ACCOUNT"hera@example.com". Se vuoi visualizzare tutti i calendari visualizzati da un utente, non solo quelli di sua proprietà, ometti OWNER_ACCOUNT. La query restituisce un oggetto Cursor che puoi utilizzare per attraversare il set di risultati restituito dalla query del database. Per ulteriori informazioni sull'utilizzo delle query nei fornitori di contenuti, consulta Fornitori di contenuti.

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

Nella sezione successiva viene utilizzato il cursore per scorrere il set di risultati. Utilizza le costanti configurate all'inizio dell'esempio per restituire i valori per ogni 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...

   ...
}

Modificare un calendario

Per eseguire un aggiornamento di un calendario, puoi fornire il _ID del calendario come ID aggiunto all'Uri (withAppendedId()) o come primo elemento di selezione. La selezione deve iniziare con "_id=?" e il primo "_id=?" deve essere il _ID del calendario.selectionArg Puoi anche eseguire gli aggiornamenti codificando l'ID nell'URI. Questo esempio modifica il nome visualizzato di un calendario utilizzando l'approccio (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);

Inserire un calendario

I calendari sono progettati per essere gestiti principalmente da un adattatore di sincronizzazione, quindi dovresti inserire i nuovi calendari solo come adattatore di sincronizzazione. Nella maggior parte dei casi, le applicazioni possono apportare modifiche superficiali ai calendari, ad esempio modificare il nome visualizzato. Se un'applicazione deve creare un calendario locale, può farlo eseguendo l'inserimento del calendario come adattatore di sincronizzazione, usando un ACCOUNT_TYPE di ACCOUNT_TYPE_LOCAL. ACCOUNT_TYPE_LOCAL è un tipo di account speciale per i calendari non associati a un account dispositivo. I calendari di questo tipo non vengono sincronizzati con un server. Per una discussione sugli adattatori di sincronizzazione, vedi Adattatori di sincronizzazione.

Tabella Eventi

La tabella CalendarContract.Events contiene i dettagli per i singoli eventi. Per aggiungere, aggiornare o eliminare eventi, un'applicazione deve includere l'autorizzazione WRITE_CALENDAR nel suo file manifest.

Le seguenti colonne Eventi sono scrivibili sia da un'applicazione sia da un adattatore di sincronizzazione. Per un elenco completo dei campi supportati, consulta la documentazione di riferimento CalendarContract.Events.

Costante Descrizione
CALENDAR_ID Il _ID del calendario a cui appartiene l'evento.
ORGANIZER Indirizzo email dell'organizzatore (proprietario) dell'evento.
TITLE Il titolo dell'evento.
EVENT_LOCATION Luogo in cui si svolge l'evento.
DESCRIPTION La descrizione dell'evento.
DTSTART L'ora di inizio dell'evento in millisecondi UTC dall'epoca.
DTEND L'ora di fine dell'evento in millisecondi UTC dall'epoca.
EVENT_TIMEZONE Il fuso orario dell'evento.
EVENT_END_TIMEZONE Il fuso orario dell'ora di fine dell'evento.
DURATION La durata dell'evento nel formato RFC5545. Ad esempio, un valore "PT1H" indica che l'evento deve durare un'ora, mentre un valore "P2W" indica una durata di due settimane.
ALL_DAY Un valore pari a 1 indica che questo evento occupa l'intero giorno, come definito dal fuso orario locale. Un valore pari a 0 indica che si tratta di un evento regolare che può iniziare e terminare in qualsiasi momento del giorno.
RRULE La regola di ripetizione per il formato dell'evento. Ad esempio, "FREQ=WEEKLY;COUNT=10;WKST=SU". Puoi trovare altri esempi qui.
RDATE Le date di ricorrenza dell'evento. In genere, RDATE viene utilizzato in combinazione con RRULE per definire un insieme aggregato di occorrenze ripetute. Per ulteriori informazioni, consulta la specifica RFC5545.
AVAILABILITY Se questo evento viene considerato come un orario occupato o come tempo libero che può essere pianificato,
GUESTS_CAN_MODIFY Se gli invitati possono modificare l'evento.
GUESTS_CAN_INVITE_OTHERS Indica se gli ospiti possono invitare altri ospiti.
GUESTS_CAN_SEE_GUESTS Indica se gli invitati possono vedere l'elenco dei partecipanti.

Aggiungi eventi

Quando l'applicazione inserisce un nuovo evento, ti consigliamo di utilizzare un intent INSERT, come descritto in Utilizzare un intent per inserire un evento. Tuttavia, se necessario, puoi inserire gli eventi direttamente. In questa sezione viene descritto come fare.

Di seguito sono riportate le regole per l'inserimento di un nuovo evento:

Ecco un esempio di inserimento di un evento. Per semplicità, questa operazione viene eseguita nel thread dell'interfaccia utente. In pratica, le inserzioni e gli aggiornamenti devono essere eseguiti in un thread asincrono per spostare l'azione in un thread in background. Per ulteriori informazioni, vedi 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:in questo esempio viene acquisito l'ID evento dopo la creazione dell'evento. Questo è il modo più semplice per ottenere un ID evento. Spesso hai bisogno dell'ID evento per eseguire altre operazioni nel calendario, ad esempio per aggiungere partecipanti o promemoria a un evento.

Eventi di aggiornamento

Quando la tua applicazione vuole consentire all'utente di modificare un evento, ti consigliamo di utilizzare un Intent EDIT, come descritto in Utilizzare un Intent per modificare un evento. Tuttavia, se necessario, puoi modificare direttamente gli eventi. Per eseguire un aggiornamento di un evento, puoi fornire il _ID dell'evento come ID aggiunto all'URI (withAppendedId()) o come primo elemento di selezione. La selezione deve iniziare con "_id=?" e il primo selectionArg deve essere il _ID dell'evento. Puoi anche eseguire aggiornamenti utilizzando una selezione senza ID. Ecco un esempio di aggiornamento di un evento. Cambia il titolo dell'evento utilizzando l'approccio 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);

Elimina eventi

Per eliminare un evento, puoi utilizzare il relativo _ID come ID aggiunto all'URI oppure utilizzare la selezione standard. Se utilizzi un ID aggiunto, non puoi nemmeno effettuare una selezione. Esistono due versioni dell'eliminazione: come applicazione e come adattatore di sincronizzazione. Un'eliminazione applicazioni imposta la colonna deleted su 1. Questo flag indica all'adattatore di sincronizzazione che la riga è stata eliminata e che questa eliminazione deve essere propagata al server. L'eliminazione di un'entità di sincronizzazione rimuove l'evento dal database insieme a tutti i dati associati. Ecco un esempio di applicazione che elimina un evento tramite il relativo _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);

Tabella Partecipanti

Ogni riga della tabella CalendarContract.Attendees rappresenta un singolo partecipante o ospite di un evento. La chiamata query() restituisce un elenco di partecipanti per l'evento con il EVENT_ID specificato. Questo EVENT_ID deve corrispondere al _ID di un determinato evento.

Nella tabella seguente sono elencati i campi scrivibili. Quando inserisci un nuovo partecipante, devi includerli tutti tranne ATTENDEE_NAME.

Costante Descrizione
EVENT_ID L'ID dell'evento.
ATTENDEE_NAME Il nome del partecipante.
ATTENDEE_EMAIL L'indirizzo email del partecipante.
ATTENDEE_RELATIONSHIP

Il rapporto tra il partecipante e l'evento. Uno dei seguenti:

ATTENDEE_TYPE

Il tipo di partecipante. Uno dei seguenti:

ATTENDEE_STATUS

Lo stato di presenza del partecipante. Uno dei seguenti:

Aggiungi partecipanti

Ecco un esempio in cui viene aggiunto un singolo partecipante a un evento. Tieni presente cheEVENT_ID è obbligatorio:

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

Tabella dei promemoria

Ogni riga della tabella CalendarContract.Reminders rappresenta un singolo promemoria per un evento. La chiamata di query() restituisce un elenco di promemoria per l'evento con EVENT_ID specificato.

Nella tabella seguente sono elencati i campi scrivibili per i promemoria. Tutti devono essere inclusi quando inserisci un nuovo promemoria. Tieni presente che gli adattatori di sincronizzazione specificano i tipi di promemoria supportati nella tabella CalendarContract.Calendars. Per maggiori dettagli, visita la pagina ALLOWED_REMINDERS.

Costante Descrizione
EVENT_ID L'ID dell'evento.
MINUTES I minuti prima dell'evento in cui deve essere attivato il promemoria.
METHOD

Il metodo di sveglia, impostato sul server. Uno dei seguenti:

Aggiungi promemoria

In questo esempio viene aggiunto un promemoria a un evento. Il promemoria viene attivato 15 minuti prima dell'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);

Tabella delle istanze

La tabella CalendarContract.Instances contiene l'ora di inizio e di fine delle occorrenze di un evento. Ogni riga di questa tabella rappresenta una singola occorrenza di evento. La tabella delle istanze non è scrivibile e fornisce solo un modo per eseguire query sulle occorrenze degli eventi.

La tabella seguente elenca alcuni dei campi su cui puoi eseguire query per un'istanza. Tieni presente che il fuso orario è definito da KEY_TIMEZONE_TYPE e KEY_TIMEZONE_INSTANCES.

Costante Descrizione
BEGIN L'ora di inizio dell'istanza, in millisecondi UTC.
END L'ora di fine dell'istanza, in millisecondi UTC.
END_DAY Il giorno di fine giuliano dell'istanza, rispetto al fuso orario del calendario.
END_MINUTE Il minuto di fine dell'istanza misurato a partire dalla mezzanotte del fuso orario di Calendar.
EVENT_ID Il _ID dell'evento per questa istanza.
START_DAY Il giorno di inizio giuliano dell'istanza, relativo al fuso orario del calendario.
START_MINUTE Il minuto di inizio dell'istanza misurato da mezzanotte, rispetto al fuso orario del calendario.

Esegui una query sulla tabella delle istanze

Per eseguire una query sulla tabella Istanze, devi specificare un intervallo di tempo per la query nell'URI. In questo esempio, CalendarContract.Instances accede al campo TITLE tramite l'implementazione dell'interfaccia CalendarContract.EventsColumns. In altre parole, TITLE viene restituito attraverso una visualizzazione del database, non attraverso l'esecuzione di query sulla tabella CalendarContract.Instances non elaborata.

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

Intent di Calendar

L'applicazione non richiede le autorizzazioni per leggere e scrivere dati di calendario. Può invece utilizzare gli intent supportati dall'applicazione Calendar di Android per trasferire le operazioni di lettura e scrittura a quell'applicazione. Nella tabella seguente sono elencati gli intent supportati dal provider di Calendar:

Azione URI Descrizione Extra

VIEW

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

Puoi anche fare riferimento all'URI con CalendarContract.CONTENT_URI. Per un esempio di utilizzo di questo intent, consulta Utilizzare gli intent per visualizzare i dati del calendario.
Apri il calendario all'ora specificata da <ms_since_epoch>. Nessuno.

VIEW

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

Puoi anche fare riferimento all'URI con Events.CONTENT_URI. Per un esempio di utilizzo di questo intento, consulta Utilizzare gli intent per visualizzare i dati del calendario.
Visualizza l'evento specificato da <event_id>. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

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

Puoi anche fare riferimento all'URI con Events.CONTENT_URI. Per un esempio di utilizzo di questo intento, consulta Utilizzare un intento per modificare un evento.
Modifica l'evento specificato da <event_id>. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

INSERT

content://com.android.calendar/events

Puoi anche fare riferimento all'URI con Events.CONTENT_URI. Per un esempio di utilizzo di questo intent, consulta Utilizzare un intent per inserire un evento.
Crea un evento. Qualsiasi extra elencato nella tabella seguente.

Nella tabella seguente sono elencati gli extra intent supportati dal provider di calendario:

Intento extra Descrizione
Events.TITLE Nome dell'evento.
CalendarContract.EXTRA_EVENT_BEGIN_TIME Ora di inizio dell'evento in millisecondi dall'epoca.
CalendarContract.EXTRA_EVENT_END_TIME Ora di fine dell'evento in millisecondi dall'epoca.
CalendarContract.EXTRA_EVENT_ALL_DAY Un valore booleano che indica che un evento dura tutto il giorno. Il valore può essere true o false.
Events.EVENT_LOCATION Luogo dell'evento.
Events.DESCRIPTION Descrizione dell'evento.
Intent.EXTRA_EMAIL Indirizzi email delle persone da invitare come elenco separato da virgole.
Events.RRULE La regola di ripetizione dell'evento.
Events.ACCESS_LEVEL Se l'evento è privato o pubblico.
Events.AVAILABILITY Se questo evento viene conteggiato come tempo occupato o è un tempo libero che può essere pianificato.

Le sezioni seguenti descrivono come utilizzare questi intent.

Utilizzare un intent per inserire un evento

L'intent INSERT consente all'applicazione di trasferire l'attività di inserimento di eventi al calendario stesso. Con questo approccio, non è necessario includere l'autorizzazione WRITE_CALENDAR nel file manifest dell'applicazione.

Quando gli utenti eseguono un'applicazione che utilizza questo approccio, l'applicazione li invia a Calendar per completare l'aggiunta dell'evento. L'intent INSERT utilizza campi aggiuntivi per precompilare un modulo con i dettagli dell'evento nel calendario. Gli utenti possono quindi annullare l'evento, modificarlo in base alle esigenze o salvarlo nei propri calendari.

Ecco uno snippet di codice che pianifica un evento il 19 gennaio 2012, dalle 07:30 alle 8:30. Tieni presente quanto segue in merito allo snippet di codice:

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

Utilizzare un intent per modificare un evento

Puoi aggiornare un evento direttamente, come descritto in Aggiornare gli eventi. Tuttavia, l'utilizzo dell'intent EDIT consente a un'applicazione che non dispone dell'autorizzazione di trasferire la modifica degli eventi all'applicazione Calendar. Quando gli utenti terminano di modificare l'evento in Calendar, vengono reindirizzati all'applicazione originale.

Ecco un esempio di intent che imposta un nuovo titolo per un evento specifico e consente agli utenti di modificare l'evento in Calendar.

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

Utilizzare le intenzioni per visualizzare i dati del calendario

Il fornitore di calendario offre due modi diversi per utilizzare l'intent VIEW:

  • Per aprire il calendario in una data specifica.
  • Per visualizzare un evento.

Ecco un esempio che mostra come aprire il calendario in una determinata data:

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

Ecco un esempio che mostra come aprire un evento per la visualizzazione:

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

Adattatori di sincronizzazione

Esistono solo piccole differenze nel modo in cui un'applicazione e un'apposita funzionalità di sincronizzazione accedono al provider di calendario:

  • Un adattatore di sincronizzazione deve specificare che si tratta di un adattatore di sincronizzazione impostando CALLER_IS_SYNCADAPTER su true.
  • Un'entità di aggiornamento deve fornire un ACCOUNT_NAME e un ACCOUNT_TYPE come parametri di query nell'URI.
  • Un'app di aggiornamento ha accesso in scrittura a più colonne di un'applicazione o di un widget. Ad esempio, un'applicazione può modificare solo alcune caratteristiche di un calendario, come il nome, il nome visualizzato, le impostazioni di visibilità e la sincronizzazione o meno del calendario. In confronto, un'entità di sincronizzazione può accedere non solo a queste colonne, ma a molte altre, come colore del calendario, fuso orario, livello di accesso, posizione e così via. Tuttavia, un'opzione di sincronizzazione è limitata ai valori ACCOUNT_NAME e ACCOUNT_TYPE specificati.

Ecco un metodo di assistenza che puoi utilizzare per restituire un URI da utilizzare con un'app di aggiornamento sincronizzato:

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