[Windows Phone 8.1] Usando el sensor de luz

Introducción

Existen grandes aplicaciones en la Windows Phone Store que se adaptan
a ciertas condiciones del medio. Por ejemplo, vamos en el coche con HERE Drive+
y oscurece, el tono de la aplicación cambia de claro a oscuro para no
molestar a los ojos. Lo mismo ocurre al entrar en un túnel o en
condiciones atmosféricas adversas.

Sin duda, una característica sumamente interesante y de agradecer de la Aplicación.

Pero…

¿cómo lo hacen?

El sensor de luz

El sensor de luz es uno de los sensores disponibles en muchos de los dispositivos Windows Phone. Este sensor nos devolverá información relacionada con el nivel de iluminación. Esta medida viene dada en Lux, lumens por metro cuadrado. Los niveles de Lux los podemos catalogar de la siguiente forma:

Condiciones de Luz De(lux) A(lux) Valor Medio (lux) Iluminación
Oscuridad total 0 10 5 1
Muy oscuro 11 50 30 2
Interior oscuro 51 200 125 3
Interior con poca luz 201 400 300 4
Interior normal 401 1000 700 5
Interior con luz 1001 5000 3000 6
Exterior oscuro 5001 10,000 7500 7
Exterior nublado 10,001 30,000 20,000 8
Luz solar directa 30,001 100,000 65,000 9

Manos a la obra

Comenzamos creando un nuevo proyecto desde cero:

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 este artículo vamos a crear un ejemplo que adapte el tema de la
aplicación entre claro y oscuro dependiendo de la luminosidad del
ambiente, gracias al sensor de luz.

Comenzamos añadiendo algunas propiedades básicas e nuestra viewmodel:

public string Info
{
     get
     {
          return "En un lugar de la Mancha, de cuyo nombre no quiero acordarme...";
     }
}

Definimos un valor intermedio entre los Lux que nos indican condiciones de interior y los de exterior para determinar si el “estado” debe ser tema claro u oscuro.

public string State
{
     get { return Lux < 3000 ? "Dark" : "Light"; }
}

Por otro lado, mostraremos en pantalla en todo momento la cantidad de Lux recibidas desde el sensor de luz:

private float _lux;
 
public float Lux
{
     get { return _lux; }
     set
     {
          _lux = value;
          RaisePropertyChanged();
          RaisePropertyChanged("State");
     }
}

Pasamos a definir nuestra interfaz de usuario:

<ScrollViewer>
     <StackPanel>
          <StackPanel
               Orientation="Horizontal">
               <TextBlock Text="LUX:"
                          FontSize="24" />
               <TextBlock
                    Text="{Binding Lux}"
                    FontSize="24"
                    FontWeight="Black"
                    Margin="5, 0"/>
          </StackPanel>
          <TextBlock
               Text="{Binding Info}"
               FontSize="24"
               TextWrapping="Wrap" />
     </StackPanel>
</ScrollViewer>

Muy sencilla. Mostramos el valor de Lux recibidos del sensor de luz y el texto de la propiedad Info de la viewmodel.

El resultado:

Al entrar en la vista, en la sobreescritura del método OnNavigatedTo, verficamos si el dispositivo cuenta con sensor de luz. Para ello, utilizamos el método GetDefault() de la clase LightSensor disponible como no podía ser de otra forma en el namespace Windows.Devices.Sensors. Si el sensor esta disponible el método GetDefault() devolverá una instancia del sensor de luz.

Una vez establecida la referencia,estableceremos el valor de ReportInterval.
Esta propiedad indica en milisegundos el valor de la tasa de refresco
en la que el sensor tomará de nuevo información. Por defecto cuenta con
un valor dado por la implementación del driver del sensor. Si deseamos
ajustar el valor a las condiciones de nuestra aplicación bastará con asignar un valor diferente a cero.

NOTA: Al salir de la Aplicación recordad devolver el valor a cero. Esto es importante para no afectar al consumo energético.

Por último, llegamos a la forma en la que obtenemos la información. Tenemos dos opciones:

  • GetCurrentReading: Obtiene una vez el valor de Lux facilitado por el sensor.
  • ReadingChanged: Realizando una suscripción a este
    evento obtenemos información del sensor de manera continuada. La tasa de
    refresco vendrá indicada por la propiedad ReportInternval.
public override Task OnNavigatedTo(NavigationEventArgs args)
{
     _dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
     _lightSensor = LightSensor.GetDefault();
 
     if (_lightSensor != null)
     {
          uint minReportInterval = _lightSensor.MinimumReportInterval;
          _lightSensor.ReportInterval = minReportInterval > 1000 ? minReportInterval : 1000;
          _lightSensor.ReadingChanged += _lightSensor_ReadingChanged;
     }
     else
     {
          Debug.WriteLine("El dispositivo no cuenta con el sensor de luz");
     }
 
      return null;
}

Al salir de la vista, en el método OnNavigatedFrom, cancelamos la suscripción al evento ReadingChanged y establecemos el valor de ReportInterval a cero:

public override Task OnNavigatedFrom(NavigationEventArgs args)
{
     if (_lightSensor != null)
     {
          _lightSensor.ReportInterval = 0;
          _lightSensor.ReadingChanged -= _lightSensor_ReadingChanged;
     }
 
     return null;
}

Llega el mometo cumbre del artículo, a continuación vamos a ver como obtenemos el valor de Lux:

void _lightSensor_ReadingChanged(LightSensor sender, LightSensorReadingChangedEventArgs args)
{
     _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
     {
          Lux = args.Reading.IlluminanceInLux;
          AppFrame.RequestedTheme =
          State.Equals("Dark", StringComparison.CurrentCultureIgnoreCase) ?
               ElementTheme.Dark : ElementTheme.Light;
     });
 
     Debug.WriteLine("Lux: {0}", Lux);
}

El método anterior se lanzará de manera continuada pudiendo acceder a la información del sensor. Obtenemos el valor de Lux
dados por el sensor, actualizará nuestra propiedad State y dependiendo
del valor de la misma, cambiamos el tema utilizado de claro a oscuro o
viceversa.

NOTA: La ejecución del método se realiza en otro
hilo en background. Por lo tanto cualquier acción que conlleve un
actualización de la UI debemos envolverla en una llamada de Dispatcher.


Podéis ver el resultado del ejemplo en video a continuación:

Y la App Universal realizada como ejemplo la podéis descargar del siguiente enlace:

Como hemos podido ver en este artículo, el uso del sensor de luz es
una tarea bastante sencilla que nos permite adaptar la UI a condicones
ambientales mejorando la experiencia de usuario.

NOTA: Exactamente la misma API la tenemos disponible para Apps Windows Store.

Recordar que podéis dejar en los comentarios cualquier tipo de sugerencia o pregunta.

Más información

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *