C# Apps on Galaxy Watch Pulsometer

Overview

The Galaxy Watch is a perfect example of having an intuitive user interface while utilizing the circular bezel, making it feel natural for the wearer. Tizen enhances that experience even further with its optimized power management and ecosystem.

With this tutorial, you can learn how simple it is to expand on Galaxy Watch's existing features to track your health and workouts in even greater detail. We will teach you how to create a simple pulsometer application.

Figure 1 Galaxy Watch Pulsometer

Figure 1 Galaxy Watch Pulsometer

Objective

Learn how to create your own Pulsometer using Tizen C# on a Galaxy Watch.

Setup

To build the Tizen application for the wearable, the environment should be downloaded and installed:

To test the application, the following devices are required:

  • Samsung Galaxy Watch

  • Emulator (optional)

Application Development

1. Preparing the area

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

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

    Figure 2 New Project Window

    Figure 2 New Project Window

  • In the New Project window do the following steps:

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

    2. 2. Select Tizen Wearable App project type.

    3. 3. Specify the project Name.

    4. 4. Set the project Location.

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

      Figure 3 Starting a new project

      Figure 3 Starting a new project

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

    Figure 4 Project Structure

    Figure 4 Project Structure

2. Adding the assets

Step 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.

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

Figure 5 Copying unpacked folders to the project

Figure 5 Copying unpacked folders to the project

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

Figure 6 Merging res folder prompt message

Figure 6 Merging res folder prompt message

Figure 7 Merging shared folder prompt message

Figure 7 Merging shared folder prompt message

3. Creating the view

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

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

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

  2. 2. Select Content Page file type.

  3. 3. Specify file name – MainPage.xaml.

  4. 4. Click the Add button to confirm.

Figure 8 Creating MainPage.xaml file

Figure 8 Creating MainPage.xaml file

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>

Step 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>

Step 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>

Step 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();
        }
    }
}

Step 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)
    {
    }
}

Step 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:

Figure 9 Sample Pulsometer

Figure 9 Sample Pulsometer

4. Handling privileges

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

  1. 1. Select the Privileges tab.

  2. 2. Click Add button and select the "http://tizen.org/privilege/healthinfo" privilege from the list.

    Click the OK button to confirm.

  3. 3. The privilege should appear on the list.

Note

do not forget to save the file (File > Save Selected Items).

Figure 10 Adding privileges

Figure 10 Adding privileges

Step 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;

Step 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)
    {
    }
}

5. Performing the measurement

Step 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;

Step 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();
    }

    // (...)

}

Step 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;
}

Step 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";
}

Step 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;
}

Step 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();
    }
}

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).

Step 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"); }
      

Step 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(); } }); }
      

7. Testing the application

Step 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.

Figure 11 Initiating application test

Figure 11 Initiating application test

The application should launch.

Figure 12 Application main display

Figure 12 Application main display

Step 2: Put the watch on your hand and press the MEASURE button. Wait a while until the measurement is done.

Note

Put the watch on your hand and press the MEASURE button. Wait a while until the measurement is done.

Figure 13 Measuring the heart rate using the application

Figure 13 Measuring the heart rate using the application

Congratulations! You have finished this tutorial completely. Thank you!