The Event sample application demonstrates how you can create listeners for specified system and custom events, and listen to both types of events. To receive a custom event using a listener, the listener must be created and published.
The following figure illustrates the application view.
Figure: Event application screens
The sample application provides a user interface for previewing available events and their status:
- System events:
- Battery level and charger status
- USB and earjack status
- Display state and auto-rotation mode
- System boot and shutdown status
- Memory status
- Wi-Fi, Bluetooth, mobile data, and roaming state
- Location, GPS, and NPS state
- Incoming message status
- Time, time zone, and hour format change
- Language and region format change
- Silent and vibration mode change
- Font change
- Custom events:
- Custom events are received once they are registered and published by the user using the Custom events tab.
The following figure shows the structure of the user interface. EDJE layout scripts are used.
Figure: Event main layout structure
The PART_MAIN_CONTENT swallow is used as a container for both available layouts.
Figure: Event tab layout structure
The final application view is created by embedding the proper components into the layouts depicted above. The resulting UI views are shown in the following figure.
Figure: Event application UI view
The application workflow can be divided into 3 logical pipelines:
- Application startup
- System event handling
- Custom event creation, publishing, and receiving
The following figure describes the workflow.
Figure: Application workflow
Prerequisites
To ensure proper application execution, the following privileges must be set:
- http://tizen.org/privilege/network.get
- http://tizen.org/privilege/message.read
- http://tizen.org/privilege/display
Implementation
Type Definitions
The following code shows the structures used as placeholders for various application data:
// General structure for application data storage struct __appdata { viewdata_s view; }; // All the Evas_Object objects represent UI components struct __viewdata { Evas_Object *win; Evas_Object *conform; Evas_Object *layout_main_panel; Evas_Object *main_toolbar; Evas_Object *main_toolbar_item_system_ev; Evas_Object *main_toolbar_item_custom_ev; Evas_Object *layout_system_ev; Evas_Object *system_ev_list; Evas_Object *layout_custom_ev; Evas_Object *custom_ev_name; Evas_Object *custom_ev_submit; Evas_Object *custom_ev_list; Elm_Genlist_Item_Class *custom_ev_itc; // Structure of callbacks handlers used by the Controller module to establish interaction with the Model module viewcallbacks_s callbacks; }; typedef struct __viewdata viewdata_s; // All the callback handlers are hooked by the Controller module to relate the control flow between the View and the Model modules struct __viewcallbacks { // Invoked when the custom event needs to be published event_do_publish_cb do_publish_cb; // Invoked at the initialization phase to obtain all the information about system events for UI generation purpose event_get_system_info_cb get_system_info_cb; // Invoked when the user requests to register a custom event handler event_set_custom_info_cb set_custom_info_cb; }; typedef struct __viewcallbacks viewcallbacks_s; // Definition of callback handlers declared in the viewcallbacks_s structure typedef void (* event_do_publish_cb)(const char *event_name); typedef bool (* event_get_system_info_cb)(int index, void **ev_info); typedef bool (* event_set_custom_info_cb)(const char *event_name, void **ev_info); // Structure keeps all the event-related information struct __system_ev_info { // Type of the event - used only for the system events specification // Type is defined as an enum whose values represent all available system events event_type_t type; // Name of the event char *name; // Readable description of the event char *desc; // Status of the event char *status_1; // Status of the event. Used if the event contains up to 2 different status information: // Incoming message type / ID char *status_2; // Status of the event. Used if the event contains up to 3 different status information: // Bluetooth state / LE state / transferring state char *status_3; // Event callback handler function event_handler_h event_h; }; typedef struct __system_ev_info system_ev_info_s; typedef struct __system_ev_info custom_ev_info_s; // Types of system events defined for source code simplification // This type definition introduces event name mapping to its numerical representation typedef enum { ET_BATTERY_CHARGER_STATUS, // SYSTEM_EVENT_BATTERY_CHARGER_STATUS ET_BATTERY_LEVEL_STATUS, // SYSTEM_EVENT_BATTERY_LEVEL_STATUS ET_USB_STATUS, //SYSTEM_EVENT_USB_STATUS ET_EARJACK_STATUS, // SYSTEM_EVENT_EARJACK_STATUS ET_DISPLAY_STATE, // SYSTEM_EVENT_DISPLAY_STATE ET_BOOT_COMPLETED, // SYSTEM_EVENT_BOOT_COMPLETED ET_SYSTEM_SHUTDOWN, // SYSTEM_EVENT_SYSTEM_SHUTDOWN ET_LOW_MEMORY, // SYSTEM_EVENT_LOW_MEMORY ET_WIFI_STATE, // SYSTEM_EVENT_WIFI_STATE ET_BT_STATE, // SYSTEM_EVENT_BT_STATE ET_LOCATION_ENABLE_STATE, // SYSTEM_EVENT_LOCATION_ENABLE_STATE ET_GPS_ENABLE_STATE, // SYSTEM_EVENT_GPS_ENABLE_STATE ET_NPS_ENABLE_STATE, // SYSTEM_EVENT_NPS_ENABLE_STATE ET_INCOMMING_MSG, // SYSTEM_EVENT_INCOMMING_MSG ET_TIME_CHANGED, // SYSTEM_EVENT_TIME_CHANGED ET_TIME_ZONE, // SYSTEM_EVENT_TIME_ZONE ET_HOUR_FORMAT, // SYSTEM_EVENT_HOUR_FORMAT ET_LANGUAGE_SET, // SYSTEM_EVENT_LANGUAGE_SET ET_REGION_FORMAT, // SYSTEM_EVENT_REGION_FORMAT ET_SILENT_MODE, // SYSTEM_EVENT_SILENT_MODE ET_VIBRATION_STATE, // SYSTEM_EVENT_VIBRATION_STATE ET_SCREEN_AUTOROTATE_STATE, // SYSTEM_EVENT_SCREEN_AUTOROTATE_STATE ET_MOBILE_DATA_STATE, // SYSTEM_EVENT_MOBILE_DATA_STATE ET_DATA_ROAMING_STATE, // SYSTEM_EVENT_DATA_ROAMING_STATE ET_FONT_SET // SYSTEM_EVENT_FONT_SET } event_type_t;
The Model module declares 2 arrays:
- static system_ev_info_s __system_ev[__SYSTEM_EVENT_COUNT_MAX];
- static custom_ev_info_s __custom_ev[__CUSTOM_EVENT_COUNT_MAX];
The arrays are used to store system and custom event information. The __SYSTEM_EVENT_COUNT_MAX and __CUSTOM_EVENT_COUNT_MAX values are both set to 25 as the upperbound limit.
Application Initialization
To initialize the application:
- Implement the entire application life-cycle in the main source file, using a common Tizen application structure:
int main(int argc, char *argv[]) { appdata_s ad = {{0,},}; int ret = 0; ui_app_lifecycle_callback_s event_callback; app_event_handler_h handlers[5] = {NULL,}; event_callback.create = __create_app; event_callback.terminate = __terminate_app; event_callback.pause = __pause_app; event_callback.resume = __resume_app; event_callback.app_control = __control_app; ui_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, __ui_app_low_battery, &ad); ui_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, __ui_app_low_memory, &ad); ui_app_add_event_handler(&handlers[APP_EVENT_DEVICE_ORIENTATION_CHANGED], APP_EVENT_DEVICE_ORIENTATION_CHANGED, __ui_app_orient_changed, &ad); ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, __ui_app_lang_changed, &ad); ui_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, __ui_app_region_changed, &ad); ret = ui_app_main(argc, argv, &event_callback, &ad); if (ret != APP_ERROR_NONE) controller_log(DLOG_ERROR, "Function ui_app_main() failed with error = %d", ret); return ret; }
- Execute the application initialization process in the __create_app() callback function, which is invoked on application startup:
static bool __create_app(void *data) { appdata_s *ad = (appdata_s *)data; return controller_init(&ad->view); }
- Invoke the controller_init() function, which controls the entire initialization process. This function is responsible for attaching the callback functions invoked by the View module to perform the required tasks:
- __controller_event_do_publish_cb(): Publish the custom event registered by the user
- __controller_event_get_system_info_cb(): Query system event information to populate the list with relevant data
- __controller_event_set_custom_info_cb(): Register the event handler to be invoked on custom event occurrence
The first and the third callback functions are called when the user performs an appropriate action in the application UI. The second callback function is called during the application UI creation.
The application UI is created with the view_create_base_gui() function. Its source code is not listed within this topic. At the end of the initialization phase, a callback function is attached to each of the available system events within the __add_system_event_handlers() function.
For a reference of all model-related functions not listed here, see Model.
bool controller_init(viewdata_s *vd) { vd->callbacks.do_publish_cb = __controller_event_do_publish_cb; vd->callbacks.get_system_info_cb = __controller_event_get_system_info_cb; vd->callbacks.set_custom_info_cb = __controller_event_set_custom_info_cb; if (!view_create_base_gui(vd)) return false; __add_system_event_handlers(); return true; } static void __add_system_event_handlers(void) { int i; // Iteration over all available system events for (i = 0; i < model_get_system_events_count(); i++) { system_ev_info_s *ev_info = NULL; // System event information structure is obtained if (!model_get_system_event_info(i, &ev_info)) continue; // Event handler is created and a callback function is attached model_add_system_event_handler(ev_info, __system_event_cb, (void *)ev_info); } }
- Attach the implementation of the callback functions in the controller_init() function:
static void __controller_event_do_publish_cb(const char *event_name) { controller_log(DLOG_INFO, "Event publishing: '%s'.", event_name); model_publish_event(event_name); }
The __controller_event_get_system_info_cb() callback is invoked by the View module as long as the function returns true. Each time, the function is called with an incremented index value. As a result, the system event information ev_info, stored at specified index, is returned. The requested data structure is obtained with the model_get_system_event_info() function.
static bool __controller_event_get_system_info_cb(int index, void **ev_info) { *ev_info = NULL; if (index >= model_get_system_events_count()) return false; system_ev_info_s *ev_info_tmp = NULL; if (!model_get_system_event_info(index, &ev_info_tmp)) return false; *ev_info = (system_ev_info_s *)ev_info_tmp; return true; }
-
The __controller_event_set_custom_info_cb() callback is invoked by the View model when the user requests to register custom event. If the registration procedure succeeds (see the __controller_register_custom_event() function implementation for details), the reference to the event information structure is returned using the ev_info parameter.
static bool __controller_event_set_custom_info_cb(const char *event_name, void **ev_info) { *ev_info = NULL; custom_ev_info_s *ev_info_tmp = NULL; if (!__controller_register_custom_event(event_name, &ev_info_tmp)) return false; *ev_info = (custom_ev_info_s *)ev_info_tmp; return true; } bool __controller_register_custom_event(const char *event_name, custom_ev_info_s **ev_info) { *ev_info = NULL; bool name_exists = false; // Event name, assigned by the user, must be unique, so you have to check whether it exists yet if (!model_check_event_exists(event_name, &name_exists)) return false; // If there is already an event registered with the given name, the function fails if (name_exists) { controller_log(DLOG_WARN, "Custom event '%s' already registered.", event_name); return false; } // Otherwise new event information structure is created if (!model_create_custom_event_info(event_name, ev_info)) return false; // Finally, the event callback function is assigned, to be invoked when the event occurs if (!model_add_custom_event_handler(*ev_info, __custom_event_cb, (void *)(*ev_info))) return false; controller_log(DLOG_INFO, "Custom event registered: '%s'.", (*ev_info)->name); return true; }
Application Termination
To terminate the application:
- When the application is terminated, call the __terminate_app() callback function:
static void __terminate_app(void *data) { appdata_s *ad = (appdata_s *)data; controller_finit(&ad->view); }
- Release all previously allocated resources with the controller_finit() function, which is responsible for destroying the UI and detaching system and custom events handlers:
void controller_finit(viewdata_s *vd) { view_destroy_base_gui(vd); model_finit(); }
- Detach the events handlers in the Model module within the model_finit() function, which calls 2 internal functions: __model_release_system_events() and __model_release_custom_events().
As the UI is not a subject for this topic, the implementation of the view_destroy_base_gui() function is omitted.
void model_finit(void) { __model_release_system_events(); __model_release_custom_events(); }
- The events handler detaching procedure relies on the __model_remove_event_handler() function for each attached event handler regardless of its type (system or custom). The related resources are freed with the __model_free_system_event_info() and __model_free_custom_event_info() functions. For reference, see Model.
static void __model_release_system_events(void) { int i; for (i = 0; i < __SYSTEM_EVENT_COUNT_MAX; i++) { system_ev_info_s *ev_info = &__system_ev[i]; __model_remove_event_handler(ev_info->event_h); __model_free_system_event_info(ev_info); } } static void __model_release_custom_events(void) { int i; for (i = 0; i < __custom_ev_count; i++) { custom_ev_info_s *ev_info = &__custom_ev[i]; __model_remove_event_handler(ev_info->event_h); __model_free_custom_event_info(ev_info); } __custom_ev_count = 0; }
The __model_free_system_event_info() and __model_free_custom_event_info() functions are not listed here, as their implementation is based only on the free() function used to free the previously allocated memory.
System Events
After all the system events are successfully hooked in the initialization phase, they can be handled once they occur. This is done with the __system_event_cb() callback function registered within the __add_system_event_handlers() function. For reference, see Application Initialization.
static void __system_event_cb(const char *event_name, bundle *event_data, void *user_data) { system_ev_info_s *ev_info = (system_ev_info_s *)user_data; char *status_1 = NULL; char *status_2 = NULL; char *status_3 = NULL; controller_log(DLOG_INFO, "System event '%s' occurred.", event_name); switch (ev_info->type) { case ET_<event_type>: if (!model_get_bundle_str(event_data, EVENT_KEY_<name_1>, &status_1) || !model_get_bundle_str(event_data, EVENT_KEY_<name_2>, &status_2) || !model_get_bundle_str(event_data, EVENT_KEY_<name_3>, &status_3)) return; break; default: return; } // status_1 ... status_3 char buffers are copied to the ev_info->status_1 ... ev_info->status_3 model_assign_event_status(&ev_info->status_1, status_1); model_assign_event_status(&ev_info->status_2, status_2); model_assign_event_status(&ev_info->status_3, status_3); view_update_system_events(); }
All the information carried by the event is stored in a bundle object structure (event_data) followed by the event name (event_name). To avoid using an inefficient string comparison function for event distinguishing, the custom event type is used (see the event_type_t definition in the Type Definitions section). These types are statically preassigned. Based on the value of the type member of the ev_info structure of the system_ev_info_s data type, the events are distinguished and the event state is obtained from the bundle object.
Each event name and the relevant bundle keys are defined by the Event API. To extract the event status, the model_get_bundle_str() function is used. For the relation between the ET_<event_type> and EVENT_KEY_<name_1> ... EVENT_KEY_<name_3>, see the Event API.
Once the valid event status is obtained, the UI is updated to reflect the current event state using the view_update_system_events() function.
Custom Events
To manage custom events:
-
Once the user registers a new event using the Register event button, the __controller_register_custom_event() function is invoked in a __controller_event_set_custom_info_cb() callback function triggered by the __view_register_event_button_clicked_cb() function attached to the Register event button. To clarify the process, all the mentioned functions are listed in the following example in the order of invocation.
// Invoked on "Register event" button press static void __view_register_event_button_clicked_cb(void *data, Evas_Object *obj, void *event_info) { viewdata_s *vd = (viewdata_s *)data; custom_ev_info_s *ev_info = NULL; char *event_name = NULL; // Event name input by the user is obtained if (!__view_get_custom_event_name(vd, &event_name)) { controller_log(DLOG_WARN, "The custom event has no name assigned."); return; } // If the event name is provided properly, the Controller callback function is invoked // to register a new event with the given name bool ret = false; if (vd->callbacks.set_custom_info_cb) ret = vd->callbacks.set_custom_info_cb((const char *)event_name, (void *)&ev_info); free(event_name); if (!ret) return; // Once the custom event is registered successfully, the UI is updated to reflect recent changes elm_genlist_item_append(__viewdata->custom_ev_list, __viewdata->custom_ev_itc, (void *)ev_info, NULL, ELM_GENLIST_ITEM_NONE, __view_custom_event_item_select_cb, (void *)ev_info); } // Invoked within the __view_register_event_button_clicked_cb() static bool __controller_event_set_custom_info_cb(const char *event_name, void **ev_info) { *ev_info = NULL; custom_ev_info_s *ev_info_tmp = NULL; // Custom event registration is performed here if (!__controller_register_custom_event(event_name, &ev_info_tmp)) return false; *ev_info = (custom_ev_info_s *)ev_info_tmp; return true; } bool __controller_register_custom_event(const char *event_name, custom_ev_info_s **ev_info) { *ev_info = NULL; bool name_exists = false; // Before the custom event is registered, verify whether the provided name exists // There is no dedicated Event API function which performs this task. In such case, // the Model iterates over all registered custom events stored within the internal data structure // and compares the name being registered with those already registered if (!model_check_event_exists(event_name, &name_exists)) return false; if (name_exists) { controller_log(DLOG_WARN, "Custom event '%s' already registered.", event_name); return false; } // If the custom name fails the existence verification, the relevant data structure is created // to store event-related information internally if (!model_create_custom_event_info(event_name, ev_info)) return false; // Once the internal data structure is created, the custom event handler is registered // and the callback function attached to the event handler if (!model_add_custom_event_handler(*ev_info, __custom_event_cb, (void *)(*ev_info))) return false; controller_log(DLOG_INFO, "Custom event registered: '%s'.", (*ev_info)->name); return true; }
-
After the custom event is registered and appears on the list, it can be published by a simple click on the relevant list item. The published item can be hooked only by those applications which are signed with the publisher certificate. The entire publishing process is shown within the following source code.
// Invoked when the user selects an event-related item on the list static void __view_custom_event_item_select_cb(void *data, Evas_Object *obj, void *event_info) { custom_ev_info_s *ev_info = (custom_ev_info_s *)data; if (!ev_info) { controller_log(DLOG_ERROR, "ev_info == NULL !!!"); return; } else if (!ev_info->name) { controller_log(DLOG_ERROR, "ev_info->name == NULL !!!"); return; } // Controller is requested to publish the event by its name if (__viewdata->callbacks.do_publish_cb) __viewdata->callbacks.do_publish_cb(ev_info->name); } // Invoked by the __view_custom_event_item_select_cb() function static void __controller_event_do_publish_cb(const char *event_name) { controller_log(DLOG_INFO, "Event publishing: '%s'.", event_name); // Event is published model_publish_event(event_name); }
-
Once the event is published, the callback function attached to its handler is invoked within all those applications which are signed with the same certificate as the publisher. In this case, only the Event sample application receives the event using the previously attached __custom_event_cb() callback function:
static void __custom_event_cb(const char *event_name, bundle *event_data, void *user_data) { custom_ev_info_s *ev_info = (custom_ev_info_s *)user_data; char *status = NULL; // Each custom event owns only one predefined key pointing to its status: CUSTOM_EVENT_KEY_STATUS // The key is defined within this application: CUSTOM_EVENT_KEY_STATUS == "custom_event_status" if (!model_get_bundle_str(event_data, CUSTOM_EVENT_KEY_STATUS, &status)) return; // If the status is successfully obtained from the event bundle, it is stored within the internal data structure model_assign_event_status(&ev_info->status_1, status); // Finally, the event status is displayed on a toast message... view_display_custom_event(ev_info->name, ev_info->status_1); // ... and on the relevant list item view_update_custom_events(); }
For Model-related function implementation and description, see Model.
Model
The responsibility of the application Model module is to operate directly on the Event API and related data. The additional benefit of this module is the simplification of the API function calling, as error checking and message logging is performed here.
Some of the functions implemented within the Model module have been briefly described in Application Termination section (__model_release_system_events(), __model_release_custom_events(), model_finit(), __model_free_system_event_info(), __model_free_custom_event_info()). The most important functions are described here.
Most of the Model functions operate on the system_ev_info_s or custom_ev_info_s structures, which represent the system and custom events internally.
To operate on the Event API and related data with the Model module:
-
Add a handler to the specified event with the model_add_<event_type>_event_handler() function, where <event_type> stands for system or custom:
bool model_add_<event_type>_event_handler(<event_type>_ev_info_s *ev_info, event_cb callback, void *user_data) { if (!ev_info || !callback) { controller_log(DLOG_ERROR, "Wrong argument provided."); return false; } // Event API function is called with name stored in the internal data structure // Callback function is attached to the event handler int ret = event_add_event_handler(ev_info->name, callback, user_data, &ev_info->event_h); if (ret != EVENT_ERROR_NONE) { controller_log(DLOG_ERROR, "Function event_add_event_handler() failed with error = %d.", ret); return false; } return true; }
-
Release the event handler using the __model_remove_event_handler() function regardless of its <event_type>:
bool __model_remove_event_handler(event_handler_h event_handler) { int ret = event_remove_event_handler(event_handler); if (ret != EVENT_ERROR_NONE) { controller_log(DLOG_ERROR, "Function event_remove_event_handler() failed with error = %d.", ret); return false; } return true; }
-
To publish a custom event, the model_publish_event() function must be called with the event name:
bool model_publish_event(const char *event_name) { static unsigned int custom_ev_counter = 0; if (!event_name) { controller_log(DLOG_ERROR, "Wrong argument provided."); return false; } // Bundle object is the carrier of the event information // It must be created and filled with proper data which describes event status bundle *bundle_ev = bundle_create(); if (!bundle_ev) { controller_log(DLOG_ERROR, "Function bundle_create() failed."); return false; } // Custom event status is created by simple concatenation of the status counter (custom_ev_counter) followed by the "status value" label custom_ev_counter++; char status[__STATUS_MSG_BUFF] = {0,}; snprintf(status, __STATUS_MSG_BUFF, "status value %u", custom_ev_counter); // Custom event status string is added to the event information carrier (bundle object) // with predefined key: CUSTOM_EVENT_KEY_STATUS == "custom_event_status" int ret = bundle_add_str(bundle_ev, CUSTOM_EVENT_KEY_STATUS, status); if (ret != EVENT_ERROR_NONE) { controller_log(DLOG_ERROR, "Function bundle_add_str() failed with error %d.", ret); return false; } // Finally, the event (identified by event_name) is published (broadcasted) with the previously created bundle object ret = event_publish_app_event(event_name, bundle_ev); // Once the event is published, the associated bundle object is not necessary anymore - it must be freed bundle_free(bundle_ev); if (ret != EVENT_ERROR_NONE) { controller_log(DLOG_ERROR, "Function event_publish_app_event() failed with error %d.", ret); return false; } return true; }
The custom event name must strictly follow the event.<app_id>.<custom_name> naming rule defined by the Event API. In the name, <app_id> is the identifier of the calling application, and <custom_name> is a custom name assigned by you or the user. For this reason, the supporting __model_format_custom_event_name() function is implemented.
static void __model_format_custom_event_name(const char *custom_name, char **ev_name) { // Naming rule is applied int ev_name_len = strlen("event") + strlen(APP_ID) + strlen(custom_name) + 3; *ev_name = (char *)calloc(ev_name_len, sizeof(char)); snprintf(*ev_name, ev_name_len, "event.%s.%s", APP_ID, custom_name); // All whitespaces are removed from the <custom_name> and the string is converted to the lower case int i; for (i = 0; i < ev_name_len; i++) { (*ev_name)[i] = tolower((*ev_name)[i]); if ((*ev_name)[i] == 32) (*ev_name)[i] = '_'; } }
-
Use the model_get_bundle_str() function to obtain the event status from the associated bundle object based on the known CUSTOM_EVENT_KEY_STATUS == "custom_event_status" key.
bool model_get_bundle_str(bundle *bundle_obj, const char *key, char **str) { *str = NULL; int ret = bundle_get_str(bundle_obj, key, str); if (ret != BUNDLE_ERROR_NONE) { controller_log(DLOG_ERROR, "Function bundle_get_str() failed with error = %d.", ret); return false; } return true; }
The following list gives a brief description on the roles of the remaining functions.
- model_get_system_events_count(): Returns the number of registered system events based on the number of relevant data stored internally.
- model_get_system_event_info(): Returns the system event information structure stored internally.
- model_create_custom_event_info(): Creates the custom event information structure and stores it internally.
- model_assign_event_status(): Assigns the status message to the specified event structure stored internally.
- model_check_event_exists(): Checks whether given event name is already registered within internal data structure.