Creating a native service for Tizen wearables - part 2: service launcher

Introduction

This article is the second part of the “Create a native service for Tizen wearables” series. Before reading this article you should read the first part, in which we have described how to create a simple service running in the background on a wearable device and uploaded using the Tizen SDK.

As standalone services without UI are not allowed in the Tizen Store, in this part we will show how to create a service launcher application and distribute it as the Combined Package with your already created service. This will allow you to create a service with accompanying UI application bundled in one package.

Prerequisites

Before reading this article please read “Creating a native service for Tizen wearables - part 1”.

https://developer.tizen.org/community/tip-tech/creating-native-service-tizen-wearables-part-1

As in this article we introduce App Control API and basics of EFL, you should be familiarized with its basics. The following code snippets and tutorials should be helpful:

App Control:

https://developer.tizen.org/community/code-snippet/native-code-snippet/launch-another-application

Elementary List widget:

https://developer.tizen.org/development/ui-practices/native-application/efl/ui-components/wearable-ui-components/list

Creating a combined package:

https://developer.tizen.org/development/getting-started/native-application/application-development-process#develop

 

Preparation steps and code arrangement

If you had been testing the example source code from “Creating a native service for Tizen wearables – part 1” article, you probably still have the MyService application installed on the device. Before you try running the accompanied code please uninstall the previous version of the MyService application from the device (using the command sdb uninstall org.example.myservice from the Tizen SDK command bar or, in case of Tizen Studio, from the Linux console). Otherwise a name conflict will occur.

Uninstalling the previous MyService application using the Command Bar

Figure 1 - uninstalling the previous MyService application

 

The attached code is the complete source code of the created service and the accompanying app. You can import them to your SDK and after creating the Combined Package they should be ready to use when you have a properly set wearable device. You can also follow the steps described in the article and create the Service application with a UI application on your own.

The source code of the service is based on the service from the previous article and the source code of the UI application is based on the SDK template. Only the parts of the code that have been added to the previous service and to the UI app template are discussed in this article.

 

Steps to do

Step 1. MyServiceLauncher: Create a launcher application

  1. First steps
  2. Simple UI
  3. Service launch request
  4. Service stop request
  5. Summary

Step 2. MyService: Modify the service to respond to app control requests and communicate with the launcher

  1. Handling the service stop request
  2. Launching the launcher application when a sensor event occurred

Step 3. Create a combined package from the launcher application and the service application

 

Step 1: Create a launcher application

  1. First steps

In the Tizen SDK we choose File -> New -> Tizen Native Project and we find a Basic UI template in the group WEARABLE-2.3.1

Creating a UI application from a "Basic UI" template

Figure 2 – Creating a UI application from a template

 

What we want the Launcher to do is to launch a service application. To allow our project to launch another application we need to give it a special privilege. To launch another application we will use the App Control API from the Application Manager and we need the appmanager.launch privilege.

Browsing through available privileges using Tizen Manifest Editor

Figure 3 – Browsing through available privileges using Tizen Manifest Editor

Setting privilege for MyServiceLauncher app using Tizen Manifest Editor

Figure 4 – Setting privilege for MyServiceLauncher app using Tizen Manifest Editor

 

After setting the privilege, we must remember to save the manifest file.

 

  1. Simple UI

The next step is to create the UI for our launcher application.

An autogenerated template code for a UI application consists of a window with conformant and a simple label inside. As we want to create a simple clickable menu, the easiest way to do it will be to put a list in the place of the label. To do it, in the appdata_s structure we declare a list handle instead of the label handle.

//in myservicelauncher.c file: 

typedef struct appdata {
    //…
	//instead of label we will create a list:
	Evas_Object *list;
} appdata_s;

Then, we modify the create_base_gui() function replacing the code for a label with a code showing list. Using the elm_list_item_append() we append elements to the list and set click event callbacks for them.

 //in create_base_gui():

ad->list = elm_list_add(ad->conform);
elm_list_item_append (ad->list, "Start service", NULL, NULL, launch_service_cb, NULL);
elm_list_item_append (ad->list, "Stop service", NULL, NULL, stop_service_cb, NULL);
elm_list_item_append (ad->list, "Close", NULL, NULL, close_app_cb, NULL);
elm_object_content_set(ad->conform, ad->list);
evas_object_show(ad->list);

Callbacks for click events are just simple wrappers.

In the close_app_cb we just do nothing and close the application:

static void close_app_cb(void *data, Evas_Object *obj, void *event_info)
 {
     ui_app_exit(); 
 }

In the launch_service_cb and stop_service_cb we launch functions that will be described later:

static void launch_service_cb(void *data, Evas_Object *obj, void *event_info)
 {
     launch_service();
 }
 
 static void stop_service_cb(void *data, Evas_Object *obj, void *event_info)
 {
     stop_service();
 }
  1. Service launch request

In the case of our application launching the service will mean executing a separate application which works in the background. To do this we will use the App Control C API. This API is provided by the <app_control.h> header, but we do not need to include it explicitly, because the template UI app already includes an <app.h> header which contains also this API. To launch another app we perform a standard App Control launch request to org.example.myservice, which is an app ID of our service.

static void launch_service()
{
    app_control_h app_control = NULL;
    if (app_control_create(&app_control)== APP_CONTROL_ERROR_NONE)
    {
        if ((app_control_set_app_id(app_control, "org.example.myservice") == APP_CONTROL_ERROR_NONE)
            && (app_control_send_launch_request(app_control, NULL, NULL) == APP_CONTROL_ERROR_NONE))
        {
            dlog_print(DLOG_INFO, LOG_TAG, "App launch request sent!");
        }
        else
        {
            dlog_print(DLOG_ERROR, LOG_TAG, "App launch request sending failed!");
        }
        if (app_control_destroy(app_control) == APP_CONTROL_ERROR_NONE)
        {
            dlog_print(DLOG_INFO, LOG_TAG, "App control destroyed.");
        }
        // We exit our launcher app, there is no point in keeping it open.
        ui_app_exit();
    }
    else
    {
        dlog_print(DLOG_ERROR, LOG_TAG, "App control creation failed!");
    }
}
  1. Service stop request

We will commence a stopping request also by sending the App Control launch request, but this time with a special custom parameter which will be added by the app_control_add_extra_data() API function. We will check this extra data when receiving the launch request by our service application.

static void stop_service()
{
    app_control_h app_control = NULL;
    if (app_control_create(&app_control)== APP_CONTROL_ERROR_NONE)
    {
        if ((app_control_set_app_id(app_control, "org.example.myservice") == APP_CONTROL_ERROR_NONE)
            && (app_control_add_extra_data(app_control, "service_action", "stop") == APP_CONTROL_ERROR_NONE)
            && (app_control_send_launch_request(app_control, NULL, NULL) == APP_CONTROL_ERROR_NONE))
        {
            dlog_print(DLOG_INFO, LOG_TAG, "App launch request sent!");
        }
        else
        {
            dlog_print(DLOG_ERROR, LOG_TAG, "App launch request sending failed!");
        }
        if (app_control_destroy(app_control) == APP_CONTROL_ERROR_NONE)
        {
            dlog_print(DLOG_INFO, LOG_TAG, "App control destroyed.");
        }
        ui_app_exit();
    }
    else
    {
        dlog_print(DLOG_ERROR, LOG_TAG, "App control creation failed!");
    }
}
  1. Summary

All the steps described above were part of the MyServiceLauncher application. Now we must modify the MyService application to respond to MyServiceLauncher requests.

Step 2: Modify the service to respond to app control requests and communicate with the launcher

In this – second – part of the series we take and modify the code of the MyService application from the part 1 (https://developer.tizen.org/community/tip-tech/creating-native-service-tizen-wearables-part-1). So everything explained in this section of the article is an addition or modification of the previous version of the service.

As we are going to need two-way App Control communication between the MyServiceLauncher and the MyService (a reason for this will be explained later), we must add the appmanager.launch privilege also to MyService. Additionally we need give the service display privilege to wake up the display when sensor event occurs. We can do this the same way we did this for the MyServiceLauncher (see Paragraph 1 a.), or we can modify the tizen-manifest.xml file body by adding the following lines inside the <manifest> opening and closing tags:

<privileges>
        <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
        <privilege>http://tizen.org/privilege/display<privilege>
</privileges>

Also, to make possible using device power wakeup we must include a following Tizen API header:

#include <device/power.h>

 

  1. Handling the service stop request

To stop the service on the MyServiceLauncher request, we must implement the service_app_control() event handler, which was an empty function in the previous version of the MyService. Here is where the app handles the App Control requests. To make sure that we handle only valid requests sent from the MyServiceLauncher application, we check if the caller app ID is correct and that we received the extra key-value pair (“service_action”,“stop”). In case the conditions above are met, we just exit the service application.

#define MYSERVICELAUNCHER_APP_ID "org.example.myservicelauncher" // an ID of the UI application of our package
#define STRNCMP_LIMIT 256 // the limit of characters to be compared using strncmp function

//...

void service_app_control(app_control_h app_control, void *data)
{
    char *caller_id = NULL, *action_value = NULL;
    if ((app_control_get_caller(app_control, &caller_id) == APP_CONTROL_ERROR_NONE)
        && (app_control_get_extra_data(app_control, "service_action", &action_value) == APP_CONTROL_ERROR_NONE))
    {
        if((caller_id != NULL) && (action_value != NULL)
            && (!strncmp(caller_id, MYSERVICELAUNCHER_APP_ID, STRNCMP_LIMIT))
            && (!strncmp(action_value,"stop", STRNCMP_LIMIT)))
        {
            dlog_print(DLOG_INFO, LOG_TAG, "Stopping MyService!");
            free(caller_id);
            free(action_value);
            service_app_exit();
            return;
        }
        else
        {
            dlog_print(DLOG_INFO, LOG_TAG, "Unsupported action! Doing nothing...");
            free(caller_id);
            free(action_value);
            caller_id = NULL;
            action_value = NULL;
        }
    }
}
  1. Launching the launcher application when a sensor event occurred

The second modification we want to make to our service application is to extend its behavior when a sensor event occurs. Until now the MyService played only a sound, now it will also launch the MyServiceLauncher UI app to allow the user to make modifications to the service settings each time a sensor event occurs. Also we should add device power wakeup to light up the screen and wake the device in case the screen was turned off.

//sensor event callback implementation
void sensor_event_callback(sensor_h sensor, sensor_event_s *event, void *user_data)
{
    // Extracting application data
    appdata_s* ad = (appdata_s*)user_data;
    sensor_type_e type = SENSOR_ALL;
    
    if((sensor_get_type(sensor, &type) == SENSOR_ERROR_NONE) && type == SENSOR_ACCELEROMETER)
    {
        if (event->values[0] >= ACCELEROMETER_SHAKE_THRESHOLD_VALUE
            || event->values[1] >= ACCELEROMETER_SHAKE_THRESHOLD_VALUE
            || event->values[2] >= ACCELEROMETER_SHAKE_THRESHOLD_VALUE
            || event->values[0] <= -ACCELEROMETER_SHAKE_THRESHOLD_VALUE
            || event->values[1] <= -ACCELEROMETER_SHAKE_THRESHOLD_VALUE
            || event->values[2] <= -ACCELEROMETER_SHAKE_THRESHOLD_VALUE)
        {
            // Event criteria were met, now we must wake up the device
            // in case the screen was off when the event occurred.
            if (device_power_wakeup(false)==DEVICE_ERROR_NONE)
            {
                dlog_print(DLOG_INFO, LOG_TAG, "Waking up the device!");
            }
            else
            {
                dlog_print(DLOG_ERROR, LOG_TAG, "Couldn't wake up!");
            }
            dlog_print(DLOG_INFO, LOG_TAG, "Event occurred!");
            
//...
// Here comes playing sound which we omit in this code fragment 
// as it stays unchanged since the last version…
//... 			

// Now the new code part starts. 
// We launch the MyServiceLauncher app...

            app_control_h app_control = NULL;
            if (app_control_create(&app_control) == APP_CONTROL_ERROR_NONE)
            {
                //Setting an app ID.
                if (app_control_set_app_id(app_control, MYSERVICELAUNCHER_APP_ID) == APP_CONTROL_ERROR_NONE)
                {
                    if(app_control_send_launch_request(app_control, NULL, NULL) == APP_CONTROL_ERROR_NONE)
                    {
                        dlog_print(DLOG_INFO, LOG_TAG, "App launch request sent!");
                    }
                }
                if (app_control_destroy(app_control) == APP_CONTROL_ERROR_NONE)
                {
                    dlog_print(DLOG_INFO, LOG_TAG, "App control destroyed.");
                }
            }
        }
    }
}

Step 3: Create a combined package from the launcher application and service application

The last thing left to improve in our service application is to combine it with the launcher application into one package, which will allow it to be distributed on the Tizen Store.

To do this we must state MyService as a project reference in the UI application (in our case the MyServiceLauncher) project properties. We right-click on the UI application project name and choose “Properties”, then find Tizen SDK àPackage àMulti. We will see the list of all available projects in the SDK to be referred to. We choose MyService. From now on we can build, package and install the two projects together.

Combining MyServiceLauncher and MyService into one package

Figure 5 – Combining MyServiceLauncher and MyService into one package

The result of this action should be visible in the Project Explorer – now MyService is labeled as combined with MyServiceLauncher.

Combined project in a Project Explorer view.

Figure 6 – Combined project in a Project Explorer view. MyService is now displayed as a sub-project combined with MyServiceLauncher application.

Summary

Now you should be able to create a very simple launcher application that controls launching and stopping the sensor-reading service working in the background. We have also showed you how to  modify the service to react to the requests sent by the launcher app. The combined package of an application and a corresponding service is allowed in the Tizen Store. This article was the second one of the “Create a native service for Tizen wearables” series. In the next part we will show you how to improve the launcher app with a nice-looking Circle UI for wearable devices with a round screen.

첨부 파일: 
List
SDK Version Since: 
2.4.0