Acabo de concluir uma série de vídeos sobre o uso de sensores em UWP, que publiquei no Channel 9. São vídeos curtos, com até 15 minutos cada. Vale a pena dar uma conferida e ver como usar os sensores disponíveis no Windows 10 (os programas funcionam tanto no desktop, em tablets, como no smartphone Windows 10):

https://channel9.msdn.com/Series/Windows-Development/Trabalhando-com-Sensores-em-UWP-Parte-1-Sensor-de-Luz – Sensor de Luz – Mostra como usar o sensor de luz para mudar a visualização conforme a luminosidade do ambiente

https://channel9.msdn.com/Series/Windows-Development/Trabalhando-com-Sensores-em-UWP-Parte-2-Bssola – Bússola – Mostra como usar a bússola para dizer ao usuário a sua orientação

https://channel9.msdn.com/Series/Windows-Development/Trabalhando-com-Sensores-em-UWP-Parte-3-Inclinmetro – Inclinômetro – Usa o inclinômetro para mover uma bola na tela conforme o usuário inclina seu dispositivo para a direita ou para a esquerda

https://channel9.msdn.com/Series/Windows-Development/Trabalhando-com-Sensores-em-UWP-Parte-4-Acelermetro – Acelerômetro – Usa o acelerômetro para fazer uma bola pular na tela quando se chacoalha o dispositivo

https://channel9.msdn.com/Series/Windows-Development/Trabalhando-com-Sensores-em-UWP-Parte-5-Geolocalizao – Geolocalização – Usa o sensor de localização para obter o local atual, consultar um serviço de meteorologia e saber se irá chover no seu local atual

This last part in the series will show a different kind of sensor – the Geolocation sensor. In the strict sense, we can’t call this as a sensor, because the geolocation service will get the current location from the GPS sensor if it exists. If not, it will use other methods, like the network of wifi to detect the current location.

To get the current location, you must work in a different way that we worked for the other sensors:

  • You must add the Location capability to the app manifest
  • The user must consent with the use of the current location
  • You should instantiate a new Geolocator instance (and not get one with GetDefault)
  • There is no ReadingChanged event, but StatusChanged event

Even with these changes, you will see that it’s very easy to work with the geolocation. In this post we will develop a program that gets the current location and queries a weather service to get the forecast and see if it will rain.

Will it rain?

In Visual Studio, create a blank UWP project. To query the weather, we will use an open source project that has a C# API to query the OpenWeather map (http://openweathermap.org/API), located in https://github.com/joancaron/OpenWeatherMap-Api-Net. We can add this lib by using the Nuget Package manager (right click the References node in Solution Explorer and select Manage Nuget Packages). Just search for openweather and install the lib:

image

Just one note here: the official package doesn’t support Windows 10, so you must choose a fork of the project (the third project in the list) to install.

Then, you must add the Location capability to the app manifest. On the solution Explorer, open package.appxmanifest and go to the tab Capabilities. There, check the Location box.

image

Then, in the Main window, add this XAML:

[sourcecode language=”csharp” padlinenumbers=”true”]
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock x:Name="RainText"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="30"/>
</Grid>
[/sourcecode]

In the constructor of MainPage, we must ask for the user permissions an process the response:

[sourcecode language=”csharp”]
public MainPage()
{
this.InitializeComponent();
InitializeLocator();
}

public enum RainStatus
{
Rain,
Sun
};

private async void InitializeLocator()
{
var userPermission = await Geolocator.RequestAccessAsync();
switch (userPermission)
{
case GeolocationAccessStatus.Allowed:
RainText.Text = "Updating rain status…";
Geolocator geolocator = new Geolocator();
Geoposition pos = await geolocator.GetGeopositionAsync();
try
{
RainText.Text = await GetRainStatus(pos) == RainStatus.Rain ?
"It’s possible to rain, you’d better take an umbrella" :
"It will be a bright an shiny day, go out and enjoy";
}
catch
{
RainText.Text = "Got an error while getting weather";
}
break;

case GeolocationAccessStatus.Denied:
RainText.Text = "I cannot check the weather if you don’t give me the access to your location…";
break;

case GeolocationAccessStatus.Unspecified:
RainText.Text = "I got an error while getting location permission. Please try again…";
break;
}
}
[/sourcecode]

If the user allows access to the location data, we get the current position with GetGeopositionAsync and then we use this position to get the rain status, using the open weather map API. The GetRainStatus method is:

[sourcecode language=”csharp”]
private async Task GetRainStatus(Geoposition pos)
{
var client = new OpenWeatherMapClient("YourPrivateId");
var weather = await client.CurrentWeather.GetByCoordinates(new Coordinates()
{
Latitude = pos.Coordinate.Point.Position.Latitude,
Longitude = pos.Coordinate.Point.Position.Longitude
});
return weather.Precipitation.Mode == "no" ? RainStatus.Sun : RainStatus.Rain;
}
[/sourcecode]

To use the OpenWeather API, you must register with the site and get an API key. For low usage, the key and usage is free. You can register at http://openweathermap.org/appid

When you run the program, you are able to know if you will need to take an umbrella to go out:

image

Conclusions

As you could see, working with sensors is very easy and it can offer a better experience for your users. You can integrate them with your apps in many different ways. In this post, I’ve shown how to use the weather API to query if it will rain in your location, a simple, but useful program.

All source code for this project is in https://github.com/bsonnino/GeoLocation

In the previous posts (Light sensor, Compass and Inclinometer), I’ve shown how to use some sensors in a UWP app. In this post, I’ll show how to use another sensor, the accelerometer. The accelerometer will measure the acceleration of the device. This measure is very useful to see when the device is moved.

This sensor will show the acceleration in the three axis, X, Y and Z, and has a particularity: as it will show the forces that the device is submitted, its measure usually is not 0, because the device is always submitted to the gravity force (unless you take it to the space). The normal measure for the standing device is 1, the gravity force. When you move it, the measure should be different than 1.

Making a ball jump in UWP

For this post, I will develop a program that shows a ball at the bottom of the window, and when the user shakes the device, the ball jumps, using an animation. The stronger the shake, the ball will jump higher.

The sensor gives three measures, but I am not interested in the acceleration in every axis. I just want the magnitude of the acceleration, and that’s given by this formula:

[sourcecode language=”text”]
magnitude = sqrt(x^2 + y^2 + z^2)
[/sourcecode]

The magnitude of the acceleration is the square root of the sum of the squares of the three measures.

With this information, we can start our program. Create a new blank UWP solution. In the main page, change the main element to a Canvas and add an ellipse to it:

[sourcecode language=”xml”]
<Canvas Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Ellipse Width="80" Height="80" Fill="Red" x:Name="Ball"/>
</Canvas>
[/sourcecode]

In the constructor of MainPage, add the code to position the ball, get the accelerometer and add the ReadingChanged event handler:

[sourcecode language=”csharp”]
public MainPage()
{
this.InitializeComponent();
Loaded += (s, e) =>
{
Canvas.SetLeft(Ball, ActualWidth / 2 – 40);
Canvas.SetTop(Ball, ActualHeight – 80);
var accelerometer = Accelerometer.GetDefault();
if (accelerometer == null)
{
return;
}
accelerometer.ReadingChanged += async (s1, e1) =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
var magnitude = Math.Sqrt(
e1.Reading.AccelerationX * e1.Reading.AccelerationX +
e1.Reading.AccelerationY * e1.Reading.AccelerationY +
e1.Reading.AccelerationZ * e1.Reading.AccelerationZ);
if (magnitude &gt; 1.5)
JumpBall(magnitude);

});
};
};
}
[/sourcecode]

The code is very similar to the ones in the previous posts: we set the ball position to the bottom of the window and then set the ReadingChanged event handler. This handler gets the magnitude of the reading and then, if the magnitude is greater than 1.5G, it calls JumpBall, to make the ball jump. The code for JumpBall is:

[sourcecode language=”csharp”]
private void JumpBall(double acceleration)
{
var da = new DoubleAnimation()
{
From = ActualHeight-80,
To = ActualHeight-80-acceleration * 200,
AutoReverse = true,
Duration = new Duration(TimeSpan.FromSeconds(1))
};
Storyboard.SetTarget(da, Ball);
Storyboard.SetTargetProperty(da, "(Canvas.Top)");
var sb = new Storyboard();
sb.Children.Add(da);
sb.Begin();
}
[/sourcecode]

We create a DoubleAnimation with the bottom of the window as the starting point, the end point is given by the magnitude of the reading. The animation is related to the Canvas.Top attached property, related to the ball. With all that set, we start the animation.

That way, when the user shakes the device, the ball jumps. Now, when you run the app and shake the device, the ball will jump.

image

Conclusions

With the accelerometer, you can give your users more interactivity, detecting when they move or shake the device and act accordingly. The accelerometer is very easy to use and can improve the games usability a lot.

The full source code for this project is in https://github.com/bsonnino/JumpingBall

In the previous two posts (Light sensor and Compass), I’ve shown how to use the sensors in a UWP app. Working with them is very easy and it can enhance the usability of your app. In this post, we willshow how to use another sensor, the Inclinometer.

This sensor is used a lot for games, as it detects the inclination of the device. That way, the user can control the game by tilting the device. Pretty cool, no? It’s note a pure sensor, as you won’t have an inclinometer in your device, but it gets its data from other two sensors, the accelerometer and the gyroscope.

The sensor usage is similar to the other sensors, and it shows three measures, Yaw (the rotation on the Z axis), Pitch (rotation on the X axis) and Roll (rotation on the Y axis):

inclinometer

(source – https://msdn.microsoft.com/en-us/windows/uwp/devices-sensors/sensors)

Playing with a ball in UWP

To show the usage f an inclinometer, we will create a project that can be a starting point for a game. We will draw a ball in the window and, depending on how the user tilts the device, the ball will move faster or slower, to the left and to the right.

We will start creating a new UWP blank app. Change the main element in the main page to a Canvas and add a new Ellipse to it:

[sourcecode language=”xml” padlinenumbers=”true”]
<Canvas Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Ellipse Width="80" Height="80" Fill="Red" x:Name="Ball"/>
</Canvas>
[/sourcecode]

In the constructor of the MainPage, we position the ball and add the code to initialize the inclinometer and set its ReadingChanged event handler:

[sourcecode language=”csharp”]
public MainPage()
{
this.InitializeComponent();
Loaded += (s, e) =>
{
Canvas.SetLeft(Ball, ActualWidth / 2 – 40);
Canvas.SetTop(Ball, ActualHeight – 80);
var inclinometer = Inclinometer.GetDefault();
if (inclinometer == null)
{
return;
}
inclinometer.ReadingChanged += async (s1, e1) =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
var position = Canvas.GetLeft(Ball);
var newPosition = position + e1.Reading.RollDegrees;
if (newPosition ActualWidth – 80)
newPosition = ActualWidth – 80;
Canvas.SetLeft(Ball, newPosition);
});
};
};
}
[/sourcecode]

As you can see, this time I’m doing all the initialization in the handler of the Loaded event of the page. That’s because ActualWidth and ActualHeight of the page aren’t set before the Loaded event fires, and if I don’t use this handler, the ball would be placed in the wrong place. As we have a Canvas, we position the ball with the attached properties Left and Top. In the code behind, this is done with the static methods Canvas.SetLeft and Canvas.SetTop.

The next step is to get the Inclinometer sensor with GetDefault and set its ReadingChanged handler. It will get the current position of the ball and will set the new position depending on the Roll (number of degrees of tilt in the Y position). That way, if the user tilts more, the ball will move faster. If he tilts less, it will move slower.

With that code in place, we have our moving ball project complete and can run it. If your device has an inclinometer, you can see the ball moving. If it doesn’t have, you can use a Windows Phone and see the same app running there.

image

Conclusions

Using the inclinometer is very simple and you can provide your users a different kind of input with it, you just need to get its reading and move the elements in your app according to the tilt of the device.

The source code for this app is in https://github.com/bsonnino/MovingBall

In the last post, I have shown how to use the light sensor to get light data and offer a better experience for the user. In this post, I will show another sensor available in 2-in-1 devices and tablets: the compass. The compass is a sensor the shows the direction, related to the magnetic north.

On physical compasses, this reading is given by a magnetic needle that is always pointing to the magnetic north. When you turn the compass, it will show you where are you heading to. In computers and smartphones, there is no magnetic needle, but the sensor shows the angle of the device, related to the magnetic north. To use the sensor, we must create a program that does the same three steps of the last post:

  • Get an instance of the sensor with the GetDefault method
  • Set its properties
  • Set a handler for the ReadingChanged

In this post, we will create a program that simulates a physical compass and shows the heading of the device.

Creating a compass simulator in UWP

The first step is to create a blank UWP project. In this project, add images tor the compass background and needle (I got my background from http://www.clipartbest.com/images-of-a-compass and the needle from http://www.clker.com/clipart-compassnorth.html) in the Assets folder.

Then, add the two images to the main window:

[sourcecode language=”xml” padlinenumbers=”true”]
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Image Source="Assets\\Compass.png" HorizontalAlignment="Stretch"
           VerticalAlignment="Stretch" Stretch="Uniform"/>
    <Image Source="Assets\\Compassnorth-Hi.png" HorizontalAlignment="Stretch"
           VerticalAlignment="Stretch" Stretch="Uniform" x:Name="Needle"/>
</Grid>
[/sourcecode]

In the constructor of MainWindow, we must get the compass and set the ReadingChanged event handler:

[sourcecode language=”csharp”]
public MainPage()
{
this.InitializeComponent();
var compass = Compass.GetDefault();
if (compass == null)
{
return;
}
compass.ReadingChanged += async (s, e) =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
RotateNeedle(e.Reading.HeadingMagneticNorth);
});
};
}
[/sourcecode]

The event handler just calls RotateNeedle, passing the reading angle as parameter. RotateNeedle is very simple:

[sourcecode language=”csharp”]
private void RotateNeedle(double angle)
{
var transform = new RotateTransform() { Angle = angle };
Needle.RenderTransformOrigin = new Windows.Foundation.Point(0.5, 0.5);
Needle.RenderTransform = transform;
}
[/sourcecode]

It just creates a RotateTransform, setting the angle to the reading angle, sets the origin of the rotation on the middle of the needle and then sets the RenderTransform property to this transform.

With this, you have a compass simulator that works both on desktops and smartphones. As you turn the device, the needle will be pointing to the magnetic north and the head will show you the direction.

image

Conclusions

As you can see, working with the compass is very easy, you can easily get the reading of the sensor and change the view, depending on what the user is heading. This is one more tool that you can use to give the user a better experience.

The full source code for the project is in https://github.com/bsonnino/Compass

Some time ago, computer makers introduced new classes of Windows devices: the 2-in-1 and the tablets. These kinds of computers bring a lot of innovation – the 2-in-1 computers can be used as notebooks and tablets, while still maintaining their power: you can have very powerful devices, that can be used at the office and on the road, thus avoiding the need of having a tablet and a notebook.

But this kind of devices have another kind of innovations that are not visible at first sight: sensors. With them, you can have the same experience you have with a smartphone – you can use the accelerator for games or gestures, the GPS for location and routing and many others. This series of posts will show how to use these sensors in UWP, so you can give your user a better experience, so he can use all the resources of his device. And all this with an added bonus, thanks to UWP development – the same project will work both on desktop devices and smartphones.

Working with sensors in UWP

Basically, working with sensors in UWP is pretty much the same:

  • You get an instance of the sensor with the GetDefault method
  • You set its properties
  • You set a handler for the ReadingChanged

That’s all that is needed to work with sensors in UWP. So, let’s go and start with the first sensor: the light sensor.

Working with the light sensor

The light sensor can be used to detect the environment lighting and adjust the screen brightness according to the external light, so the use has the best experience. In this post I will show a simple way to create the effect used in GPS devices: when it’s day, it shows the display with a white background and when it’s night, it shows it with a black background.

To get this effect, the simplest way is to use themes. UWP has three default themes, Dark, Light and High Contrast and you can set them by using the RequestedTheme property of the control (in our case, the main window). So, let’s start.

In Visual Studio create a UWP application and add this XAML to the main page:

[sourcecode language=”xml” padlinenumbers=”true”]

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Day" HorizontalAlignment="Center" x:Name="MainText"
VerticalAlignment="Center" FontSize="48" />
</Grid>
[/sourcecode]

Then, in the MainPage constructor, we will initialize the light sensor and process its readings:

[sourcecode language=”csharp”]
public MainPage()
{
this.InitializeComponent();
var lightSensor = LightSensor.GetDefault();
if (lightSensor == null)
{
MainText.Text = "There is no light sensor in this device";
return;
}
lightSensor.ReportInterval = 15;
lightSensor.ReadingChanged += async (s, e) =>
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
if (e.Reading.IlluminanceInLux < 30)
{

RequestedTheme = ElementTheme.Dark;
MainText.Text = "Night";
}
else
{
RequestedTheme = ElementTheme.Light;
MainText.Text = "Day";
}
});
};
}
[/sourcecode]

We must use the Dispatcher to change the theme and text, because the ReadingChanged can be called in a different thread of the UI thread. When the Illuminance reading is less than 30 Lux, we change to the Dark theme and change the text to Night.

Now, when you run the program in a device that has a light sensor, you will see the default view in daylight like this:

Day

If you cover the light sensor to simulate the lack of light, you will see something like this:

Night

Conclusions

As you can see, it’s very easy to work with sensors. With them, you can give a better experience for your users, so they can enjoy using your apps. And a added benefit is that you can use the same app in a desktop or in a Windows Phone.

The source code for this app is in https://github.com/bsonnino/LightSensor

Os novos dispositivos 2-em-1 Windows 10 trouxeram uma novidade: você pode usar os seus diversos sensores para aumentar a experiência do usuário em seus programas.

O Delphi trouxe a possibilidade de usar estes sensores em seus programas, tanto usando a VCL como no FireMonkey. A minha palestra na CodeRage Brasil mostra como você pode criar seus programas Delphi que utilizam a classe TSensor para melhorar a experiência do usuário. Confira em  https://www.youtube.com/watch?v=U2uKyuKwJcY