Mobile native Wearable native

Application

A Tizen native application is similar to a conventional Linux application, with some additional features optimized for mobile devices. The additional features have constraints, such as a relatively small screen size and lack of system resources compared to a larger system. For example, for power management reasons, the application can take actions to reduce usage when it finds out that it has its display window covered over by another application window. State change events are delivered to make it possible to detect these situations.

The Application API provides interfaces for the following categories:

Managing the Event Loop

In order for an application to operate successfully, it must receive events from the platform. For this, it must start the main event loop - this is mandatory for all Tizen native applications.

The ui_app_main() function is used to start the event loop. Before calling this function, set up the app_event_callback_s structure variable, which is passed to the function.

For more information about launching applications, see Launching Applications.

Registering Callbacks for Events

The following table lists the application state change events.

Table: Application state change events
Callback Description
app_create_cb() Used to take necessary actions before the main event loop starts. Place the UI generation code here to prevent missing any events from your application UI.
app_pause_cb() Used to take necessary actions when the application becomes invisible. For example, release memory resources so other applications can use them. Do not starve the foreground application that is interacting with the user.
app_resume_cb() Used to take necessary actions when the application becomes visible. If you relinquish anything in the app_pause_cb() callback, re-allocate those resources here before the application resumes.
app_terminate_cb() Used to take necessary actions when the application is terminating. Release all resources, especially any allocations and shared resources, so that other running applications can fully use any shared resources.

For more information, see Managing Application States and Transitions.

To listen to system events, use the ui_app_add_event_handler() function. The system events are triggered with the app_event_cb() callback function. The following table lists the event types.

Table: Event types
Event type Description
APP_EVENT_LOW_MEMORY Event type for the callback function that is responsible for saving data in the main memory to a persistent memory or storage to avoid data loss in case the Tizen platform Low Memory Killer kills your application to get more free memory. The callback function must also release any cached data in the main memory to secure more free memory.
APP_EVENT_LOW_BATTERY Event type for the callback function that is responsible for saving data in the main memory to a persistent memory or storage to avoid data loss in case the power goes off completely. The callback function must also stop heavy CPU consumption or power consumption activities to save the remaining power.
APP_EVENT_DEVICE_ORIENTATION_CHANGED Event type for the callback function that is responsible for changing the display orientation to match the device orientation.
APP_EVENT_LANGUAGE_CHANGED Event type for the callback function that is responsible for refreshing the display into the new language.
APP_EVENT_REGION_FORMAT_CHANGED Event type for the callback function that is responsible for refreshing the display into the new time zone.

Launching Applications

An application can be launched by the user from the Launcher or by another application.

The App Control can be used to describe either an action to be performed by other applications, or the results of the operation performed by a launched application. The application can receive results from the launched application.

Regardless of how an application is launched, the application framework starts the application by creating a new process and calling the entry point of the application. Like a conventional Linux application, the main function of the application is its entry point. In the Tizen application, the main task is to hand over control to the application framework by calling the ui_app_main() function:

bool app_create(void *user_data)
{
   // Take necessary actions before the main event loop starts
   // Initialize UI resources and application data
   // If this function returns true, the application main loop starts
   // If this function returns false, the application terminates
   return true;
}

void app_control(app_control_h app_control, void *user_data)
{
   // Handle the launch request
}

void app_pause(void *user_data)
{
   // Take necessary actions when application becomes invisible
}

void app_resume(void *user_data)
{
   // Take necessary actions when application becomes visible
}

void app_terminate(void *user_data)
{
   // Release all resources
}

int main(int argc, char *argv[])
{
   struct appdata ad;
 
   ui_app_lifecycle_callback_s event_callback;
     
   event_callback.create = app_create;
   event_callback.terminate = app_terminate;
   event_callback.pause = app_pause;
   event_callback.resume = app_resume;
   event_callback.app_control = app_control;

   memset(&ad, 0x0, sizeof(struct appdata));

   return ui_app_main(argc, argv, &event_callback, &ad);
}

The ui_app_main() function initializes the application and starts the main loop. It takes 4 parameters and uses them to initialize the application. The argc and argv parameters contain the values from the application framework, and you must never change their values. The third parameter is a state transition handler that is responsible for managing the state transitions the application goes through while it is running. The fourth parameter is application data to be passed to each state handler.

When the ui_app_main() is first invoked, the application moves from the ready state to the created state. The application has to initialize itself. During this transition, the application framework calls the application's app_create_cb() state transition callback just before the application enters the main loop. Within the registered callback, you must initialize the application resources and create the main window.

If the app_create_cb() callback function returns false, the application moves to the terminated state. If it returns true, the application enters the main loop.

Handling the Launch Options

The application framework calls the application's app_control_cb() callback just after the application enters the main loop. This callback is passed to the app_control containing the reason why the application was launched. For example, the application can be launched to open a file to handle the request that has been sent by other application. In all of these cases, the application is responsible for checking the content of the app_control and responding appropriately. The content of the app_control can be empty, if the application is launched by the user from the Launcher.

static void app_control(app_control_h app_control, void *user_data)
{
   struct appdata *ad = (struct appdata *)user_data;
   char *operation;
   char *uri;
   char *mime_type;
 
   app_control_get_operation(app_control, operation);
 
   if (!strcmp(operation, APP_CONTROL_OPERATION_VIEW))
   {
      app_control_get_uri(app_control, &uri);
      app_control_get_mime(app_control, &mime_type);
 
      if (uri && !strcmp(mime_type, "image/jpg"))
      {
         display_image_file(ad, uri); // Display a specific image file
      }
   }
 
   if (ad->win)
      elm_win_activate(ad->win);
}

Application Controls

The App control API provides functions for launching other applications with a specific operation, URI, and MIME type. The requesting application can get a result back from the launched application.

To launch an application with the App control API, create an app_control handle and add information to that handle. You can set the following information:

  • Operation: Action to be performed by the app control.
  • URI: Data itself to be performed.
  • MIME type: Specific type of the URI.
  • Application ID: ID of the application to be launched.
  • Extra data: Key-value pairs to provide additional information for the launch request and the result of the request.

The operation is mandatory information for sending the launch request. The app control API provides several functions to get and set the above information to the app_control handle.

To launch an application with the app control API, use one of the following methods:

The application launched by the app control can return the result to the caller application.

You can take advantage of the Tizen base application functionalities through the app control feature. You can also export your application functionality to allow other applications to launch your application.

Explicit Launch

When you request an explicit launch:

  • If the underlying application launcher framework finds an application matched with the given application ID in the installed application list, it launches the application in a new process. If the matched application is not found, the framework returns the APP_CONTROL_ERROR_APP_NOT_FOUND result. Additional information (such as operation, URI, or MIME type) is not be used to select an application for an explicit launch.
  • If the operation setting in the app_control handle is set to APP_CONTROL_OPERATION_DEFAULT, the application ID must be set. Otherwise the APP_CONTROL_ERROR_INVALID_PARAMETER result is returned.

The following code example launches a calculator application explicitly with the application ID:

#include <app.h>
#include <dlog.h>
 
#define TAG "MY_TAG"

app_control_h app_control;
 
app_control_create(&app_control);
app_control_set_operation(app_control, APP_CONTROL_OPERATION_DEFAULT);
app_control_set_app_id(app_control, "org.tizen.calculator");
 
if (app_control_send_launch_request(app_control, NULL, NULL) == APP_CONTROL_ERROR_NONE) 
{
   dlog_print(DLOG_INFO, TAG, "Succeeded to launch a calculator app.");
} 
else 
{
   dlog_print(DLOG_ERROR, TAG, "Failed to launch a calculator app.");
}
 
app_control_destroy(app_control);

Implicit Launch

When you request an implicit launch:

  • Only 3 data categories are used to determine which application can be launched: Operation, URI scheme, and MIME type.
  • The application launcher framework iterates the desktop files of installed applications on the device to find applications where the 3 categories are exactly matched.
  • If only one application is matched for the given categories, that application is launched. If multiple matching applications are found, the application selector is shown and the user can select the proper application.
  • Each app control requires a different combination of the 3 categories. For some, only one category is necessary (for example, URI), for others, all 3 can be needed. Check the app control list and required data in the API Reference to determine the needed categories.

To allow the application launcher framework to find and select matching applications, each application must describe its operation, URI, or MIME type correctly.

The following code example launches a camera application with the operation and MIME type:

#include <app.h>
#include <dlog.h>

#define TAG "MY_TAG"

app_control_h app_control;
 
app_control_create(&app_control);
app_control_set_operation(app_control, APP_CONTROL_OPERATION_CREATE_CONTENT);
app_control_set_mime(app_control, "image/jpg");
if (app_control_send_launch_request(app_control, NULL, NULL) == APP_CONTROL_ERROR_NONE) 
{
   dlog_print(DLOG_INFO, TAG, "Succeeded to launch a viewer app.");
} 
else 
{
   dlog_print(DLOG_ERROR, TAG, "Failed to launch a viewer app.");
}
 
app_control_destroy(app_control);

The following code example launches a gallery application with the operation, URI, and MIME type:

#include <app.h>
#include <dlog.h>

#define TAG "MY_TAG"
 
app_control_h app_control;
 
app_control_create(&app_control);
app_control_set_operation(app_control, APP_CONTROL_OPERATION_VIEW);
app_control_set_uri(app_control, "file:///home/myhome/Photos/1_photo.jpg");
app_control_set_mime(app_control, "image/*");
 
if (app_control_send_launch_request(app_control, NULL, NULL) == APP_CONTROL_ERROR_NONE) 
{
   dlog_print(DLOG_INFO, TAG, "Succeeded to launch a viewer app.");
} 
else 
{
   dlog_print(DLOG_ERROR, TAG, "Failed to launch a viewer app.");
}
 
app_control_destroy(app_control);

Getting the App Control Results

The app control result from the requested application is delivered to the caller application in the app_control handle with extra data. For some cases, the App control API provides pre-defined extra data keys.

If you cannot find a proper key, you can define your own key. However, the customized key must be shared between the caller and callee applications.

The following code example gets the result of an app control request by implementing an app_control result callback:

#include <app.h>
#include <dlog.h>
 
#define TAG "MY_TAG"
 
// Callback function to get result
static void app_control_result(app_control_h request, app_control_h reply, app_control_result_e result, void *user_data) 
{
   char *value;
 
   if (result == APP_CONTROL_RESULT_SUCCEEDED) 
   {
      if (app_control_get_extra_data(reply, APP_CONTROL_DATA_SELECTED, &value) == APP_CONTROL_ERROR_NONE)
      {
         dlog_print(DLOG_INFO, TAG, "[app_control_result_cb] Succeeded: value(%s)", value);
      } 
      else 
      {
         dlog_print(DLOG_ERROR, TAG, "[app_control_result_cb] Failed");
      }
 
   } 
   else 
   {
      dlog_print(DLOG_ERROR, TAG, "[app_control_result_cb] APP_CONTROL_RESULT_FAILED.");
   }
}

The following code example requests the launch of another application:

#include <app.h>
#include <dlog.h>

#define TAG "MY_TAG"

app_control_h app_control;
 
app_control_create(&app_control);
 
app_control_set_operation(app_control, APP_CONTROL_OPERATION_CREATE_CONTENT);
app_control_set_mime(app_control, "text/plain");
 
if (app_control_send_launch_request(app_control, app_control_result, NULL) == APP_CONTROL_ERROR_NONE) 
{
   dlog_print(DLOG_INFO, TAG, "Succeeded: the application is launched.");
} 
else 
{
   dlog_print(DLOG_ERROR, TAG, "Failed to launch an application.");
}
 
app_control_destroy(app_control);

The following code example implements an app_control callback in the callee application:

static void app_control(app_control_h app_control, void *user_data) 
{
   struct appdata *ad = (struct appdata *)user_data;
   char *operation;
   char *mime;
   app_control_h reply;
   char *app_id;
 
   app_control_get_operation(app_control, &operation);
 
   if (!strcmp(operation, APP_CONTROL_OPERATION_CREATE_CONTENT)) 
   {
      app_control_get_mime(app_control, &mime);
 
      if (!strcmp(mime, "text/plain")) 
      {
         app_control_create(&reply);
 
         app_get_app_id(&app_id);
         app_control_add_extra_data(reply, APP_CONTROL_DATA_SELECTED, app_id);
         app_control_reply_to_launch_request(reply, app_control, APP_CONTROL_RESULT_SUCCEEDED);
 
         app_control_destroy(reply);
      }
   }
}

Exporting AppControl Functionality

You can export functionalities of your application to be used in another application. However, if the other application uses the application control functionality implicitly without the application ID, it must declare the application control information in its manifest file:

<app-control>
   <mime name="application/xhtml+xml"/>
   <operation name="http://tizen.org/appcontrol/operation/view"/>
   <uri name="http://test.com"/>
</app-control>
<app-control>
   <operation name="http://tizen.org/appcontrol/operation/call"/>
</app-control>

The resolution filter is used when resolving the application control. Each entry of the resolution filter has the <app-control> element and forms an application resolution unit. The additional URI or MIME type information must contain the associated operation ID, and the retrieved application control must have the specified application ID and operation ID when resolving the application control.

You can specify the application control information of your application in the application project settings in the IDE; an operation ID must be specified for the application control.

Using Platform Application Controls

Tizen provides base applications, such as Web browser, image viewer, music player, and video player. Using the App Control module (in mobile and wearable applications), you can take advantage of the Tizen base application functionalities.

The Tizen platform provides the platform application controls for the following base applications:

  • FileManager
  • ImageViewer
  • Internet
  • MusicPlayer
  • VideoPlayer

The following table defines the details of each platform application control.

Table: Tizen base application services
Service Operation Scheme MIME
Browsing a Web page http://tizen.org/appcontrol/operation/view
  • http
  • https
-
Displaying an image
  • file
  • http
  • https
  • image/bmp
  • image/gif
  • image/jpeg
  • image/png
Playing a sound file file
  • audio/aac
  • audio/amr
  • audio/mp3
  • audio/wav
Playing a video file
  • video/mp4
  • video/3gpp
Selecting a file http://tizen.org/appcontrol/operation/pick
  • */*
  • image/*
  • video/*
  • audio/*
Note
Tizen provides support for the defined MIME types of the base application services depending on the platform implementation.

Handling Alarms

The Alarm API (in mobile and wearable applications) provides functions to launch an application at a specific time. The mechanism involved in launching the application is the App Control API (in mobile and wearable applications).

The AppControl API allows launching an application explicitly, giving its package name, or providing certain criteria that the application must meet. For example, the criteria can include the type of data on which the application must be able to operate. The structure containing the criteria is called an appcontrol.

For more information, see the Launching Applications guide.

Managing Application States and Transitions

The Tizen native application can be in one of several different states. Typically, the application is launched by the user from the Launcher, or by another application. As the application is starting, the app_create_cb() callback is executed and the main event loop starts. The application now normally becomes the frontmost window, with focus. When the application loses the frontmost or focus status, the app_pause_cb() callback is invoked and your application goes into a pause state. The pause state means that the application is not terminated but is running in the background. The application can go into a pause state because:

  • A new application is launched from the request of your application.
  • The user requests to go to the home screen.
  • A system event occurs and causes a resident application with a higher priority (such as an incoming phone call) to become active and hide your application temporarily.
  • An alarm is triggered for another application, which becomes the top-most window and hides your application.

When your application becomes visible again, the app_resume_cb() callback is invoked. This happens because:

  • Another application requests your application to run (perhaps the Task Navigator, which shows all running applications and lets the user select any application to run).
  • All applications on top of your application in the window stack finish.
  • An alarm is triggered for your application, so it becomes the top-most window and hides other applications.

When your application starts exiting, the app_terminate_cb() callback is invoked. Your application terminates because:

  • Your application itself requests to exit by calling the ui_app_exit() function to terminate the event loop.
  • The Low Memory Killer is killing your application in a low memory situation.

The application state changes are managed by the underlying framework. The following figure and table illustrate the application states.

Figure: Application states

Application state transitions

Table: Application states
State Description
READY Application is launched.
CREATED Application starts the main loop.
RUNNING Application is running and visible to the user.
PAUSED Application is running but invisible to the user.
TERMINATED Application is terminated.

The Application API defines 5 states with corresponding transition handlers. The state transition is notified through a state transition callback function, whether the application is created, running, paused, resumed, or terminated. The application must react to each state change appropriately.

Figure: Application state transitions

Application state transitions

Localizing Application Strings

Tizen provides localized resources to make your application usable for different countries. The localization is based on the Internationalization API (in mobile and wearable applications), which makes strings translatable and places them in .po (portable object) files.

Note

The .po files must be placed in the res/po directory of the application. The files can be edited using the PO File Editor provided by the Tizen SDK.

Depending on the device's locale information, your application must load the proper resource set. If no matching resource set is found for the device's current locale, the default resource set is used.

To get the localized value of a string, use the MsgID shown in the PO File Editor, prefaced with an underscore _ (for example, _(<MsgID>)). The underlying implementation calls the i18n_get_text() function to retrieve the localized value:

char *hello_text = i18n_get_text("Hello");

The hello_text variable is set to the localized text for "Hello" for the current locale of the device.

When you change the language setting on the device, the text changes in the application according to the current language.

Marking Text Parts as Translatable

The most common way to use a translation involves the following APIs:

elm_object_translatable_text_set(Evas_Object *obj, const char *text)
elm_object_item_translatable_text_set(Elm_Object_Item *it, const char *text)

They set the untranslated string for the "default" part of the given Evas_Object or Elm_Object_Item and mark the string as translatable.

Similar functions are available if you wish to set the text for a part that is not "default":

elm_object_translatable_part_text_set(Evas_Object *obj, const char *part, const char *text)
elm_object_item_translatable_part_text_set(Elm_Object_Item *it, const char *part, const char *text)

It is important to provide the untranslated string to these functions, because the EFLs trigger the translation themselves and re-translate the strings automatically, if the system language changes.

Translating Texts Directly

The approach described in the previous section is not applicable all of the time. For instance, it does not work if you are populating a genlist, if you need plurals in the translation or if you want to do something else than put the translation in elementary UI components.

It is possible to retrieve the translation for a given text through the i18n_get_text() function from app_i18n.h.

char *i18n_get_text(const char *msgid);

This function takes as input a string (that is copied to an msgid field in the .po files) and returns the translation (the corresponding msgstr field).

Note
Do not modify or free the return value of these functions. They are statically allocated.

When giving the text for a genlist item, you can use it in a similar manner as in the example below.

#include "app_i18n.h"
static char *_genlist_text_get(void *data, Evas_Object *obj, const char *part)
{
   return strdup(i18n_get_text("Some Text"));
}

Plurals

Plurals are handled through the ngettext() function. Its prototype is shown below.

char *ngettext(const char *msgid, const char *msgid_plural, unsigned long int n);
  • msgid is the same as before, that is, the untranslated string
  • msgid_plural is the plural form of msgid
  • the quantity (in English, 1 is singular and anything else is plural)

A matching fr.po file contains the following lines.

msgid "%d Comment"
msgid_plural "%d Comments"
msgstr[0] "%d commentaire"
msgstr[1] "%d commentaires"

Several Plurals

It is possible to have several plural forms. For instance, the .po file for Polish could contain the following lines.

msgid "%d Comment"
msgid_plural "%d Comments"
msgstr[0] "%d Komentarz"
msgstr[1] "%d Komentarze"
msgstr[2] "%d Komentarzy"

The index values after msgstr are defined in system-wide settings. The ones for Polish are given below:

"Plural-Forms: nplurals = 3; plural = n = = 1 ? 0 : n%10> = 2 && n%10< = 4 && (n%100<10 | | n%100> = 20) ? 1 : 2;\n"

There are three forms (including singular). The index is 0 (singular), if the given integer n is 1. Then, if (n % 10 >= 2 && % 10 <= 4 && (n % 100 < 10 | | n % 100 >= 20), the index is 1, otherwise it is 2.

Handling Language Changes at Runtime

The user can change the system language settings at any time. When that is done, the framework notifies the application, which changes the language used in the Elementary. The UI components receive a "language,changed" signal and reset their text.

This is how to handle the framework event:

static void
_app_language_changed(void *data)
{
   char *language;
   // Retrieve the current system language
   system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &language);
   // Set the language in elementary
   elm_language_set(language);
   free(language);
}
int
main(int argc, char *argv[])
{
   ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, _app_language_changed, &ad);
}

The call to elm_language_set() above triggers the emission of the "language,changed" signal, which is handled the same way as the typical smart event signals.

Extracting Messages for Translation

The xgettext tool extracts strings to translate to a .pot file (po template), while msgmerge maintains the existing .po files. The typical workflow is as follows:

  • run xgettext once; it generates a .pot file
  • when adding a new translation, copy the .pot file to <locale>.po and translate that file
  • new runs of xgettext update the existing .pot file and msgmerge updates the .po files

The following example is a typical call to xgettext.

xgettext --directory = src --output-dir = res/po --keyword = _ --keyword = N_ --keyword = elm_object_translatable_text_set:2 --keyword = elm_object_item_translatable_text_set:2 --add-comments = --from-code = utf-8 --foreign-use

This extracts all strings that are used inside the _() function (as an optional short-hand for i18n_get_text()), use UTF-8 as the encoding and add the comments right before the strings to the output files).

The following example is a typical call to msgmerge.

msgmerge --width=120 --update res/po/fr.po res/po/ref.pot

Internationalization Tips

Do Not Make Assumptions about Languages

Languages vary greatly and even if you knew several of them, do not assume there is any common logic to them.

For example, with English typography, no character must appear before colons and semicolons (':' and ';'). However, with French typography, there must be "espace fine insécable", that is, a non-breakable space (HTML's &nbsp;) that is narrower that regular spaces.

This prevents proper translation in the following construct:

snprintf(buf, some_size, "%s: %s", i18n_get_text(error), i18n_get_text(reason));

The correct way to translate it is to use a single string and let the translators manage the punctuation. This means translating the format string instead:

snprintf(buf, some_size, i18n_get_text("%s: %s"), i18n_get_text(error), i18n_get_text(reason));

It is not always possible, but aim for this unless a specific issue arises.

Translations Are of Different Lengths

Depending on the language, the translation has a different length on screen. In some cases, a language has a shorter construct than another, while the situation is reversed in another case; a language may have a word for a specific concept, while another does not and requires a circumlocution (designating something by using several words).

For Source Control, Do Not Commit .po If Only Line Indicators Have Changed

From the example above, a translation block looks like:

#: some_file.c:43 another_file.c:41
msgid "Click Here"
msgstr "Cliquez ici"

In case you insert a new line at the top of "some_file.c", the line indicator changes to look like this:

#: some_file.c:44 another_file.c:41

Obviously, on non-trivial projects, such changes often happen. If you use source control and commit such changes even though no actual translation change has happened, each commit probably contains a change to .po files. This hampers readability of the change history, and in case several people are working in parallel and need to merge their changes, this creates huge merge conflicts each time.

Only commit changes to .po files when there are actual translation changes, not because line comments have changed.

Using _() as Shorthand to the i18n_get_text() Function

Since calling i18n_get_text() may often happen, it is abbreviated to _(). The Tizen SDK provides this abbreviation by default.

Proper Sorting: strcoll()

There is a string comparison tailored for sorting data for display: strcoll(). It works the same way as strcmp() but sorts the data according to the current locale settings.

int strcmp(const char *s1, const char *s2);
int strcoll(const char *s1, const char *s2);

The function prototype is a standard one and indicates how to order strings. A detailed explanation is out of scope for this guide, but use the strcoll() function as the comparison function for sorting the data set you are using.

Working with Translators

The system described above is a common one and is likely to be known to translators, meaning that giving its name (gettext) may be enough to explain how it works. In addition to this documentation, there is extensive additional documentation as well as questions and answers on the topic in the Internet.

Do not hesitate to put comments in your code above the strings to be translated, since they can be extracted along with the strings and saved in the .po files for the translator to see them.

Go to top