[Tips and Tricks] Windows 10: Custom State Trigger para gestionar cambios en el estado de la batería

Battery - 03Introducción

Entre la lista de factores importantes que marcan diferencia en practicamente cualquier dispositivo móvil encontramos la batería. Hemos ido viendo una mejora paulatina pero gradual en la calidad y duración de las mismas. Sin embargo, las exigencias requeridas también han ido incrementando. Mayor cantidad de aplicaciones usadas por los usuarios, más sensores, etc.

A pesar de las posibilidades ofrecidas por el sistema para poder gestionar el uso de la batería, reducir opciones activas cuando empieza a tener un nivel escaso, en nuestras propias aplicaciones y como desarrolladores, contamos con APIs para poder trabajar con la batería; detectar capacidad, porcentaje y otras opciones.

En este artículo, vamos a crear varios Adaptive Triggers personalizados con el objetivo de obtener información del estado y porcentaje de la batería.

¿AdaptiveTriggers?

Con la llegada del SDK de Windows 10 tenemos la posibilidad de crear Apps Universales con un único binario que funcione en múltiples plataformas. Es un paso importante pero que conlleva realizar una acción que sera comun, diferenciar entre las diferentes plataformas donde correrá dicho binario para poder adaptar la interfaz de usuario. Con ese objetivo llegan los Adaptive Triggers. Recibimos potentes novedades en los Visual States:

  • Podemos modificar propiedades sin necesidad de animaciones. Anteriormente, la síntaxis era mucho más verbosa y necesitábamos utilizar StoryBoards para cambiar cualquier propiedad por simple que fuese.
  • Contamos con los StateTrigger. Podemos lanzar Triggers cuando se aplica un estado visual sin necesidad de código adyacente en el code-behind. El concepto es muy similar a los Triggers que tenemos disponible en WPF y Silverlight y el objetivo es el mismo, realizar un cambio cuando una condición cambia.

Actualmente contamos con un tipo de StateTrigger por defecto, el Adaptive Trigger que cuenta con los siguientes tipos:

  • MinWindowWidth
  • MinWindowHeight

Ambos nos permiten detectar cambios dinámicos en el tamaño de la pantalla de modo que se adapte el tamaño de la pantalla entre pantallas pequeñas y grandes. El funcionamiento es similar a las media queries en CSS por ejemplo. Se crearán diferentes estados estableciendo unos altos y anchos mínimos, de modo que, cuando la pantalla es más grande que el tamaño asignado se activará el estado visual.

Custom State Triggers relacionados con estado de batería

Los Triggers disponibles son lo suficientemente potentes como para permitirnos un trabajo correcto adaptando la interfaz de usuario pero… ¿podemos llegar más lejos?, ¿y si no es suficiente?

Podemos crear state triggers propios creando una clase que herede de la clase base llamada StateTriggerBase disponible dentro del namespace Windows.UI.Xaml.

En esta ocasión vamos a crear dos state triggers:

  • BaterryStatusTrigger: Nos permitirá detectar el estado de la batería, es decir, si esta cargándose, descargándose, etc.
  • BatteryPercentageTrigger: Nos indicará si el nivel de la batería es alto, medio o bajo para poder actuar en consecuencia.

BatteryStatusTrigger

Comenzamos creando el primer StateTrigger. Creamos una clase que hereda de StateTriggerBase:

public class BatteryStatusTrigger : StateTriggerBase
{

}

Para facilitar la verificación del estado, evitando errores con cadenas vamos a crear una enumeración llamada BatteryChargingStatus:

public enum BatteryChargingStatus        
{            
     Charging = 0,
     Discharging = 1,
     Unknown = 2        
}

Y una propiedad del tipo de la enumeración que usaremos para verificar el valor actual:

private static BatteryChargingStatus _charging;

En nuestro StateTrigger crearemos una propiedad de dependencia llamada BatteryStatus que nos permitirá pasar el estado de la batería, de modo que podamos lanzar la condición idónea en cada caso:

public BatteryChargingStatus BatteryStatus
{            
     get { return (BatteryChargingStatus)GetValue(BatteryStatusProperty); }            
     set { SetValue(BatteryStatusProperty, value); }
}
        
public static readonly DependencyProperty BatteryStatusProperty =
       DependencyProperty.Register("BatteryStatus", typeof(BatteryChargingStatus), typeof(BatteryStatusTrigger),
       new PropertyMetadata(false, OnBatteryStatusPropertyChanged));
        
private static void OnBatteryStatusPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)       
{           
     var obj = (BatteryStatusTrigger)d;
     var val = (BatteryChargingStatus)e.NewValue;

     obj.SetActive(val == _charging);       
}

Para acceder a información relacionada con la batería utilizaremos el namespace Windows.Devices.Power donde tendremos acceso a la clase AggregateBattery. Esta clase agrupa todas las baterías que pueda tener el dispositivo (podrían ser más de una) otorgando acceso a información y reportes de forma agrupada.

Utilizamos AggregateBattery para obtener información de la batería utilizando el método GetReport que nos devolverá una instancia de tipo BatteryReport.

Accederemos a la propiedad Status (enumeración BatteryStatus) para verificar el estado de la batería:

public BatteryStatusTrigger()       
{
     UpdateStatus();

     Windows.Devices.Power.Battery.AggregateBattery.ReportUpdated += (s, a) =>
     {
          UpdateStatus();
     };        
}

Dependiendo del valor de Status:

  • NotPresent: No se encuentra batería.
  • Discharging: Batería descargándose.
  • Idle: Inactiva.
  • Charging: Batería cargándose.

Estableceremos el valor adecuado de nuestra propia enumeración, BatteryChargingStatus.

private void UpdateStatus()
{
     var batteryReport = Windows.Devices.Power.Battery.AggregateBattery.GetReport();

     switch (batteryReport.Status)
     {
          case Windows.System.Power.BatteryStatus.Charging:
               _charging = BatteryChargingStatus.Charging;
               break;
          case Windows.System.Power.BatteryStatus.Discharging:
               _charging = BatteryChargingStatus.Discharging;
               break;
          default:
               _charging = BatteryChargingStatus.Unknown;
               break;            
     }        
}

De esta forma, podemos facilmente notificar al usuario o realizar ajustes en la interfaz dependiendo del estado de la batería.

BatteryPercentageTrigger

Continuamos con el segundo de los StateTrigger. En esta ocasión nuestra intención es verificar el porcentaje de carga para poder realizar ajustes en la interfaz con facilidad dependiendo de la capacidad de batería disponible.

De nuevo, creamos una clase que hereda de StateTriggerBase:

public class BatteryPercentageTrigger : StateTriggerBase    
{

}

Creamos enumeración personalizada para saber el estado de la batería:

public enum BaterryPercentageState        
{            
     VeryHight = 0,
     Hight = 1,
     Medium = 2,
     Low = 3,
     Verylow = 4,
     Unknown = 5        
}

Desde valores muy elevados a muy bajos en función del nivel de batería.

private static BaterryPercentageState _batteryPercentageState;

En nuestro StateTrigger crearemos una propiedad de dependencia llamada BatteryPercentage que nos permitirá pasar el estado de carga de la batería, de modo que podamos lanzar la condición idónea en cada caso:

public BaterryPercentageState BaterryPercentage        
{            
     get { return (BaterryPercentageState)GetValue(BaterryPercentageProperty); }            
     set { SetValue(BaterryPercentageProperty, value); }        
}
        
public static readonly DependencyProperty BaterryPercentageProperty =
       DependencyProperty.Register("BaterryPercentage", typeof(BaterryPercentageState), typeof(BatteryPercentageTrigger),
       new PropertyMetadata(BaterryPercentageState.Unknown, OnBaterryPercentagePropertyChanged));
        
private static void OnBaterryPercentagePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)        
{            
     var obj = (BatteryPercentageTrigger)d;
     var val = (BaterryPercentageState)e.NewValue;

     obj.SetActive(val == _batteryPercentageState);        
}

Al igual que en StateTrigger anterior utilizaremos los métodos de obtención de reportes y evento de cambio en reporte para verificar de manera exacta el porcentaje de la batería:

public BatteryPercentageTrigger()        
{            
     UpdatePercentage();

     Windows.Devices.Power.Battery.AggregateBattery.ReportUpdated += (s, a) =>
     {
          UpdatePercentage();
     };        
}

Utilizaremos las propiedades FullChargeCapacityInMilliwattHours, que nos indica la capacidad de la batería junto la propiedad RemainingCapacityInMilliwattHours, que nos indica la capacidad disponible ambas en mW-h para calcular el porcentaje de la batería:

private void UpdatePercentage()        
{
     var batteryReport = Windows.Devices.Power.Battery.AggregateBattery.GetReport();

     if (batteryReport.FullChargeCapacityInMilliwattHours != null && batteryReport.RemainingCapacityInMilliwattHours != null)
     {
          var percentage = (batteryReport.RemainingCapacityInMilliwattHours.Value /
              (double)batteryReport.FullChargeCapacityInMilliwattHours.Value) * 100;

          if (percentage <= 100 && percentage > 80)
          {
              _batteryPercentageState = BaterryPercentageState.VeryHight;
          }
          else if (percentage <= 80 && percentage > 60)
          {
              _batteryPercentageState = BaterryPercentageState.Hight;
          }
          else if (percentage <= 60 && percentage > 40)
          {
              _batteryPercentageState = BaterryPercentageState.Medium;
          }
          else if (percentage <= 40 && percentage > 20)
          {
               _batteryPercentageState = BaterryPercentageState.Low;
          }
          else if (percentage <= 20 && percentage > 1)
          {
              _batteryPercentageState = BaterryPercentageState.Verylow;
          }
          else
          {
             _batteryPercentageState = BaterryPercentageState.Unknown;
          }
     }        
}   

Segun porcentaje de la batería estableceremos el valor adecuado de nuestra enumeración de tipo BatteryPercentageState.

Utilizando los StateTriggers creados

Con ambos StateTriggers a nuestro servicio ha llegado el momento de utilizarlos. Contaremos con una interfaz sumamente simple:

<TextBlock x:Name="BatteryText"               
           Text="Battery Status"/>

Mostraremos un texto diferente según el porcentaje de la batería utilizando BatteryPercentageTrigger y el texto en color verde si el dispositivo esta cargando la batería o rojo si al contrario, la batería se esta descargando utilizando BatteryStatusTrigger:

<VisualStateManager.VisualStateGroups>
     <VisualStateGroup>
          <VisualState x:Name="Charging">
              <VisualState.StateTriggers>
                  <customStateTriggers:BatteryStatusTrigger BatteryStatus="Charging" />
              </VisualState.StateTriggers>
              <VisualState.Setters>
                  <Setter Target="BatteryText.Foreground" Value="Green" />
              </VisualState.Setters>
          </VisualState>
          <VisualState x:Name="Discharging">
              <VisualState.StateTriggers>
                   <customStateTriggers:BatteryStatusTrigger BatteryStatus="Discharging" />
               </VisualState.StateTriggers>
               <VisualState.Setters>
                   <Setter Target="BatteryText.Foreground" Value="Red" />
               </VisualState.Setters>
           </VisualState>
       </VisualStateGroup>
       <VisualStateGroup>
           <VisualState x:Name="PercentageVeryHight">
               <VisualState.StateTriggers>
                   <customStateTriggers:BatteryPercentageTrigger BaterryPercentage="VeryHight" />
               </VisualState.StateTriggers>
               <VisualState.Setters>
                  <Setter Target="BatteryText.Text" Value="Very hight" />
               </VisualState.Setters>
          </VisualState>
          <VisualState x:Name="PercentageHight">
               <VisualState.StateTriggers>
                   <customStateTriggers:BatteryPercentageTrigger BaterryPercentage="Hight" />
               </VisualState.StateTriggers>
               <VisualState.Setters>
                   <Setter Target="BatteryText.Text" Value="Hight" />
               </VisualState.Setters>
           </VisualState>
           <VisualState x:Name="PercentageMedium">
               <VisualState.StateTriggers>
                   <customStateTriggers:BatteryPercentageTrigger BaterryPercentage="Medium" />
               </VisualState.StateTriggers>
               <VisualState.Setters>
                   <Setter Target="BatteryText.Text" Value="Medium" />
               </VisualState.Setters>
           </VisualState>
           <VisualState x:Name="PercentageLow">
               <VisualState.StateTriggers>
                   <customStateTriggers:BatteryPercentageTrigger BaterryPercentage="Low" />
               </VisualState.StateTriggers>
               <VisualState.Setters>
                   <Setter Target="BatteryText.Text" Value="Low" />
               </VisualState.Setters>
           </VisualState>
           <VisualState x:Name="PercentageVeryLow">
               <VisualState.StateTriggers>
                   <customStateTriggers:BatteryPercentageTrigger BaterryPercentage="Verylow" />
               </VisualState.StateTriggers>
               <VisualState.Setters>
                   <Setter Target="BatteryText.Text" Value="Very low" />
               </VisualState.Setters>
           </VisualState>
     </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

Si ejecutamos la App:

Custom State Triggers de batería

Custom State Triggers de batería

Nuestra aplicación se ejecuta en un dispositivo móvil con la batería descargándose y a nivel bajo, es decir, por debajo de 40% y por encima de 20%.

Podéis acceder al código fuente directamente en GitHub:

Ver GitHub

Recordar que cualquier tipo de duda o sugerencia la podéis dejar en los comentarios de la entrada.

Más Información

 

2 pensamientos en “[Tips and Tricks] Windows 10: Custom State Trigger para gestionar cambios en el estado de la batería

  1. Hola, permíteme una petición. he estado mirando por internet y si la documentación de Windows Phone 8.0 era mala y la de Windows Phone 8.1 peor, la de W10 (universal apps) ya ni te cuento, así que si no te es mucha molestia, podrías crear (a modo de como ha hecho hoy el bruno con la band) “postear” una serie de tutoriales, vídeos, cursos, etc. de como desarrollar para windows phone (w10).
    Gracias

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