CalendarioCalendar

API de calendarioCalendar API

Un nuevo conjunto de API introducidas en Android 4 calendario admite aplicaciones que están diseñadas para leer o escribir datos en el proveedor de calendario.A new set of calendar APIs introduced in Android 4 supports applications that are designed to read or write data to the calendar provider. Estas API admiten una gran variedad de opciones de interacción con los datos de calendario, incluida la capacidad para leer y escribir los eventos, los asistentes y avisos.These APIs support a wealth of interaction options with calendar data, including the ability to read and write events, attendees, and reminders. Mediante el proveedor de calendario en la aplicación, datos agregados a través de la API aparecerá en la aplicación de calendario integrada que se incluye con Android 4.By using the calendar provider in your application, data you add through the API will appear in the built-in calendar app that comes with Android 4.

Adición de permisosAdding Permissions

Cuando se trabaja con el nuevo API de calendario en la aplicación, lo primero que debe hacer es agregar los permisos adecuados para el manifiesto de Android.When working with the new calendar APIs in your application, the first thing you need to do is add the appropriate permissions to the Android manifest. Son los permisos necesarios para agregar android.permisson.READ_CALENDAR y android.permission.WRITE_CALENDAR, dependiendo de si son de lectura o escritura de datos de calendario.The permissions you need to add are android.permisson.READ_CALENDAR and android.permission.WRITE_CALENDAR, depending on whether you are reading and/or writing calendar data.

Cómo usar el contrato de calendarioUsing the Calendar Contract

Una vez configurados los permisos, puede interactuar con datos de calendario mediante la CalendarContract clase.Once you set the permissions, you can interact with calendar data by using the CalendarContract class. Esta clase proporciona un modelo de datos que las aplicaciones pueden usar cuando interactúan con el proveedor de calendario.This class provides a data model that applications can use when they interact with the calendar provider. El CalendarContract permite que las aplicaciones resolver los URI a las entidades de calendario, como los eventos y calendarios.The CalendarContract allows applications to resolve the Uris to calendar entities, such as calendars and events. También proporciona una manera de interactuar con varios campos en cada entidad, como nombre y ID, o inicio de un evento y fecha de finalización de un calendario.It also provides a way to interact with various fields in each entity, such as a calendar's name and ID, or an event's start and end date.

Veamos un ejemplo que utiliza la API de calendario.Let's look at an example that uses the Calendar API. En este ejemplo, examinaremos cómo enumerar los calendarios y sus eventos, así como agregar un nuevo evento a un calendario.In this example, we'll examine how to enumerate calendars and their events, as well as how to add a new event to a calendar.

Lista de calendariosListing Calendars

En primer lugar, vamos a examinar cómo enumerar los calendarios que se han registrado en la aplicación de calendario.First, let's examine how to enumerate the calendars that have been registered in the calendar app. Para ello, nos podemos crear una instancia de un CursorLoader.To do this, we can instantiate a CursorLoader. Introducido en 3.0 Android (API de 11), CursorLoader es la manera preferida para consumir un ContentProvider.Introduced in Android 3.0 (API 11), CursorLoader is the preferred way to consume a ContentProvider. Como mínimo, debemos especificar el Uri de contenido de calendarios y las columnas que queremos devolver; Esta especificación de columna se conoce como un proyección.At a minimum, we'll need to specify the content Uri for calendars and the columns we want to return; this column specification is known as a projection.

Una llamada a la CursorLoader.LoadInBackground método nos permite consultar un proveedor de contenido para los datos, como el proveedor de calendario.Calling the CursorLoader.LoadInBackground method allows us to query a content provider for data, such as the calendar provider. LoadInBackground realiza la operación de carga real y devuelve un Cursor con los resultados de la consulta.LoadInBackground performs the actual load operation and returns a Cursor with the results of the query.

El CalendarContract nos ayuda a especificar el contenido de ambas Uri y la proyección.The CalendarContract assists us in specifying both the content Uri and the projection. Para obtener el contenido Uri para consultar calendarios, podemos usar simplemente el CalendarContract.Calendars.ContentUri propiedad similar al siguiente:To get the content Uri for querying calendars, we can simply use the CalendarContract.Calendars.ContentUri property like this:

var calendarsUri = CalendarContract.Calendars.ContentUri;

Mediante el CalendarContract para especificar qué calendario columnas que queremos es igual de simple.Using the CalendarContract to specify which calendar columns we want is equally simple. Simplemente agregamos los campos de la CalendarContract.Calendars.InterfaceConsts clase a una matriz.We just add fields in the CalendarContract.Calendars.InterfaceConsts class to an array. Por ejemplo, el siguiente código incluye el identificador del calendario, el nombre para mostrar y nombre de cuenta:For example, the following code includes the calendar's ID, display name, and account name:

string[] calendarsProjection = {
    CalendarContract.Calendars.InterfaceConsts.Id,
    CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
    CalendarContract.Calendars.InterfaceConsts.AccountName
};

El Id es importante incluir si usas un SimpleCursorAdapter para enlazar los datos a la interfaz de usuario, como veremos en breve.The Id is important to include if you are using a SimpleCursorAdapter to bind the data to the UI, as we will see shortly. Con el Uri de contenido y proyección en su lugar, creamos una instancia de la CursorLoader y llamar a la CursorLoader.LoadInBackground método para devolver un cursor con los datos del calendario, tal como se muestra a continuación:With the content Uri and projection in place, we instantiate the CursorLoader and call the CursorLoader.LoadInBackground method to return a cursor with the calendar data as shown below:

var loader = new CursorLoader(this, calendarsUri, calendarsProjection, null, null, null);
var cursor = (ICursor)loader.LoadInBackground();

La interfaz de usuario para este ejemplo contiene un ListView, con cada elemento de la lista que representa un calendario único.The UI for this example contains a ListView, with each item in the list representing a single calendar. El siguiente XML muestra el marcado que incluye el ListView:The following XML shows the markup that includes the ListView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
  <ListView
    android:id="@android:id/android:list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
</LinearLayout>

Además, es necesario especificar la interfaz de usuario para cada elemento de lista, que se coloque en un archivo XML independiente como sigue:Also, we need to specify the UI for each list item, which we place in a separate XML file as follows:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
  <TextView android:id="@+id/calDisplayName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="16dip" />
  <TextView android:id="@+id/calAccountName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="12dip" />
</LinearLayout>

Desde este punto, es normal Android código para enlazar los datos desde la posición del cursor a la interfaz de usuario.From this point on, it's just normal Android code to bind the data from the cursor to the UI. Vamos a usar un SimpleCursorAdapter como sigue:We'll use a SimpleCursorAdapter as follows:

string[] sourceColumns = {
    CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
    CalendarContract.Calendars.InterfaceConsts.AccountName };

int[] targetResources = {
    Resource.Id.calDisplayName, Resource.Id.calAccountName };      

SimpleCursorAdapter adapter = new SimpleCursorAdapter (this,
    Resource.Layout.CalListItem, cursor, sourceColumns, targetResources);

ListAdapter = adapter;

En el código anterior, el adaptador toma las columnas especificadas en el sourceColumns de matriz y los escribe en los elementos de interfaz de usuario en el targetResources matriz para cada entrada de calendario en el cursor.In the above code, the adapter takes the columns specified in the sourceColumns array and writes them to the user interface elements in the targetResources array for each calendar entry in the cursor. La actividad que se usa aquí es una subclase de ListActivity; incluye la ListAdapter propiedad en el que se establece el adaptador.The Activity used here is a subclass of ListActivity; it includes the ListAdapter property to which we set the adapter.

Esta es una captura de pantalla que muestra el resultado final, con la información de calendario que se muestra en el ListView:Here's a screenshot showing the end result, with the calendar info displayed in the ListView:

CalendarDemo que se ejecuta en el emulador, mostrar dos entradas del calendarioCalendarDemo running in emulator, displaying two calendar entries

Lista de eventos del calendarioListing Calendar Events

Siguiente Echemos un vistazo a cómo enumerar los eventos de un calendario determinado.Next let's look at how to enumerate the events for a given calendar. Basándose en el ejemplo anterior, le presentamos una lista de eventos cuando el usuario selecciona uno de los calendarios.Building upon the example above, we'll present a list of events when the user selects one of the calendars. Por lo tanto, se necesita para administrar la selección de elementos en el código anterior:Therefore, we'll need to handle the item selection in the previous code:

ListView.ItemClick += (sender, e) => {
    int i = (e as ItemEventArgs).Position;

    cursor.MoveToPosition(i);
    int calId =
        cursor.GetInt (cursor.GetColumnIndex (calendarsProjection [0]));

    var showEvents = new Intent(this, typeof(EventListActivity));
    showEvents.PutExtra("calId", calId);
    StartActivity(showEvents);
};

En este código, estamos creando una intención para abrir una actividad de tipo EventListActivity, pasar un identificador del calendario en la intención.In this code, we're creating an Intent to open an Activity of type EventListActivity, passing the calendar's ID in the Intent. Necesitamos el Id. de saber qué calendario para consultar los eventos.We will need the ID to know which calendar to query for events. En el EventListActivitydel OnCreate método, podemos recuperar el identificador de la Intent tal como se muestra a continuación:In the EventListActivity's OnCreate method, we can retrieve the ID from the Intent as shown below:

_calId = Intent.GetIntExtra ("calId", -1);

Ahora vamos a eventos de consulta para este Id. de calendarioNow let's query events for this calendar ID. El proceso para consultar los eventos es similar a la forma en que se consulta para obtener una lista de calendarios anteriormente, pero esta vez vamos a trabajar con el CalendarContract.Events clase.The process to query for events is similar to the way we queried for a list of calendars earlier, only this time we'll work with the CalendarContract.Events class. El código siguiente crea una consulta para recuperar los eventos:The following code creates a query to retrieve events:

var eventsUri = CalendarContract.Events.ContentUri;

string[] eventsProjection = {
    CalendarContract.Events.InterfaceConsts.Id,
    CalendarContract.Events.InterfaceConsts.Title,
    CalendarContract.Events.InterfaceConsts.Dtstart
};

var loader = new CursorLoader(this, eventsUri, eventsProjection,
                   String.Format ("calendar_id={0}", _calId), null, "dtstart ASC");
var cursor = (ICursor)loader.LoadInBackground();

En este código, primero debemos obtener el contenido Uri para los eventos desde el CalendarContract.Events.ContentUri propiedad.In this code, we first get the content Uri for events from the CalendarContract.Events.ContentUri property. Luego, especificamos las columnas de evento que van a recuperar de la matriz eventsProjection.Then we specify the event columns we want to retrieve in the eventsProjection array. Por último, creamos una instancia de un CursorLoader con esta información y la llamada del cargador LoadInBackground método devuelva un Cursor con los datos del evento.Finally, we instantiate a CursorLoader with this information and call the loader's LoadInBackground method to return a Cursor with the event data.

Para mostrar los datos del evento en la interfaz de usuario, podemos usar marcado y código tal como se hizo antes de mostrar la lista de calendarios.To display the event data in the UI, we can use markup and code just like we did before to display the list of calendars. De nuevo, utilizamos SimpleCursorAdapter para enlazar los datos a un ListView tal como se muestra en el código siguiente:Again, we use SimpleCursorAdapter to bind the data to a ListView as shown in the following code:

string[] sourceColumns = {
    CalendarContract.Events.InterfaceConsts.Title,
    CalendarContract.Events.InterfaceConsts.Dtstart };

int[] targetResources = {
    Resource.Id.eventTitle,
    Resource.Id.eventStartDate };

var adapter = new SimpleCursorAdapter (this, Resource.Layout.EventListItem,
    cursor, sourceColumns, targetResources);

adapter.ViewBinder = new ViewBinder ();       
ListAdapter = adapter;

La principal diferencia entre este código y el código que se usó anteriormente para mostrar la lista de calendario es el uso de un ViewBinder, que se establece en la línea:The main difference between this code and the code that we used earlier to show the calendar list is the use of a ViewBinder, which is set on the line:

adapter.ViewBinder = new ViewBinder ();

La ViewBinder clase nos permite un mayor control sobre cómo se enlazan valores a las vistas.The ViewBinder class allows us to further control how we bind values to views. En este caso, usamos, para convertir la hora de inicio del evento de milisegundos a una cadena de fecha, como se muestra en la siguiente implementación:In this case, we use it to convert the event start time from milliseconds to a date string, as shown in the following implementation:

class ViewBinder : Java.Lang.Object, SimpleCursorAdapter.IViewBinder
{    
    public bool SetViewValue (View view, Android.Database.ICursor cursor,
        int columnIndex)
    {
        if (columnIndex == 2) {
            long ms = cursor.GetLong (columnIndex);

            DateTime date = new DateTime (1970, 1, 1, 0, 0, 0,
                DateTimeKind.Utc).AddMilliseconds (ms).ToLocalTime ();

            TextView textView = (TextView)view;
            textView.Text = date.ToLongDateString ();

            return true;
        }
        return false;
    }    
}

Esto muestra una lista de eventos, como se muestra a continuación:This displays a list of events as shown below:

Captura de pantalla de la aplicación de ejemplo muestra tres eventos de calendarioScreenshot of example app displaying three calendar events

Agregar un evento de calendarioAdding a Calendar Event

Hemos visto cómo leer datos de calendario.We've seen how to read calendar data. Ahora veamos cómo agregar un evento a un calendario.Now let's see how to add an event to a calendar. Para que funcione, no olvide incluir el android.permission.WRITE_CALENDAR permiso se ha mencionado anteriormente.For this to work, be sure to include the android.permission.WRITE_CALENDAR permission we mentioned earlier. Para agregar un evento a un calendario, se hará lo siguiente:To add an event to a calendar, we will:

  1. Crear un ContentValues instancia.Create a ContentValues instance.
  2. Usar claves de la CalendarContract.Events.InterfaceConsts clase para rellenar el ContentValues instancia.Use keys from the CalendarContract.Events.InterfaceConsts class to populate the ContentValues instance.
  3. Establezca las zonas horarias para el inicio de evento y hora de finalización.Set the time zones for the event start and end times.
  4. Use un ContentResolver para insertar los datos del evento en el calendario.Use a ContentResolver to insert the event data into the calendar.

El código siguiente muestra estos pasos:The code below illustrates these steps:

ContentValues eventValues = new ContentValues ();

eventValues.Put (CalendarContract.Events.InterfaceConsts.CalendarId,
    _calId);
eventValues.Put (CalendarContract.Events.InterfaceConsts.Title,
    "Test Event from M4A");
eventValues.Put (CalendarContract.Events.InterfaceConsts.Description,
    "This is an event created from Xamarin.Android");
eventValues.Put (CalendarContract.Events.InterfaceConsts.Dtstart,
    GetDateTimeMS (2011, 12, 15, 10, 0));
eventValues.Put (CalendarContract.Events.InterfaceConsts.Dtend,
    GetDateTimeMS (2011, 12, 15, 11, 0));

eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone,
    "UTC");
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventEndTimezone,
    "UTC");

var uri = ContentResolver.Insert (CalendarContract.Events.ContentUri,
    eventValues);

Observe que si no se establece la zona horaria, una excepción de tipo Java.Lang.IllegalArgumentException se iniciará.Note that if we do not set the time zone, an exception of type Java.Lang.IllegalArgumentException will be thrown. Dado que los valores de hora del evento se deben expresar en milisegundos desde la época, creamos un GetDateTimeMS (método) (en EventListActivity) para convertir las especificaciones de nuestra fecha en formato de milisegundo:Because event time values must be expressed in milliseconds since epoch, we create a GetDateTimeMS method (in EventListActivity) to convert our date specifications into millisecond format:

long GetDateTimeMS (int yr, int month, int day, int hr, int min)
{
    Calendar c = Calendar.GetInstance (Java.Util.TimeZone.Default);

    c.Set (Java.Util.CalendarField.DayOfMonth, 15);
    c.Set (Java.Util.CalendarField.HourOfDay, hr);
    c.Set (Java.Util.CalendarField.Minute, min);
    c.Set (Java.Util.CalendarField.Month, Calendar.December);
    c.Set (Java.Util.CalendarField.Year, 2011);

    return c.TimeInMillis;
}

Si se agregue un botón a la interfaz de usuario de la lista de eventos y se ejecuta el código anterior en el botón, haga clic en el controlador de eventos, el evento se agrega al calendario y se actualizan en nuestra lista tal como se muestra a continuación:If we add a button to the event list UI and run the above code in the button's click event handler, the event is added to the calendar and updated in our list as shown below:

Captura de pantalla de la aplicación de ejemplo con eventos de calendario seguido de botón de agregar el evento de ejemploScreenshot of example app with calendar events followed by Add Sample Event button

Si se abre la aplicación de calendario, a continuación, veremos que se escribe el evento existe así:If we open the calendar app, then we will see that the event is written there as well:

Captura de pantalla de la aplicación de calendario mostrando el evento seleccionadoScreenshot of calendar app displaying the selected calendar event

Como puede ver, Android permite el acceso sencillo y eficaz recuperar y conservar los datos de calendario, lo que permite a las aplicaciones se integren perfectamente las capacidades de calendario.As you can see, Android allows powerful and easy access to retrieve and persist calendar data, allowing applications to seamlessly integrate calendar capabilities.