Development

Step 1: Preparing the area

Open Visual Studio IDE to create a new Tizen Wearable App.

  1. Go to File > New > Project to open the New Project window.

  2. In the New Project window do the following steps:

    a. Select Installed > Visual C# > Tizen platform.

    b. Select Tizen Wearable App project type.

    c. Specify the project Name.

    d. Set the project Location.

    e. Click the OK button to start creating a new project.

  3. Project structure should look like the following one (Solution Explorer window).

Step 2: Adding assets

  1. Download and unpack the assets for the application.

    The assets pack consists of two folders...

    ... which contain the following set of images:

    • background image file (res/background.png)

    • on-going measurement indicator image file (res/heart.png)

    • Custom application icon - existing file should be replaced (shared/res/PulsometerSDC.png). Note that the application icon file name will be different if you choose own name for the project.

  2. Select and copy the unpacked folders and paste them directly to the PulsometerSDC project.

  3. Confirm following pop-ups to replace the content of the res and shared folders of the project.

Step 3: Creating the view

  1. Go to Solution Explorer window, right-click on the project and select Add > New Item from the context menu.

  2. The "Add New Item" window will appear. Create MainPage.xaml file:

    a. Select Installed > Visual C# Items > Xamarin.Forms item type.

    b. Select Content Page file type.

    c. Specify file name – MainPage.xaml.

    d. Click the Add button to confirm.

  3. Open MainPage.xaml file. Add an XML namespace for Tizen.Circular.UI library and replace the ContentPage with a CirclePage from the cui namespace.

    <?xml version="1.0" encoding="utf-8" ?>
    <cui:CirclePage xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    xmlns:cui="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=Tizen.Wearable.CircularUI.Forms"
                    x:Class="PulsometerSDC.MainPage">
        <cui:CirclePage.Content>
            <StackLayout>
                <Label Text="Welcome to Xamarin.Forms!"
                    VerticalOptions="CenterAndExpand"
                    HorizontalOptions="CenterAndExpand" />
            </StackLayout>
        </cui:CirclePage.Content>
    </cui:CirclePage>
    
  4. Replace the content of the page with three elements positioned in absolute layout:

    • Image element for the application background (background.png)

    • Image element for the on-going measurement indicator (heart.png)

    • Label element displaying current heart rate value

    <?xml version="1.0" encoding="utf-8" ?>
    <cui:CirclePage xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    xmlns:cui="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=Tizen.Wearable.CircularUI.Forms"
                    x:Class="PulsometerSDC.MainPage">
        <cui:CirclePage.Content>
            <AbsoluteLayout>
                <Image AbsoluteLayout.LayoutFlags="All"
                       AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
                       Source="background.png" />
    
                <Image x:Name="measuringIndicator"
                       AbsoluteLayout.LayoutFlags="None"
                       AbsoluteLayout.LayoutBounds="155, 64, 50, 44"
                       Source="heart.png"
                       IsVisible="False" />
    
                <Label x:Name="hrValue"
                       TextColor="#454545"
                       FontSize="20"
                       AbsoluteLayout.LayoutFlags="None"
                       AbsoluteLayout.LayoutBounds="127, 169, 104, 48"
                       HorizontalTextAlignment="Center"
                       Text="0" />
            </AbsoluteLayout>
        </cui:CirclePage.Content>
    </cui:CirclePage>
    
  5. Add an ActionButton element to the page. It will be starting and stopping the heart rate measurement.

    <?xml version="1.0" encoding="utf-8" ?>
    <cui:CirclePage xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    xmlns:cui="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=Tizen.Wearable.CircularUI.Forms"
                    x:Class="PulsometerSDC.MainPage">
        <cui:CirclePage.Content>
            <AbsoluteLayout>
                <Image AbsoluteLayout.LayoutFlags="All"
                       AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
                       Source="background.png" />
    
                <Image x:Name="measuringIndicator"
                       AbsoluteLayout.LayoutFlags="None"
                       AbsoluteLayout.LayoutBounds="155, 64, 50, 44"
                       Source="heart.png"
                       IsVisible="False" />
    
                <Label x:Name="hrValue"
                       TextColor="#454545"
                       FontSize="20"
                       AbsoluteLayout.LayoutFlags="None"
                       AbsoluteLayout.LayoutBounds="127, 169, 104, 48"
                       HorizontalTextAlignment="Center"
                       Text="0" />
            </AbsoluteLayout>
        </cui:CirclePage.Content>
    
        <cui:CirclePage.ActionButton>
            <cui:ActionButtonItem Text="MEASURE"
                                  x:Name="actionButton"
                                  Clicked="OnActionButtonClicked" />
        </cui:CirclePage.ActionButton>
    </cui:CirclePage>
    
  6. Open the MainPage.xaml.cs file (code behind file of the MainPage.xaml file). Add a using statement for the Tizen.CircularUI library and replace base class of the page with the CirclePage.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;
    
    using Tizen.Wearable.CircularUI.Forms;
    
    namespace PulsometerSDC
    {
        [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class MainPage : CirclePage	
        {
            public MainPage()
            {
                InitializeComponent();
            }
        }
    }
    
  7. Add an empty click handler to the action button we created earlier.

    public partial class MainPage : CirclePage
    {
        public MainPage()
        {
            InitializeComponent();
        }
    
        private void OnActionButtonClicked(object sender, EventArgs e)
        {
        }
    }
    
  8. Open the App.cs file. Replace the MainPage property assignment with new instance of the class we created earlier.

    public class App : Application
    {
    	public App()
    	{
    		// The root page of your application
    		MainPage = new MainPage();
    	}
    
    	protected override void OnStart()
    	{
    		// Handle when your app starts
    	}
    
    	protected override void OnSleep()
    	{
    		// Handle when your app sleeps
    	}
    
    	protected override void OnResume()
    	{
    		// Handle when your app resumes
    	}
    }
    

To build and run this application on the device, follow the steps below:

  • Press Ctrl+Shift+B keys to build the project.

  • Press Ctrl+F5 keys to start installing the application.

The application should now look like the one below:

Step 4: Handling privileges

  1. Open tizen-manifest.xml file (configuration editor should appear):

    a. Select the Privileges tab.

    b. Click Add button and select the "http://tizen.org/privilege/healthinfo" privilege from the list. Click the OK button to confirm.

    c. The privilege should appear on the list.

  2. Open the MainPage.xaml.cs file. Add a using statement for the Tizen.Security namespace.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;
    
    using Tizen.Wearable.CircularUI.Forms;
    using Tizen.Security;
    
  3. Create the CheckPrivileges method and two callbacks - OnPrivilegesGranted and OnPrivilegesDenied. Call the method in the page constructor.

    The CheckPrivileges method checks the status of user's approval for the "http://tizen.org/privilege/healthinfo" privilege. It may get the status instantly (user already allowed or denied granting the privilege and his/her choice was remembered) or have to ask the user before proceeding. Finally it calls one of two callbacks - OnPrivilegesGranted and OnPrivilegesDenied .

    The OnPrivilegesGranted callback is empty for now and will be implemented later.

    The OnPrivilegesDenied callback closes the application because the measurement cannot be done.

    public partial class MainPage : CirclePage
    {
        public MainPage()
        {
            InitializeComponent();
            CheckPrivileges();
        }
    
        private void CheckPrivileges()
        {
            // check permission status (allow, deny, ask) to determine action which has to be taken
            string privilege = "http://tizen.org/privilege/healthinfo";
            CheckResult result = PrivacyPrivilegeManager.CheckPermission(privilege);
    
            if (result == CheckResult.Allow)
            {
                OnPrivilegesGranted();
            }
            else if (result == CheckResult.Deny)
            {
                OnPrivilegesDenied();
            }
            else // the user must be asked about granting the privilege
            {
                PrivacyPrivilegeManager.GetResponseContext(privilege).TryGetTarget(out var context);
    
                if (context != null)
                {
                    context.ResponseFetched += (sender, e) =>
                    {
                        if (e.cause == CallCause.Answer && e.result == RequestResult.AllowForever)
                        {
                            OnPrivilegesGranted();
                        }
                        else
                        {
                            OnPrivilegesDenied();
                        }
                    };
                }
    
                PrivacyPrivilegeManager.RequestPermission(privilege);
            }
        }
    
        private void OnPrivilegesGranted()
        {
        }
    
        private void OnPrivilegesDenied()
        {
            // close the application
            Tizen.Applications.Application.Current.Exit();
        }
    
        private void OnActionButtonClicked(object sender, EventArgs e)
        {
        }
    }
    

Step 5: Performing the measurement

  1. Open the MainPage.xaml.cs file. Add a using statement for the Tizen.Sensor namespace.

    using Tizen.Wearable.CircularUI.Forms;
    using Tizen.Security;
    using Tizen.Sensor;
    
  2. Add two private fields. The first one stores an instance of the HeartRateMonitor class, while the second one is a flag indicating if there is on-going measurement.

    public partial class MainPage : CirclePage
    {
        private HeartRateMonitor _monitor;
        private bool _measuring = false;
    
        public MainPage()
        {
            InitializeComponent();
            CheckPrivileges();
        }
    
        // (...)
    
    }
    
  3. Create and configure an instance of the monitor (in OnPrivilegesGranted method).

    private void OnPrivilegesGranted()
    {
        // create an instance of the monitor
        _monitor = new HeartRateMonitor();
        // specify frequency of the sensor data event by setting the interval value (in milliseconds)
        _monitor.Interval = 1000;
    }
    
  4. Add OnMonitorDataUpdated callback method. It will handle DataUpdated event of the monitor by updating the label displaying current heart rate value. We will use it in the next step.

    private void OnPrivilegesDenied()
    {
        // close the application
        Tizen.Applications.Application.Current.Exit();
    }
    
    private void OnMonitorDataUpdated(object sender, HeartRateMonitorDataUpdatedEventArgs e)
    {
        // update displayed value
        hrValue.Text = e.HeartRate > 0 ? e.HeartRate.ToString() : "0";
    }
    
  5. Add methods responsible for starting and stopping the measurement.

    If the measurement needs to be started:

    • listener method (OnMonitorDataUpdated) is registered to the DataUpdated event of the monitor

    • Start method of the monitor (HeartRateMonitor) is called

    • action button text is changed to STOP

    • measuring indicator element (heart image) is shown

    If the measurement needs to be stopped:

    • listener method (OnMonitorDataUpdated) is unregistered from the DataUpdated event of the monitor

    • Stop method of the monitor (HeartRateMonitor) is called

    • action button text is changed to MEASURE

    • measuring indicator element (heart image) is hidden

    private void OnMonitorDataUpdated(object sender, HeartRateMonitorDataUpdatedEventArgs e)
    {
        // update displayed value
        hrValue.Text = e.HeartRate > 0 ? e.HeartRate.ToString() : "0";
    }
    
    private void StartMeasurement()
    {
        _monitor.DataUpdated += OnMonitorDataUpdated;
        _monitor.Start();
        _measuring = true;
    
        // update the view
        actionButton.Text = "STOP";
        measuringIndicator.IsVisible = true;
    }
    
    private void StopMeasurement()
    {
        _monitor.DataUpdated -= OnMonitorDataUpdated;
        _monitor.Stop();
        _measuring = false;
    
        // update the view
        actionButton.Text = "MEASURE";
        measuringIndicator.IsVisible = false;
    }
    
  6. Implement the action button click handler. It starts or stops the measurement depending on the current state (_measuring flag).

    private void OnActionButtonClicked(object sender, EventArgs e)
    {
        if (_measuring)
        {
            StopMeasurement();
        }
        else
        {
            StartMeasurement();
        }
    }
    

Step 6: Customizing the life cycle

The last thing, we want to do, is stopping the measurement when the application goes into the background (home button is pressed).

  1. Open the App.cs file. We will use MessagingCenter class to notify other modules that the application enters the sleeping state.

    protected override void OnSleep()
    {
        // Handle when your app sleeps
        MessagingCenter.Send(this, "sleep");
    }
    
  2. Go to the MainPage.xaml.cs file. Extend the OnPrivilegesGranted method by subscribing to message sent in the App.cs file. The handler will stop the measurement if it is necessary.

    private void OnPrivilegesGranted()
    {
        // create an instance of the monitor
        _monitor = new HeartRateMonitor();
        // specify frequency of the sensor data event by setting the interval value (in milliseconds)
        _monitor.Interval = 1000;
    
        // stop the measurement when the application goes background
        MessagingCenter.Subscribe(this, "sleep", (sender) => {
            if (_measuring)
            {
                StopMeasurement();
            }
        });
    }
    

Step 7: Testing the application

  1. Connect the target device and select Build > Build Solution or F6 as a shortcut to build it and then select Debug > Start Without Debugging from the Visual Studio menu or use Ctrl + F5 shortcut to run on the target device.

    The application should launch.

  2. Put the watch on your hand and press the MEASURE button. Wait for a while until the measurement is done. It takes about 10 seconds for the first results to show up.


You're done!

Congratulations! You have successfully achieved the goal of this Code Lab activity. Now, you can create a pulsometer app using Tize C# by yourself! But, if you're having trouble, you may check out the link below.

Pulsometer App Complete Code1.50 MB