Il provider di calendari è un repository per gli eventi del calendario di un utente. L'API Calendar Provider consente di eseguire query, inserire, aggiornare ed eliminare operazioni 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 è incentrato principalmente sull'utilizzo dell'API Calendar Provider come applicazione. Per ulteriori informazioni sulle differenze tra gli adattatori di sincronizzazione, consulta la sezione Adattatori di sincronizzazione.
Generalmente, per leggere o scrivere dati di calendario, il manifest di un'applicazione deve includere le autorizzazioni appropriate, descritte in Autorizzazioni utente. Per semplificare l'esecuzione delle operazioni più comuni, il provider di Calendar offre un insieme di intent, come descritto negli intent di Calendar. Questi intent indirizzano gli utenti all'applicazione Calendar per inserire, visualizzare e modificare eventi. L'utente interagisce con l'applicazione Calendar e poi torna all'applicazione originale. Pertanto, l'applicazione non deve richiedere autorizzazioni né fornire un'interfaccia utente per visualizzare o creare eventi.
Concetti 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 provider di calendari) in genere espongono i dati come insieme di tabelle basato su un modello di database relazionale, in cui ogni riga è un record e ogni colonna è 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 (sottoposto a wrapping come oggetto Uri
) che identifica in modo univoco il relativo set di dati. Un fornitore di contenuti che controlla più set di dati (più tabelle) espone un URI separato per ciascuno. Tutti gli URI dei provider iniziano con la stringa "content://". In questo modo, i dati vengono identificati come controllati da un fornitore di contenuti. Il Calendar
Provider definisce le costanti degli URI per ciascuna delle sue classi (tabelle). Questi URI hanno il formato <class>.CONTENT_URI
. Ad
esempio, Events.CONTENT_URI
.
La figura 1 mostra una rappresentazione grafica del modello dei dati del fornitore di calendario. Mostra le tabelle principali e i campi che le collegano tra loro.
Un utente può avere più calendari e diversi calendari possono essere associati a diversi tipi di account (Google Calendar, Exchange e così via).
L'CalendarContract
definisce il modello dei dati delle informazioni relative a calendari e eventi. Questi dati vengono archiviati in una serie di tabelle elencate di seguito.
Tabella (classe) | Descrizione |
---|---|
Questa tabella contiene le informazioni specifiche del calendario. Ogni riga della tabella contiene i dettagli di un singolo calendario, come nome, colore, informazioni di sincronizzazione e così via. | |
CalendarContract.Events |
Questa tabella contiene le
informazioni specifiche sull'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. I partecipanti, i promemoria e le proprietà estese vengono archiviati in tabelle separate.
Ognuno di essi 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 singoli, esiste 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 sul partecipante (invitato) all'evento. Ogni riga rappresenta un singolo invitato di un evento. Specifica il tipo di invitato e la relativa risposta di partecipazione all'evento. |
CalendarContract.Reminders |
Questa tabella contiene i dati degli avvisi e delle notifiche. 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 è impostato dall'adattatore di sincronizzazione
che possiede il calendario specifico. I promemoria vengono specificati pochi minuti prima dell'evento e hanno un metodo che determina il modo in cui verrà avvisato l'utente. |
L'API Calendar Provider è progettata per essere flessibile e potente. Allo stesso tempo, è importante offrire una buona esperienza utente finale e proteggere l'integrità del calendario e dei suoi dati. A tal fine, ecco alcuni aspetti da tenere presente quando si utilizza l'API:
- Inserimento, aggiornamento e visualizzazione di eventi di calendario. Per inserire, modificare e leggere direttamente eventi del provider di calendari, devi disporre delle autorizzazioni appropriate. Tuttavia, se non stai creando un'applicazione di calendario o un adattatore di sincronizzazione a tutti gli effetti, 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 all'applicazione. Quando utilizzi gli intent, l'applicazione invia gli utenti all'applicazione Calendar per eseguire l'operazione desiderata in un modulo precompilato. Al termine, vengono riportati nella tua applicazione. Progettando la tua applicazione in modo che eseguano operazioni comuni tramite Calendar, fornisci agli utenti un'interfaccia utente coerente e solida. Questo è l'approccio consigliato. Per ulteriori informazioni, vedi Intent di Calendar.
- Adattatori di sincronizzazione. 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
eCalendarContract.Events
sono presenti colonne riservate agli adattatori di sincronizzazione da utilizzare. Il provider e le applicazioni non devono modificarli. Infatti, non sono visibili se non vi si accede tramite un adattatore di sincronizzazione. Per ulteriori informazioni sugli adattatori di sincronizzazione, consulta la sezione 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 dei calendari
La tabella CalendarContract.Calendars
contiene i dettagli dei singoli calendari. Le seguenti colonne di Calendar possono essere modificate sia da un'applicazione sia da un adattatore di sincronizzazione.
Per un elenco completo dei campi supportati, consulta la pagina di riferimento CalendarContract.Calendars
.
Costante | Descrizione |
---|---|
NAME |
Il nome del calendario. |
CALENDAR_DISPLAY_NAME |
Il nome del calendario che verrà mostrato all'utente. |
VISIBLE |
Un valore booleano che indica se il calendario è selezionato per la visualizzazione. Il valore 0 indica che gli eventi associati a questo calendario non devono essere visualizzati. Il valore 1 indica che dovrebbero essere visualizzati gli eventi associati a questo calendario. 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 gli eventi devono essere archiviati sul dispositivo. Il valore 0 indica di non sincronizzare il calendario o non archiviare i relativi eventi sul dispositivo. Il valore 1 indica gli eventi di sincronizzazione per il calendario e archivia i relativi eventi 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 univoco solo in base ai valori di ACCOUNT_NAME
e ACCOUNT_TYPE
. ACCOUNT_TYPE
è la stringa corrispondente all'autenticatore dell'account utilizzato quando l'account è stato registrato con AccountManager
. Esiste anche un tipo speciale di account denominato ACCOUNT_TYPE_LOCAL
per i calendari non associati a un account del dispositivo.
Gli account ACCOUNT_TYPE_LOCAL
non vengono sincronizzati.
Esegui 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 andrebbe eseguita in un
thread asincrono anziché nel thread principale. Per ulteriori discussioni, consulta la sezione Caricatori. Se non stai solo leggendo 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, crei la query. La selezione specifica i criteri per la query. In questo esempio la query cerca i calendari che hanno ACCOUNT_NAME
"hera@example.com", ACCOUNT_TYPE
"com.example" e OWNER_ACCOUNT
"hera@example.com". Se vuoi vedere 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 la sezione 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 impostate 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 l'aggiornamento di un calendario, puoi fornire _ID
del calendario come ID aggiunto all'URI (withAppendedId()
) o come primo elemento di selezione. La selezione
deve iniziare con "_id=?"
e la prima
selectionArg
deve essere la data _ID
del calendario.
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);
Inserisci un calendario
I calendari sono progettati per essere gestiti principalmente tramite un adattatore di sincronizzazione, pertanto ti consigliamo di inserire solo i nuovi calendari come adattatori di sincronizzazione. Nella maggior parte dei casi, le applicazioni possono apportare solo 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, utilizzando un ACCOUNT_TYPE
di ACCOUNT_TYPE_LOCAL
.
ACCOUNT_TYPE_LOCAL
è un tipo di account speciale per i calendari non
associati a un account del dispositivo. I calendari di questo tipo non vengono sincronizzati con un server. Per una discussione sugli adattatori di sincronizzazione, consulta Adattatori di sincronizzazione.
Tabella degli eventi
La tabella CalendarContract.Events
contiene i dettagli dei singoli eventi. Per aggiungere, aggiornare o eliminare eventi, un'applicazione deve includere l'autorizzazione WRITE_CALENDAR
nel file manifest.
Le seguenti colonne Eventi possono essere modificate 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 |
_ID del calendario a cui appartiene l'evento. |
ORGANIZER |
Indirizzo email dell'organizzatore (proprietario) dell'evento. |
TITLE |
Il titolo dell'evento. |
EVENT_LOCATION |
Dove si svolge l'evento. |
DESCRIPTION |
La descrizione dell'evento. |
DTSTART |
L'ora di inizio dell'evento in millisecondi UTC a partire dall'epoca. |
DTEND |
L'ora in cui l'evento termina in millisecondi UTC a partire 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, il valore "PT1H" indica che l'evento
dovrebbe durare un'ora, mentre il valore "P2W" indica una
durata di due settimane. |
ALL_DAY |
Il valore 1 indica che questo evento occupa l'intera giornata, come definito dal fuso orario locale. Il valore 0 indica che si tratta di un evento regolare che può iniziare e terminare in qualsiasi momento di un giorno. |
RRULE |
La regola di ricorrenza 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, utilizzi RDATE
insieme a RRULE
per definire un insieme aggregato di occorrenze ripetute. Per ulteriori informazioni, consulta la specifica RFC5545. |
AVAILABILITY |
Se questo evento conta come un tempo occupato o è un tempo libero, è possibile pianificarlo. |
GUESTS_CAN_MODIFY |
Indica se gli invitati possono modificare l'evento. |
GUESTS_CAN_INVITE_OTHERS |
Se gli invitati possono invitare altre persone. |
GUESTS_CAN_SEE_GUESTS |
Se gli invitati possono visualizzare l'elenco dei partecipanti. |
Aggiungi eventi
Quando l'applicazione inserisce un nuovo evento, ti consigliamo di utilizzare un intent INSERT
, come descritto in Utilizzo di un intent per inserire un evento. Tuttavia, se necessario, puoi inserire gli eventi direttamente. Questa sezione descrive come eseguire questa operazione.
Di seguito sono riportate le regole per l'inserimento di un nuovo evento:
- Devi includere
CALENDAR_ID
eDTSTART
. - Devi includere un elemento
EVENT_TIMEZONE
. Per ottenere un elenco degli ID dei fusi orari installati nel sistema, utilizzagetAvailableIDs()
. Tieni presente che questa regola non si applica se inserisci un evento tramite l'intentINSERT
, descritto in Utilizzo di un intent per inserire un evento. Per lo scenario viene fornito un fuso orario predefinito. - Per gli eventi non ricorrenti, devi includere
DTEND
. - Per gli eventi ricorrenti, devi includere un
DURATION
oltre aRRULE
oRDATE
. Tieni presente che questa regola non si applica se inserisci un evento tramite l'intentINSERT
, descritto in Utilizzo di un intent per inserire un evento. In questo scenario, puoi utilizzareRRULE
insieme aDTSTART
eDTEND
e l'applicazione Calendar la converte automaticamente in una durata.
Ecco un esempio di inserimento di un evento. Questa operazione viene eseguita nel thread della UI
per semplicità. In pratica, l'inserimento e gli aggiornamenti devono essere eseguiti in un
thread asincrono per spostare l'azione in un thread in background. Per ulteriori
informazioni, consulta la pagina 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: guarda in che modo questo esempio acquisisce l'ID evento dopo la creazione dell'evento. Questo è il modo più semplice per ottenere un ID evento. Spesso l'ID evento è necessario per eseguire altre operazioni sul calendario, ad esempio per aggiungere partecipanti o promemoria a un evento.
Eventi di aggiornamento
Se l'applicazione vuole consentire all'utente di modificare un evento, ti consigliamo di utilizzare un intent EDIT
, come descritto in Utilizzo di un intent per modificare un evento.
Tuttavia, se necessario, puoi modificare gli eventi direttamente. Per eseguire l'aggiornamento di un evento, puoi fornire _ID
dell'evento come ID aggiunto all'URI (withAppendedId()
) o come primo elemento di selezione.
La selezione deve iniziare con "_id=?"
e la prima
selectionArg
deve essere la data _ID
dell'evento. Puoi
anche eseguire gli aggiornamenti utilizzando una selezione senza ID. Ecco un esempio di aggiornamento
di un evento. Modifica 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
Puoi eliminare un evento in base al _ID
come ID aggiunto all'URI o mediante la selezione standard. Se utilizzi un ID aggiunto, non puoi effettuare anche una selezione.
Esistono due versioni di eliminazioni: come applicazione e come adattatore di sincronizzazione. Un'eliminazione dell'applicazione imposta la colonna deleted su 1. Questo flag che comunica all'adattatore di sincronizzazione che la riga è stata eliminata e che questa eliminazione deve essere propagata al server. L'eliminazione di un adattatore di sincronizzazione rimuove l'evento dal database insieme a tutti i dati associati. Ecco un esempio di applicazione dell'eliminazione di un evento tramite _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 dei partecipanti
Ogni riga della tabella CalendarContract.Attendees
rappresenta un singolo partecipante o invitato a un evento. La chiamata
query()
restituisce un elenco dei partecipanti all'evento con il valore EVENT_ID
specificato.
Questo EVENT_ID
deve corrispondere al valore _ID
di un determinato evento.
Nella tabella seguente sono elencati
i campi scrivibili. Quando inserisci un nuovo partecipante, devi includerlo 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 del partecipante all'evento. Uno dei seguenti: |
ATTENDEE_TYPE |
Il tipo di partecipante. Uno dei seguenti: |
ATTENDEE_STATUS |
Lo stato di partecipazione del partecipante. Uno dei seguenti: |
Aggiungi partecipanti
Ecco un esempio in cui viene aggiunto un singolo partecipante a un evento. Tieni presente che EVENT_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 a
query()
restituisce un elenco di promemoria per
l'evento con il valore
EVENT_ID
specificato.
Nella tabella seguente sono elencati i campi scrivibili per i promemoria. Devono essere tutti inclusi quando si inserisce un nuovo promemoria. Tieni presente che gli adattatori di sincronizzazione specificano i tipi di promemoria supportati nella tabella CalendarContract.Calendars
. Per informazioni dettagliate, visita la pagina ALLOWED_REMINDERS
.
Costante | Descrizione |
---|---|
EVENT_ID |
L'ID dell'evento. |
MINUTES |
I minuti precedenti all'evento in cui il promemoria dovrebbe essere attivato. |
METHOD |
Il metodo di allarme, 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 è accessibile in scrittura 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 giuliano di fine dell'istanza, relativo al fuso orario del calendario. |
END_MINUTE |
Il minuto finale dell'istanza misurato da mezzanotte nel 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 in relazione al fuso orario del calendario. |
Esegui una query sulla tabella delle istanze
Per eseguire una query sulla tabella delle istanze, devi specificare un intervallo di tempo per la query nell'URI. In questo esempio, CalendarContract.Instances
ottiene l'accesso al campo TITLE
tramite la sua implementazione dell'interfaccia CalendarContract.EventsColumns
.
In altre parole, TITLE
viene restituito tramite una visualizzazione del database e non tramite 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 calendario
L'applicazione non ha bisogno delle 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 all'applicazione. Nella tabella seguente sono elencati gli intent supportati dal fornitore di calendari:
Azione | URI | Descrizione | Extra |
---|---|---|---|
VIEW |
CalendarContract.CONTENT_URI .
Per un esempio di utilizzo di questo intent, consulta la sezione Utilizzo degli intent per visualizzare i dati del calendario.
|
Apri il calendario con l'ora specificata da <ms_since_epoch> . |
Nessuna. |
Events.CONTENT_URI .
Per un esempio di utilizzo di questo intent, consulta la sezione Utilizzo degli 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 |
Events.CONTENT_URI .
Per un esempio di utilizzo di questo intent, consulta la sezione Utilizzo di un intent per modificare un evento.
|
Modifica l'evento specificato da <event_id> . |
CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME |
EDIT INSERT |
Events.CONTENT_URI .
Per un esempio di utilizzo di questo intent, consulta la sezione Utilizzo di un intent per inserire un evento.
|
Crea un evento. | Uno qualsiasi degli extra elencati nella tabella seguente. |
Nella tabella seguente sono elencati gli intent extra supportati dal fornitore di calendari:
Intent extra | Descrizione |
---|---|
Events.TITLE |
Nome dell'evento. |
CalendarContract.EXTRA_EVENT_BEGIN_TIME |
Tempo 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 |
Gli indirizzi email delle persone da invitare sotto forma di elenco separato da virgole. |
Events.RRULE |
La regola di ricorrenza dell'evento. |
Events.ACCESS_LEVEL |
Indica se l'evento è pubblico o privato. |
Events.AVAILABILITY |
Se questo evento viene conteggiato come tempo occupato o come tempo libero, è possibile programmarlo. |
Le seguenti sezioni descrivono come utilizzare questi intent.
Utilizzare un intent per inserire un evento
L'utilizzo dell'intent INSERT
consente all'applicazione di trasferire l'attività di inserimento dell'evento 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 le 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, modificare il modulo in base alle esigenze o salvare l'evento nei propri calendari.
Di seguito è riportato uno snippet di codice che pianifica un evento il 19 gennaio 2012 dalle 7:30 alle 8:30. Tieni presente quanto segue in merito a questo snippet di codice:
- Specifica
Events.CONTENT_URI
come URI. - Utilizza i campi
CalendarContract.EXTRA_EVENT_BEGIN_TIME
eCalendarContract.EXTRA_EVENT_END_TIME
aggiuntivi per precompilare il modulo con l'ora dell'evento. I valori per questi orari devono essere in millisecondi UTC a partire dall'epoca. - Utilizza il campo aggiuntivo
Intent.EXTRA_EMAIL
per fornire un elenco separato da virgole di invitati, specificati in base all'indirizzo email.
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 è autorizzata a trasferire la modifica degli eventi all'applicazione Calendar.
Quando gli utenti completano la modifica dell'evento in Calendar, vengono reindirizzati all'applicazione originale.
Ecco un esempio di intent che imposta un nuovo titolo per un evento specificato 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 gli intent per visualizzare i dati del calendario
Il fornitore di calendari offre due modi diversi per utilizzare l'intent VIEW
:
- Per aprire il calendario per una data specifica.
- Per visualizzare un evento.
Ecco un esempio che mostra come aprire Calendar per una data specifica:
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 adattatore di sincronizzazione accedono al provider di calendari:
- Un adattatore di sincronizzazione deve specificare che si tratta di un adattatore di sincronizzazione impostando
CALLER_IS_SYNCADAPTER
sutrue
. - Un adattatore di sincronizzazione deve fornire un
ACCOUNT_NAME
e unACCOUNT_TYPE
come parametri di ricerca nell'URI. - Un adattatore di sincronizzazione ha accesso in scrittura a più colonne rispetto a un'applicazione o un widget.
Ad esempio, un'applicazione può modificare solo alcune caratteristiche di un calendario, come il nome, il nome visualizzato, l'impostazione di visibilità e se il calendario è sincronizzato. In confronto, un adattatore di sincronizzazione può accedere non solo a queste colonne, ma anche a molte altre,
ad esempio il colore del calendario, il fuso orario, il livello di accesso, la posizione e così via.
Tuttavia, un adattatore di sincronizzazione è limitato ai valori
ACCOUNT_NAME
eACCOUNT_TYPE
specificati.
Ecco un metodo helper che puoi utilizzare per restituire un URI da utilizzare con un adattatore di sincronizzazione:
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(); }