[Windows Phone 8.1] El Action Center

ActionCenterIntroducción

Los Live Tiles disponibles en la plataforma Windows son una excelente y elegante forma de notificar al usuario con información relevante para el mismo. Sin embargo, no todas las aplicaciones están ancladas al inicio y a veces el usuario puede perder información. Para solventar esto llega el Action Center, un lugar donde ver todas las notificaciones de todas las aplicaciones incluso de las no ancladas al incio además de poder acceder a configuración básica del sistema como el modo vuelo, WiFi o Bluetooth.

Con el SDK de Windows Phone 8.1 tenemos a nuestra disposición varias APIs que permiten administrar las notificaciones del centro de actividades (Action Center). En este artículo vamos a conocer las APIs disponibles.

¿Te apuntas?

Manos a la Obra

Comenzamos creando un nuevo proyecto:

Nuevo proyecto

Nuevo proyecto

Partimos de la plantilla Blank App para centrar nuestra atención en la gestión de notificaciones. Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

En el artículo actual vamos a centrarnos en varios puntos:

  • Enviar una notificación Toast local que mostrará un mensaje (como hsata ahora) y además quedara registrada en el Action Center.
  • Enviar un nuevo tipo de notificación Toast llamada “fantasma” que no muestra mensaje sino que aparece directamente en el Action Center.
  • Vamos a aprender como gestiona las colecciones de notificaciones el Action Center.
  • Vamos a gestionar notificaciones, además de añadirlas, vamos a ver como eliminarlas.

Para cubrir estos objetivos, vamos a añadir múltiples vistas, cada una de ellas, centrada en uno de los objetivos anteriores. Añadimos:

  • ToastView: Desde donde enviar una notificación Toast.
  • GhostView : Desde donde enviar una notificación “fantasma”.
  • QueueView: Desde aqui enviaremos un grupo de notificaciones.
  • EditView: Desde aqui gestionaremos múltiples notificaciones.

Nos centramos en la vista principal de la aplicación:

<ScrollViewer>
     <StackPanel Margin="12">
            <TextBlock Text="ACTION CENTER" FontSize="32"
                       Margin="0, 0, 0, 25"/>
            <TextBlock Text="Enviaremos una notificación toast local. EL popup de la notificación aparecerá y automáticamente tambien se enviará al action center."
                       TextWrapping="Wrap" />
            <Button Content="Notificación Toast" Command="{Binding ToastCommand}"/>
            <TextBlock Text="Enviaremos una notificación toast fantasma local. Usamos la propiedad SupressPopup del Toast para que solo aparezca en el action center."
                       TextWrapping="Wrap" />
            <Button Content="Notificación Toast fantasma" Command="{Binding GhostCommand}"/>
            <TextBlock Text="Toda aplicación tiene una cantidad finita de espacio en el action center. En este ejemplo enviamos múltiples notificaciones para demostrar su funcionamiento."
                       TextWrapping="Wrap" />
            <Button Content="Sistema de colas" Command="{Binding QueueCommand}"/>
            <TextBlock Text="Gracias a NotificationManager.History podemos eliminar notificaciones del action center."
                       TextWrapping="Wrap" />
            <Button Content="Gestión de notificaciones" Command="{Binding EditCommand}"/>
     </StackPanel>
</ScrollViewer>

Como podemos ver, contamos con un listado de botones que ejecutan comandos de la viewmodel, que realizarán la navegación a sus respectivas vistas. Vemos el código de la viewmodel:

private ICommand _ghostCommand;
private ICommand _queueCommand;
private ICommand _editCommand;
private ICommand _toastCommand;

public ICommand GhostCommand
{
     get { return _ghostCommand = _ghostCommand ?? new DelegateCommand(GhostCommandDelegate); }
}

public ICommand QueueCommand
{
     get { return _queueCommand = _queueCommand ?? new DelegateCommand(QueueCommandDelegate); }
}

public ICommand EditCommand
{
     get { return _editCommand = _editCommand ?? new DelegateCommand(EditCommandDelegate); }
}

public ICommand ToastCommand
{
     get { return _toastCommand = _toastCommand ?? new DelegateCommand(ToastCommandDelegate); }
}

public void GhostCommandDelegate()
{
     AppFrame.Navigate(typeof (GhostView));
}

public void QueueCommandDelegate()
{
     AppFrame.Navigate(typeof (QueueView));
}

public void EditCommandDelegate()
{
     AppFrame.Navigate(typeof (EditView));
}

public void ToastCommandDelegate()
{
     AppFrame.Navigate(typeof(ToastView));
}

Aún nada específico de notificaciones o el Action Center, sencillamente la estructura base de nuestro ejemplo. El resultado de lo realizado hsata aqui es:

Interfaz de nuestro ejemplo

Interfaz de nuestro ejemplo

Enviando notificaciones Toast

Para poder probar el centro de actividades tenemos que enviar notificaciones. La forma más sencilla de enviar notificaciones es utilizando notificaciones locales del sistema. Para la gestión correcta de todo vamos a crear un servicio llamado LocalNotificationService:

public class LocalNotificationService : ILocalNotificationService
{

}

En la definición del servicio comenzamos con un método imprescindible, verificar si podemos enviar notificaciones o no:

/// <summary>
/// Verifica si podemos enviar notificaciones o no.
/// Verifica si estan habilitadas las notificaciones toast en la App.
/// </summary>
/// <returns></returns>
bool CanSendToasts();

Implementamos la interfaz:

public bool CanSendToasts()
{
     bool canSend = true;
     var notifier = ToastNotificationManager.CreateToastNotifier();

     if (notifier.Setting != NotificationSetting.Enabled)
          canSend = false;

     return canSend;
}

Antes de continuar, vamos a analizar que hacemos en el método anterior.

Utilizamos la clase ToastNotificationManager. Esta clase tiene como objetivo principal crear objetos de tipo ToastNotifier usados para generar notificaciones del sistema. Además, nos permite acceder al contenido XML de las plantillas de notificaciones para poder acceder y modificar su contenido. En este caso, utilizamos el método  CreateToastNotifier que crea e inicializa una instancia de ToastNotification. Verificamos basicamente si las notificaciones estan habilitadas o no.

Para que la aplicación sea capaz de gestionar notificaciones Toast debemos activar la opción en el archivo de manifiesto del paquete.

Habilitar las notificaciones Toast en el archivo de manifiesto

Habilitar las notificaciones Toast en el archivo de manifiesto

Nuestro objetivo principal en el servicio es crear notificaciones. Ese será el objetivo del siguiente método:

/// <summary>
/// Utiliza la plantilla ToastText02. Plantilla sencilla, se puede ver el catálogo en: http://msdn.microsoft.com/en-us/library/windows/apps/hh761494.aspx
/// </summary>
/// <param name="toastHeading"></param>
/// <param name="toastBody"></param>
/// <param name="tag"></param>
/// <param name="group"></param>
/// <returns></returns>
public ToastNotification CreateToast(string toastHeading, string toastBody, string tag, string group)
{
     // Usamos la plantilla ToastText02.
     ToastTemplateType toastTemplate = ToastTemplateType.ToastText02;

      // Obtenemos el xml que configura el toast para poder acceder a sus propiedades.
      XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);

      //Buscamos el text dentro del contenido.
      XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");

      // Establecemos el texto.
      toastTextElements[0].AppendChild(toastXml.CreateTextNode(toastHeading));
      toastTextElements[1].AppendChild(toastXml.CreateTextNode(toastBody));

      IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
      ((XmlElement)toastNode).SetAttribute("duration", "long");

      // Creamos la notificación.
      ToastNotification toast = new ToastNotification(toastXml);

      // Si nos llega tag se lo asignamos.
      if (!string.IsNullOrEmpty(tag))
           toast.Tag = tag;

      // Si nos llega grupo se lo asignamos.
      if (!string.IsNullOrEmpty(group))
          toast.Group = group;

      return toast;
}

En el código anterior, se crea una notificación Toast local utilizando la plantilla ToastText02. Esta plantilla cuenta con un máximo de dos elementos de texto. Es una notificación simple pero bastante usada.

NOTA: Podéis acceder a el catálogo de plantillas de notificación del sistema.

Tras crear la notificación volvemos a utilizar a la clase ToastNotificationManager para acceder al contenido XML de la notificación y añadir el texto recibido como parámetros en la notificación.

Además, podemos recibir etiqueta o grupo para la notificación. Veremos cuando y para que se utilizarán.

Bien, el método anterior crea notificaciones locales pero… ¿cómo las enviamos?

Vamos a crear otro método en nuestro servicio que se encargue de crear la notificación y lanzarla:

/// <summary>
/// Además de crear la notificación, la lanza y muestra.
/// </summary>
/// <param name="toastHeading"></param>
/// <param name="toastBody"></param>
/// <param name="suppressPopup"></param>        
/// <param name="tag"></param>
/// <param name="group"></param>
public void ShowToast(string toastHeading, string toastBody, string tag, string group, bool suppressPopup)
{
     ToastNotification toast = CreateToast(toastHeading, toastBody, tag, group);

     // SuppressPopup = true no apareceel popup, se envia directamente el action center.
     toast.SuppressPopup = suppressPopup;

     // Envia la notificación toast.
     ToastNotificationManager.CreateToastNotifier().Show(toast);
}

Para enviar la notificación localmente utilizamos el método ToastNotifier.Show(ToastNotification).

Hasta aquí nuestro servicio es lo suficientemente potente como para enviar notificaciones locales. Asi pues… !¿a que esperamos?!

Nos centramos en el primero de nuestros puntos, enviar una notificación local normal. Recordad que creamos una vista llamada ToastView que vinculamos (usamos Ioc, con un ViewModelLocator) a su viewmodel:

DataContext="{Binding ToastViewModel, Source={StaticResource Locator}}"

Nos centramos en la vista de ToastView. Basicamente añadimos un botón que nos permita enviar la notificación:

<Grid>
     <StackPanel Margin="12">
          <TextBlock Text="DEMO:" FontSize="32" />
          <TextBlock TextWrapping="Wrap">
                Enviaremos una notificación toast local. EL popup de la notificación aparecerá y automáticamente tambien se enviará al action center.
          </TextBlock>
          <Button Content="Enviar Notificación" Command="{Binding SendNotificationCommand}"/>
     </StackPanel>
</Grid>

El resultado es:

Action Center 02

Notificación Toast local mostrando mensaje y enviando al Action Center

Nos centramos en la viewmodel de esta vista:

private ILocalNotificationService _localNotificationService;
private ICommand _sendNotificationCommand;

public ToastViewModel(ILocalNotificationService localNotificationService)
{
     _localNotificationService = localNotificationService;
}

public ICommand SendNotificationCommand
{
     get { return _sendNotificationCommand = _sendNotificationCommand ?? new DelegateCommand(SendNotificationCommandDelegate); }
}

public void SendNotificationCommandDelegate()
{
     if (_localNotificationService.CanSendToasts())
          _localNotificationService.ShowToast("Toast Simple", "EL popup de la notificación aparecerá", string.Empty, string.Empty, false);
}

El botón lanza un comando que utiliza el servicio de notificaciones locales llamando al método ShowToast que analizamos previamente. Creará una notificación Toast local y la mostrará:

Notificación Toast enviada

Notificación Toast enviada

Aparecerá un mensaje como el de la captura anterior. Además:

Notificación registrada en el Action Center

Notificación registrada en el Action Center

Automáticamente se mostrará también en el centro de actividades.

Notificaciones fantasma

Aunque mostrar un mensaje emergente con las notificaciones es una funcionalidad fantástica además de una manera ideal de atraer la atención del usuario sobre algo importante que esta ocurriendo en nuestra aplicación. De hecho, es una forma tan efectiva de llamar la atención del usuario que si mostramos demasiados mensajes lograremos el objetivo contrario al buscado, resultaremos pesados.

¿Y si en lugar de mostrar un mensaje emergente con cada notificación, las registramos directamente en el centro de actividades?

Pues ahora es algo posible. Veamos como sería. Comenzamos creando la interfaz de la vista GhostView:

<Grid>
     <StackPanel Margin="12">
          <TextBlock Text="DEMO:" FontSize="32" />
          <TextBlock TextWrapping="Wrap">
                Enviaremos una notificación toast "fantasma" local. Usamos la propiedad SupressPopup del Toast para que solo aparezca en el action center.
          </TextBlock>
          <Button Content="Enviar Notificación Fantasma" Command="{Binding SendGhostNotificationCommand}"/>
      </StackPanel>
</Grid>

El resultado:

Interfaz para enviar notificaciones fantasmas

Interfaz para enviar notificaciones fantasmas

Nos centramos en la viewmodel de la vista:

private ILocalNotificationService _localNotificationService;
private ICommand _sendGhostNotificationCommand;

public GhostViewModel(ILocalNotificationService localNotificationService)
{
     _localNotificationService = localNotificationService;
}

public ICommand SendGhostNotificationCommand
{
     get { return _sendGhostNotificationCommand = _sendGhostNotificationCommand ?? new DelegateCommand(SendGhostNotificationCommandDelegate); }
}

public void SendGhostNotificationCommandDelegate()
{
     if (_localNotificationService.CanSendToasts())
          _localNotificationService.ShowToast("Toast Simple", "EL popup de la notificación NO aparecerá", string.Empty, string.Empty, true);
}

De nuevo contamos con un comando que lanza el método ShowToast de nuestro servicio de notificaciones locales. Sin embargo, en esta ocasión el método cuenta con un parámetro distinto al caso anterior. El último parámetro es un booleano que áfecta a ka propiedad SuppressPopup. Esta propiedad indica si se suprime el mensaje emergente de la notificación pero manteniendo al usuario informado mediante el centro de actividades:

Notificación sin mensaje, aparece directamente en el Action Center

Notificación sin mensaje, aparece directamente en el Action Center

La cola de notificaciones del Action Center

El centro de actividades tiene límites. Una misma aplicación puede mantener hasta 20 notificaciones como límite. Cada aplicación gestiona su cola de notificaciones en el centro de actividades siguiente el principio FIFO.

¿Qué quiere decir esto?

Cuando se envia una nueva notificación de la aplicación al centro de actividades y ya se ha llegado al límite, se elimina automáticamente la notificación más antigua.

NOTA: En caso de tener más de 20 notificaciones se muestra un mensaje “Más notificaciones” para avisar al usuario. Al pulsarlo se abre la aplicación.

Creamos la interfaz que nos permita enviar múltiples notificaciones:

<Grid>
     <StackPanel Margin="12">
          <TextBlock Text="DEMO:" FontSize="32" />
          <TextBlock TextWrapping="Wrap">
                Toda aplicación tiene una cantidad finita de espacio en el action center. En este ejemplo enviamos múltiples notificaciones para demostrar su funcionamiento.
          </TextBlock>
          <Button Content="Enviar múltiples notificaciones" Command="{Binding SendNotificationsCommand}"/>
     </StackPanel>
</Grid>

El resultado es:

Interfaz que nos permite lanzar múltiples notificaciones

Interfaz que nos permite lanzar múltiples notificaciones

Nos centramos en su viewmodel:

private const int toastsToSend = 25;

private ILocalNotificationService _localNotificationService;
private ICommand _sendNotificationsCommand;

public QueueViewModel(ILocalNotificationService localNotificationService)
{
     _localNotificationService = localNotificationService;
}

public ICommand SendNotificationsCommand
{
     get { return _sendNotificationsCommand = _sendNotificationsCommand ?? new DelegateCommand(SendNotificationsCommandDelegate); }
}

public void SendNotificationsCommandDelegate()
{
     if (_localNotificationService.CanSendToasts())
     {
          // Enviamos múltiples notificaciones
          for (int i = 0; i < toastsToSend; i++)
          {
               _localNotificationService.ShowToast(string.Format("Toast {0}", i + 1), "Contenido", string.Empty, string.Empty, true);
          }
     }
}

El pulsar el botón ejecutamos un comando de la viewmodel en la que en bucle lanzamos el evento ShowToast de nuestro servicio 25 veces (declarado en constante).

El resultado es el siguiente:

Cola de notificaciones

Cola de notificaciones

Como ya mencionamos previamente, cada aplicación cuenta con una cola de hasta 20 notificaciones mostrando la opción “más notificaciones” en caso de existir más.

Eliminar notificaciones del Action Center

Hasta ahora hemos visto como se envían notificaciones Toast y notificaciones Toast fantasmas y su registro en el centro de actividades asi como la gestión de colas que lleva a cabo el mismo. A continuación, continuaremos viendo como realizar gestión de notificaciones en el centro de actividades.

Creamos la interfaz de esta última parte del ejemplo:

<Grid>
     <StackPanel Margin="12">
          <TextBlock Text="DEMO:" FontSize="32" />
          <TextBlock TextWrapping="Wrap">
                Gracias a NotificationManager.History podemos eliminar notificaciones del action center.
          </TextBlock>
          <Button Content="Enviar notificaciones" Command="{Binding SendNotificationsCommand}" />
          <Button Content="Eliminar por Tag" Command="{Binding RemoveTagCommand}" />
          <Button Content="Eliminar por grupo" Command="{Binding RemoveGroupCommand}" />
          <Button Content="Eliminar todas las notificaciones" Command="{Binding RemoveAllCommand}" />
      </StackPanel>
</Grid>

Sencilla, cuatro botones que nos permiten enviar notificaciones (con etiquetas y grupos que veremos a continuación) y eliminarlas:

Interfaz gestión de notificaciones

Interfaz gestión de notificaciones

Nos centramos en el primer botón. Al pulsarlo ejecutará un comando de la viewmodel:

private ICommand _sendNotificationsCommand;

public ICommand SendNotificationsCommand
{
     get { return _sendNotificationsCommand = _sendNotificationsCommand ?? new DelegateCommand(SendNotificationsCommandDelegate); }
}

public void SendNotificationsCommandDelegate()
{
     _localNotificationService.ShowToast("Toast Tag", "Contenido", "Tag", string.Empty, false);

     _localNotificationService.ShowToast("Toast Group", "Contenido", string.Empty, "Group", false);

     _localNotificationService.ShowToast("Toast Tag&Group", "Contenido", "Tag", "Group", false);
}

El comando lanzará tres notificaciones:

  • La primera de ellas con etiqueta llamada “Tag”.
  • La segunda lanzará una notificación con grupo llamado “Group”.
  • La última será una notificación con etiqueta y grupo, “Tag” y “Group” respectivamente.

ToastNotification cuenta con las propiedades Tag y Group que permiten administrar facilmente las notificaciones:

Enviando notificaciones

Enviando notificaciones

Las propiedades Tag y Group de la notificación nos permiten quitar notificaciones de forma específica o grupos de notificaciones. Para ello, vamos a añadir nuevos métodos en nuestro servicio de notificaciones locales:

/// <summary>
/// Elimina notificaciones toast por tag o por grupo.
/// </summary>
/// <param name="tag"></param>
/// <param name="group"></param>
public void RemoveToast(string tag, string group)
{
     if (!string.IsNullOrEmpty(group) && string.IsNullOrEmpty(tag))
          ToastNotificationManager.History.RemoveGroup(group);
     else if (string.IsNullOrEmpty(group) && !string.IsNullOrEmpty(tag))
          ToastNotificationManager.History.Remove(tag);
     else
          ToastNotificationManager.History.Remove(tag, group);
}

/// <summary>
/// Elimina todas las notificaciones toast.
/// </summary>
public void RemoveAllToasts()
{
     ToastNotificationManager.History.Clear();
}

Usamos los métodos Remove de ToastNotificationHistory para quitar notificaciones específicas o grupos de notificaciones.

Creamos un método llamado RemoveToast que nos permite eliminar notificaciones por etiqueta, por grupo o por ambas propiedades. Utilizamos el método ToastNotificationHistory.Remove(string)  para eliminar una notificación por etiqueta. Para eliminar una notificación por grupo utilizamos el método ToastNotificationHistory.RemoveGroup(string). Por último, para eliminar notificaciones por etiqueta y grupo utilizamos ToastNotificationHistory.Remove(string, string).

NOTA: No podemos crear un objeto de tipo ToastNotificationHistory directamente pero podemos obtener una referencia a la instancia por medio de la propiedad History de la clase ToastNotificationManager.

El segundo método creado, RemoveAllToasts, utiliza el método ToastNotificationHistory.Clear() para quitar todas las notificaciones del centro de activiades.

El segundo botón ejecutarán un comando en la viewmodel:

private ICommand _removeTagCommand;

public ICommand RemoveTagCommand
{
     get { return _removeTagCommand = _removeTagCommand ?? new DelegateCommand(RemoveTagCommandDelegate); }
}

public void RemoveTagCommandDelegate()
{
     _localNotificationService.RemoveToast("Tag", string.Empty);
}

Que utilizará el método RemoveToast pasandole como parámetro la etiqueta correspondiente. El segundo botón volverá a ejecutar un comando utilizando el método RemoveToast de nuestro servicio de notificaciones locales:

private ICommand _removeGroupCommand;

public ICommand RemoveGroupCommand
{
     get { return _removeGroupCommand = _removeGroupCommand ?? new DelegateCommand(RemoveGroupCommandDelegate); }
}
   
public void RemoveGroupCommandDelegate()
{
     _localNotificationService.RemoveToast(string.Empty, "Group");
}

En este caso pasándole como parámetro el grupo correspondiente. Por último, el último botón eliminará todas las notificaciones. En este caso utilizaremos el método RemoveAllToasts de nuestro servicio:

private ICommand _removeAllCommand;

public ICommand RemoveAllCommand
{
     get { return _removeAllCommand = _removeAllCommand ?? new DelegateCommand(RemoveAllCommandDelegate); }
}

public void RemoveAllCommandDelegate()
{
     _localNotificationService.RemoveAllToasts();
}

Podéis descargar el ejemplo realizado a continuación:

Más información

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s