Workout, a Tizen Sample App for Monitoring Health Sensors
-
Similar Topics
-
By Samsung Newsroom
This is the final blog in a series to introduce the sample application Workout, a Tizen example for monitoring health sensors on a wearable device.
The first blog, Workout -- A Tizen Sample App for Monitoring Health Sensors, presented the basic features of the application. The second blog, Adding Distance Traveled to the Tizen Workout Sample App, described how distance traveled is calculated. The third blog, Adding Heart Rate Summary to the Tizen Workout App, demonstrated how heart rate data is gathered.
This blog describes how the application uses the Tizen.Wearable.CircularUI extension of the Xamarin.Forms framework. This extension provides a set of components customized for the wearable profile that makes development easier and efficient. It provides, among others, a CircleListView component, which is used on the summary view of the application. The list contains elements that differ from each other in terms of appearance. Apart from the different contents of the text, they allow you to:
Use different icon images Set different positions of text elements on selected elements Use converters for selected list items Display the action button on selected elements of the list
Time
Distance
Pace
Intensity ItemSource
The information about how the individual elements of the list should look like is provided by ItemSource, which is represented by the list of elements of the DetailsItemData class.
Views/Workout/DetailsPageView.xaml
<cui:CircleListView.ItemsSource> <x:Array Type="{x:Type models:DetailsItemData}"> <models:DetailsItemData Name="time" Value="{Binding ElapsedTime}" Icon="images/details_time_icon.png"> <models:DetailsItemData.ValueBounds> <Rectangle X=".5" Y="193" Width="-1" Height="-1" /> </models:DetailsItemData.ValueBounds> <models:DetailsItemData.NameBounds> <Rectangle X=".5" Y="245" Width="-1" Height="-1" /> </models:DetailsItemData.NameBounds> </models:DetailsItemData> <models:DetailsItemData Name="distance" Value="{Binding Distance}" Icon="images/details_distance_icon.png"> <models:DetailsItemData.ValueBounds> <Rectangle X=".5" Y="193" Width="-1" Height="-1" /> </models:DetailsItemData.ValueBounds> <models:DetailsItemData.NameBounds> <Rectangle X=".5" Y="245" Width="-1" Height="-1" /> </models:DetailsItemData.NameBounds> </models:DetailsItemData> <models:DetailsItemData Name="average pace" Value="{Binding AveragePace}" Icon="images/details_average_pace_icon.png"> <models:DetailsItemData.ValueBounds> <Rectangle X=".5" Y="193" Width="-1" Height="-1" /> </models:DetailsItemData.ValueBounds> <models:DetailsItemData.NameBounds> <Rectangle X=".5" Y="245" Width="-1" Height="-1" /> </models:DetailsItemData.NameBounds> </models:DetailsItemData> <models:DetailsItemData Name="intensity" Value="{Binding Intensity, Converter={StaticResource BpmRangeValueConverter}}" Icon="images/details_intensity_icon.png" IsActionButtonVisible="True"> <models:DetailsItemData.ValueBounds> <Rectangle X=".5" Y="172" Width="-1" Height="-1" /> </models:DetailsItemData.ValueBounds> <models:DetailsItemData.NameBounds> <Rectangle X=".5" Y="224" Width="-1" Height="-1" /> </models:DetailsItemData.NameBounds> </models:DetailsItemData> </x:Array> </cui:CircleListView.ItemsSource> Models/Workout/DetailsItemData.cs
using Xamarin.Forms; namespace Workout.Models.Workout { /// <summary> /// Details item data class. /// Used as one element of the details page list. /// </summary> public class DetailsItemData : BindableObject { #region properties public static readonly BindableProperty ValueProperty = BindableProperty.Create("Value", typeof(string), typeof(DetailsItemData), default(string)); /// <summary> /// Workout detail name. /// </summary> public string Name { get; set; } /// <summary> /// Workout detail value. /// </summary> public string Value { get => (string)GetValue(ValueProperty); set => SetValue(ValueProperty, value); } /// <summary> /// Workout detail icon. /// </summary> public string Icon { get; set; } /// <summary> /// Item layout value bounds. /// </summary> public Rectangle ValueBounds { get; set; } /// <summary> /// Item layout name bounds. /// </summary> public Rectangle NameBounds { get; set; } /// <summary> /// Workout detail action button visibility flag. /// </summary> public bool IsActionButtonVisible { get; set; } #endregion } } ItemTemplate
The values provided by ItemSource are used in ItemTemplate.
Views/Workout/DetailsPageView.xaml
<cui:CircleListView.ItemTemplate> <DataTemplate> <ViewCell> <AbsoluteLayout HeightRequest="360" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"> <Image AbsoluteLayout.LayoutFlags="XProportional" AbsoluteLayout.LayoutBounds=".5, 74, AutoSize, AutoSize"> <Image.Source> <FileImageSource File="{Binding Icon}" /> </Image.Source> </Image> <Label Text="{Binding Value}" FontSize="{StaticResource FontSizeM}" TextColor="#FFF" AbsoluteLayout.LayoutFlags="XProportional" AbsoluteLayout.LayoutBounds="{Binding ValueBounds}"> </Label> <Label Text="{Binding Name}" FontSize="{StaticResource FontSizeXXS}" FontAttributes="Bold" TextColor="#AAFFCC" AbsoluteLayout.LayoutFlags="XProportional" AbsoluteLayout.LayoutBounds="{Binding NameBounds}"> </Label> <Button AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0, 1, 1, .25" Text="OK" TextColor="#1B1B7D" BackgroundColor="#AAFFCC" Command="{Binding BindingContext.FinishCommand, Source={x:Reference listView}}" IsVisible="{Binding IsActionButtonVisible}" tizen:VisualElement.Style="bottom" /> </AbsoluteLayout> </ViewCell> </DataTemplate> </cui:CircleListView.ItemTemplate> The values modify the content in each ViewCell element accordingly, so that:
The Name and Value properties set the values of the Text property of the selected Label elements The NameBounds and ValueBounds properties set the LayoutBounds property of absolutely positioned Label elements The Icon property sets the Source property of the Image elements responsible for displaying the item icon The IsActionButtonVisible property sets the IsVisible property of Button elements, making them visible when the given value is True Read More
To learn more about the implementation of CircleListView in the Workout application, please see this tutorial.
Thank you for reading the tutorials about the Workout app. For more information about this app and developing for the Tizen platform, please visit developer.tizen.org.
View the full blog at its source
-
By Samsung Newsroom
This is the third blog in a series to introduce the sample application Workout, a Tizen example for monitoring health sensors on a wearable device.
The first blog, Workout -- A Tizen Sample App for Monitoring Health Sensors, presented the basic features of the application. The second blog, Adding Distance Traveled to the Tizen Workout Sample App, described how distance traveled is calculated.
In this blog, I will demonstrate another key feature of the app, Heart Rate Measurement (HRM), which shows the most recent heart rate intensity.
Implementation
To start collecting data from the HRM sensor, first start Tizen.Sensor.HeartRateMonitor from TizenFX API.
HeartRateMonitorService.cs
public void Init() { try { _hrm = new HRM { Interval = 1000, PausePolicy = SensorPausePolicy.None }; _hrm.DataUpdated += OnDataUpdated; } catch (Exception) { NotSupported?.Invoke(this, EventArgs.Empty); } } Initiating HRM in this way invokes DataUpdated every one second and the sensor is not stopped even when the application is sent to the background. The data from the event is handled by the OnDataUpdated handler, which invokes the event with the single bpm value.
This event is listened to by the OnServiceDataUpdated handler in the HeartRateMonitorModel, where all information related to heart rate is calculated:
HeartRateMonitorModel.cs
private void OnServiceDataUpdated(object sender, int bpm) { double normalizedBpm = Math.Clamp((bpm - _minBpm) / (double)(_maxBpm - _minBpm), 0, 1); int bpmRange = bpm < _minBpm ? 0 : Math.Min((int)((normalizedBpm * (_bpmRanges - 1)) + 1), _bpmRanges - 1); if (!_isMeasurementPaused) { _bpmRangeOccurrences[bpmRange]++; } Updated?.Invoke(this, new HeartRateMonitorUpdatedEventArgs(new HeartRateMonitorData { Bpm = bpm, BpmRange = bpmRange, BpmRangeOccurrences = _bpmRangeOccurrences, NormalizedBpm = normalizedBpm })); } However, let's start with the values that are used in the above method:
_maxBpm - this value is calculated during the class instantiation according to the formula: 220 - user age
_minBpm - this is half the value of _maxBpm
_minBpm and _maxBpm is used to calculate normalizedBpm, a value ranging from 0 to 1.
Next, the bpmRange to which the current HRM service value belongs is calculated: For bpm below _minBpm, bpmRange is set to 0. For bpm greater than or equal to _minBpm, bpmRange is set to either (_normalizedBpm * (_bpmRanges -1) + 1) or (_bpmRanges - 1), whichever value is smaller.
This calculated pulse interval is used as a position in an array, whose value is increased by 1. To obtain the most common pulse interval, find the index with the highest value associated with it.
DetailsPageViewModel.cs
Intensity = Array.LastIndexOf(bpmRangeOccurrences, bpmRangeOccurrences.Max()).ToString(); To display the range indication, Intensity is delivered to XAML and converted into text using a converter.
DetailsPageView.xaml.cs
<models:DetailsItemData Name="intensity" Value="{Binding Intensity, Converter={StaticResource BpmRangeValueConverter}}" Icon="images/details_intensity_icon.png" IsActionButtonVisible="True"> Read more
To learn more about the implementation of the HRM sensor and the use of the data in the Workout app, see this tutorial
In the final blog of this series, you'll learn how CircleListView is used in the app.
View the full blog at its source
-
By Samsung Newsroom
This is the second blog in a series to introduce the sample application Workout, a Tizen example for monitoring health sensors on a wearable device.
The previous blog, Workout -- A Tizen Sample App for Monitoring Health Sensors, introduced the sample application, Workout, for runners who own a wearable device. In this blog, I will describe how one of the key features, traveled distance, is calculated.
Implementation
To calculate the traveled distance, the application uses the LocationService class providing location-related GPS data. This service uses the Tizen.Location API to initialize the GPS receiver:
Services/LocationService.cs
/// <summary> /// Initializes LocationService class instance. /// </summary> private LocationService() { _locator = new Locator(LocationType.Hybrid) { Interval = _gpsCallbackInterval }; AttachEvents(); } The API is also used to set the change handlers:
Services/LocationService.cs
/// <summary> /// Sets service listeners. /// </summary> private void AttachEvents() { _locator.ServiceStateChanged += (sender, args) => ServiceStateChanged?.Invoke(this, args.ServiceState); _locator.LocationChanged += (sender, args) => LocationChanged?.Invoke(this, args.Location); _locator.SettingChanged += (sender, args) => SettingChanged?.Invoke(this, args.IsEnabled); } Every time the location changes, the LocationChanged event is invoked with the new location.
This event has an attached listener in LocationModel which receives the new location object. The new location is used to calculate the distance to the previous location and stored in a _locationData object:
Models/LocationModel.cs
_locationData.Distance += location.GetDistanceTo(_lastLocation) / SettingsService.Instance.Distance.UnitToKmRatio; The new location data is passed to MainModel, where all workout data are gathered and processed before being sent to viewModels.
The entire flow of location data and other workout data is described in detail at tizenschool.org
In the next blog in this series, I will discuss how data is gathered from the heart rate monitor.
View the full blog at its source
-
By SAMSUNG
Hit the ground running. Here’s how you can activate your usual workout at a single press of the button. Discover more: http://smsng.co/GalaxyFit #GalaxyFit #HowTo
-
-
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.