Widget Application: Creating Widget Applications
This tutorial demonstrates how you can create a widget application.
Warm-up
Become familiar with the Widget Application API basics by learning about:
-
Initializing the Widget Application
Initialize a widget application for use.
-
Creating the Widget Application
Create a widget application, and define and register system callbacks.
-
Managing Widget Instance Life-cycle Callbacks
Define and register life-cycle callbacks.
-
Drawing the Widget UI
Create a UI object of the widget on the home screen.
-
Managing the Widget Instance
Get the widget instance and the instance ID.
Initializing the Widget Application
To initialize the widget application:
- To use the functions and data types of the Widget Application API (in mobile and wearable applications), include the <widget_app.h> header file in your application:
#include <widget_app.h>
- Edit the widget application settings in the manifest file.
Creating the Widget Application
To create the widget application:
-
Start and initialize the application with the main() function.
Set up the widget_app_lifecycle_callback_s structure variable for the widget application life-cycle callbacks, define the functions themselves (widget_app_create() for initialization and widget_app_terminate() for termination), and call the widget_app_main() function to start the application event loop.
int main(int argc, char *argv[]) { widget_app_lifecycle_callback_s ops = {0,}; int ret; ops.create = widget_app_create; ops.terminate = widget_app_terminate; ret = widget_app_main(argc, argv, &ops, NULL); if (ret != WIDGET_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "widget_app_main() failed. err = %d", ret); } return ret; }
- Use the widget_app_create() life-cycle function to initialize any resources that can be shared among widget instances. This function is called before the main event loop starts.
widget_class_h widget_app_create(void *user_data) { // Hook to take necessary actions before main event loop starts widget_instance_lifecycle_callback_s obj_callback = {0,}; app_event_handler_h handlers[5] = {NULL,}; // Register the callback functions for the widget instance life-cycle
- Register the callback functions for the system events.
At the end of the widget_app_create() function, remember to create a widget instance class and return a handle for it, so that the handle can be used for making widget instances.
// Register the callback functions for system events widget_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, widget_app_low_battery, NULL); widget_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, widget_app_low_memory, NULL); widget_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, widget_app_lang_changed, NULL); widget_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, widget_app_region_changed, NULL); return widget_app_class_create(obj_callback, user_data); }
When the system-related callback are no longer needed, remove them with the widget_app_remove_event_handler() function.
- Define the callback functions for the system events:
void widget_app_lang_changed(app_event_info_h event_info, void* user_data) { // Take actions when language setting changes and messages must be translated char *locale = NULL; app_event_get_language(event_info, &locale); elm_language_set(locale); free(locale); } void widget_app_region_changed(app_event_info_h event_info, void* user_data) { // Take actions when the time zone changes } void widget_app_low_battery(app_event_info_h event_info, void* user_data) { // Take actions when system is running low on battery (less than 5%) // Save the work and avoid battery-intensive processes widget_app_exit(); } void widget_app_low_memory(app_event_info_h event_info, void* user_data) { // Take actions when system is running on low memory // Save the work and release resources; if necessary, some apps can be killed widget_app_exit(); }
- When you no longer need the widget application, release the resources and terminate the application:
static void widget_app_terminate(void *user_data) { // Release all resources }
Managing Widget Instance Life-cycle Callbacks
To manage the widget instance life-cycle:
- Define the widget instance life-cycle callbacks:
- This callback is triggered when the widget instance is created.
Initialize resources for this widget instance and draw the UI. If bundle content is not NULL, restore the previous status.
int widget_instance_create(widget_context_h context, bundle *content, int w, int h, void *user_data) { widget_instance_data_s *wid = (widget_instance_data_s*) malloc(sizeof(widget_instance_data_s)); int ret; if (content != NULL) { // Recover the previous status with the bundle object } // Create the UI return WIDGET_ERROR_NONE; }
- This callback is triggered when the widget instance is destroyed.
Release all widget resources. If the reason for the termination is not WIDGET_APP_DESTROY_TYPE_PERMANENT, store the current status with the incoming bundle.
int widget_instance_destroy(widget_context_h context, widget_app_destroy_type_e reason, bundle *content, void *user_data) { if (reason != WIDGET_APP_DESTROY_TYPE_PERMANENT) { // Save the current status at the bundle object } return WIDGET_ERROR_NONE; }
- This callback is triggered when the widget instance is paused.
Take the necessary actions since the widget instance becomes invisible. The framework can destroy a paused widget instance.
int widget_instance_pause(widget_context_h context, void *user_data) { return WIDGET_ERROR_NONE; }
- This callback is triggered when the widget instance is resumed.
Take the necessary actions since the widget instance becomes visible.
int widget_instance_resume(widget_context_h context, void *user_data) { return WIDGET_ERROR_NONE; }
- This callback is triggered before the widget instance is resized.
Take the necessary actions to accommodate the new size.
int widget_instance_resize(widget_context_h context, int w, int h, void *user_data) { return WIDGET_ERROR_NONE; }
- This callback is triggered when a widget update event is received.
Take the necessary actions for the widget update. If the force parameter is true, the widget can be updated even in the pause state.
int widget_instance_update(widget_context_h context, bundle *content, int force, void *user_data) { return WIDGET_ERROR_NONE; }
- This callback is triggered when the widget instance is created.
- Register the callbacks in the widget_instance_lifecycle_callback_s structure during the widget application initialization:
widget_class_h widget_app_create(void *user_data) { widget_instance_lifecycle_callback_s obj_callback = {0,}; // Register the callback functions obj_callback.create = widget_instance_create; obj_callback.destroy = widget_instance_destroy; obj_callback.pause = widget_instance_pause; obj_callback.resume = widget_instance_resume; obj_callback.resize = widget_instance_resize; obj_callback.update = widget_instance_update; // Register system-related callbacks return widget_app_class_create(obj_callback, user_data); }
Drawing the Widget UI
To draw the widget UI, you must get a window object with the widget_app_get_elm_win() function and create the UI on the home screen:
#include <widget_app_efl.h> typedef struct widget_instance_data { Evas_Object *win; Evas_Object *conform; Evas_Object *label; } widget_instance_data_s; static int widget_instance_create(widget_context_h context, bundle *content, int w, int h, void *user_data) { widget_instance_data_s *wid = (widget_instance_data_s*) malloc(sizeof(widget_instance_data_s)); int ret; if (content != NULL) { // Recover the previous status with the bundle object } // Window ret = widget_app_get_elm_win(context, &wid->win); if (ret != WIDGET_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "failed to get window. err = %d", ret); return WIDGET_ERROR_FAULT; } evas_object_resize(wid->win, w, h); // Conformant wid->conform = elm_conformant_add(wid->win); evas_object_size_hint_weight_set(wid->conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_win_resize_object_add(wid->win, wid->conform); evas_object_show(wid->conform); // Label wid->label = elm_label_add(wid->conform); evas_object_resize(wid->label, w, h / 3); evas_object_move(wid->label, 0, h / 3); evas_object_show(wid->label); elm_object_text_set(wid->label, "Hello widget"); // Show the window after the base GUI is set up evas_object_show(wid->win); widget_app_context_set_tag(context, wid); return WIDGET_ERROR_NONE; } int widget_instance_destroy(widget_context_h context, widget_app_destroy_type_e reason, bundle *content, void *user_data) { if (reason != WIDGET_APP_DESTROY_TYPE_PERMANENT) { // Save the current status at the bundle object } widget_instance_data_s *wid = NULL; widget_app_context_get_tag(context, (void**)&wid); if (wid->win) evas_object_del(wid->win); free(wid); return WIDGET_ERROR_NONE; }
Managing the Widget Instance
To manage the widget instance:
- You can set a customized widget instance with the widget_app_context_set_tag() function when the instance is created. To update or destroy the customized widget, get the instance with the widget_app_context_get_tag() function.
typedef struct { int val1; } user_defined_s; int widget_instance_create(widget_context_h context, bundle *content, int w, int h, void *user_data) { user_defined_s *uds = (user_defined_s*)malloc(sizeof(user_defined_s)); uds->val1 = 0; widget_app_context_set_tag(context, uds); } int widget_instance_destroy(widget_context_h context, widget_destroy_type_e reason, bundle *content, void *user_data) { user_defined_s *uds = NULL; widget_app_context_get_tag(context, (void**)&uds); free(uds); } int widget_instance_update(widget_context_h context, bundle *content, int force, void *user_data) { user_defined_s *uds = NULL; widget_app_context_get_tag(context, (void**)&uds); uds->val1 = 1; }
- Get the widget instance ID:
int widget_instance_update(widget_context_h context, bundle *content, int force, void *user_data) { const char *inst_id = NULL; inst_id = widget_app_get_id(context); }