The Context Trigger sample application demonstrates how you can manage contextual rules using the Contextual Trigger API. The application displays several rules in a genlist. You can tap each list item to start or stop the rule. When a rule is triggered, a notification is posted with an appropriate message.
The following figure illustrates the main view of the Context Trigger.
Figure: Context Trigger screen
Prerequisites
To ensure proper application execution, the following privileges must be set:
- To post a notification:
- http://tizen.org/privilege/notification
- To use The 5th-day-no-driving System rule:
- http://tizen.org/privilege/alarm.set
- To use the Home Wi-Fi rule:
- http://tizen.org/privilege/location
- http://tizen.org/privilege/network.get
Implementation
Rule Module
To initialize the rule module:
-
Use the app_create() callback function to initialize the Context Trigger sample application. Register the contextual rules with the add_rules() function. The following example shows how to create a rule handle for a battery rule and to register the rule.
void add_rules(void) { // Add rules rule_info[RULE_BATTERY].id = add_battery_rule(); rule_info[RULE_CALL].id = add_call_rule(); rule_info[RULE_DRIVING].id = add_driving_rule(); rule_info[RULE_HOME].id = add_home_rule(); } static int add_battery_rule(void) { int rule_id = 0; context_trigger_rule_h rule = NULL; context_trigger_rule_entry_h battery_e = NULL; bool battery_e_supported; context_trigger_rule_event_is_supported(CONTEXT_TRIGGER_EVENT_BATTERY, &battery_e_supported); if (!battery_e_supported) { rule_info[RULE_BATTERY].result = CONTEXT_TRIGGER_ERROR_NOT_SUPPORTED; return rule_id; } context_trigger_rule_create(CONTEXT_TRIGGER_LOGICAL_CONJUNCTION, &rule); context_trigger_rule_set_description(rule, rule_info[RULE_BATTERY].description); context_trigger_rule_event_create(CONTEXT_TRIGGER_EVENT_BATTERY, CONTEXT_TRIGGER_LOGICAL_CONJUNCTION, &battery_e); context_trigger_rule_entry_add_key(battery_e, CONTEXT_TRIGGER_LOGICAL_DISJUNCTION, CONTEXT_TRIGGER_LEVEL); context_trigger_rule_entry_add_comparison_string(battery_e, CONTEXT_TRIGGER_LEVEL, CONTEXT_TRIGGER_EQUAL_TO, CONTEXT_TRIGGER_EMPTY); context_trigger_rule_entry_add_comparison_string(battery_e, CONTEXT_TRIGGER_LEVEL, CONTEXT_TRIGGER_EQUAL_TO, CONTEXT_TRIGGER_CRITICAL); context_trigger_rule_entry_add_comparison_string(battery_e, CONTEXT_TRIGGER_LEVEL, CONTEXT_TRIGGER_EQUAL_TO, CONTEXT_TRIGGER_LOW); context_trigger_rule_entry_add_key(battery_e, CONTEXT_TRIGGER_LOGICAL_CONJUNCTION, CONTEXT_TRIGGER_IS_CHARGING); context_trigger_rule_entry_add_comparison_int(battery_e, CONTEXT_TRIGGER_IS_CHARGING, CONTEXT_TRIGGER_EQUAL_TO, CONTEXT_TRIGGER_FALSE); context_trigger_rule_add_entry(rule, battery_e); context_trigger_rule_set_action_notification(rule, rule_info[RULE_BATTERY].name, rule_info[RULE_BATTERY].msg, NULL, NULL); rule_info[RULE_BATTERY].result = context_trigger_add_rule(rule, &rule_id); if (rule_info[RULE_BATTERY].result != CONTEXT_TRIGGER_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "Failed to add '%s' rule: %d", rule_info[RULE_BATTERY].name, rule_info[RULE_BATTERY].result); context_trigger_rule_entry_destroy(battery_e); context_trigger_rule_destroy(rule); return rule_id; }
-
When the Context Trigger application is terminated, the app_terminate() callback function is called, and all registered rules are disabled and removed in the remove_rules() function. An enabled rule can be removed after being disabled.
void remove_rules(void) { // Get rules int enabled_rule_cnt = 0; int disabled_rule_cnt = 0; int *enabled_rule_ids = NULL; int *disabled_rule_ids = NULL; int error = context_trigger_get_own_rule_ids(&enabled_rule_ids, &enabled_rule_cnt, &disabled_rule_ids, &disabled_rule_cnt); if (error != CONTEXT_TRIGGER_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get rule ids"); return; } // Disable and remove enabled rules int i; for (i = 0; i < enabled_rule_cnt; i++) { context_trigger_disable_rule(enabled_rule_ids[i]); context_trigger_remove_rule(enabled_rule_ids[i]); } // Remove disabled rules for (i = 0; i < disabled_rule_cnt; i++) { context_trigger_remove_rule(disabled_rule_ids[i]); } if (enabled_rule_ids) { free(enabled_rule_ids); enabled_rule_ids = NULL; } if (disabled_rule_ids) { free(disabled_rule_ids); disabled_rule_ids = NULL; } }
View Manager Module
To create the genlist:
-
The genlist is created using the elm_genlist_add() function. For the genlist to be displayed properly, a genlist item class has to be created and defined with the elm_genlist_item_class_new() function. The following code snippet demonstrates how to set the item class properties. The text_get() and a content_get() callback functions are defined for creating the item text and layout.
int index; Evas_Object *genlist; Elm_Genlist_Item_Class *itc_name, *itc; // Create item class itc = elm_genlist_item_class_new(); itc->item_style = "multiline"; itc->func.text_get = _gl_text_get_cb; itc->func.content_get = _gl_content_get_cb; // Genlist genlist = elm_genlist_add(parent); elm_genlist_mode_set(genlist, ELM_LIST_COMPRESS); evas_object_size_hint_weight_set(genlist, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(genlist, EVAS_HINT_FILL, EVAS_HINT_FILL);
-
The genlist is filled with rule items. To append items to the genlist, the elm_genlist_item_append() function is invoked for each Eina_List item.
// For each rule for (index = RULE_FIRST; index < RULE_LAST; index++) { // Rule item elm_genlist_item_append(genlist, itc, (void *)&rule_info[index], NULL, ELM_GENLIST_ITEM_NONE, _gl_selected_cb, NULL); }
-
The application's rule_data structure contains its rule information, such as name and description. It is later passed on to the previously defined callback function. The following example shows the _gl_text_get_cb() and the _gl_content_get_cb() callback functions. The rule information is retrieved from the parameter and used to create the item layout.
static char* _gl_text_get_cb(void *data, Evas_Object * obj, const char *part) { rule_data_s *info = (rule_data_s *) data; if (!strcmp(part, "elm.text")) return strdup(info->name); else if (!strcmp(part, "elm.text.multiline")) return strdup(info->description); return NULL; } static Evas_Object* _gl_content_get_cb(void *data, Evas_Object * obj, const char *part) { rule_data_s *info = (rule_data_s *) data; if (!strcmp(part, "elm.swallow.end")) { Evas_Object *check = elm_check_add(obj); evas_object_smart_callback_add(check, "changed", _check_changed_cb, info); evas_object_propagate_events_set(check, EINA_FALSE); evas_object_size_hint_weight_set(check, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(check, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_object_style_set(check, "on&off"); elm_check_state_set(check, false); elm_check_state_pointer_set(check, &info->enabled); if (info->result != CONTEXT_TRIGGER_ERROR_NONE) elm_object_disabled_set(check, EINA_TRUE); return check; } return NULL; }
-
When a genlist item or a check button is clicked, a corresponding rule is enabled or disabled. If the user taps a rule item which fails to be added, an error popup is shown to indicate the error reason.
static void _gl_selected_cb(void *data, Evas_Object * obj, void *event_info) { Elm_Object_Item *it = (Elm_Object_Item *) event_info; elm_genlist_item_selected_set(it, false); rule_data_s *info = elm_object_item_data_get(it); if (info->result == CONTEXT_TRIGGER_ERROR_NONE) { int error = CONTEXT_TRIGGER_ERROR_NONE; Evas_Object *check = elm_object_item_part_content_get(it, "elm.swallow.end"); if (elm_check_state_get(check)) { error = disable_rule(info->id); if (error == CONTEXT_TRIGGER_ERROR_NONE) elm_check_state_set(check, !info->enabled); } else { error = enable_rule(info->id); if (error == CONTEXT_TRIGGER_ERROR_NONE) elm_check_state_set(check, !info->enabled); } } else { view_create_error_popup(data, info); } } static void _check_changed_cb(void *data, Evas_Object * obj, void *event_info) { rule_data_s *info = (rule_data_s *) data; int error = CONTEXT_TRIGGER_ERROR_NONE; if (elm_check_state_get(obj)) { error = enable_rule(info->id); if (error != CONTEXT_TRIGGER_ERROR_NONE) elm_check_state_set(obj, !info->enabled); } else { error = disable_rule(info->id); if (error != CONTEXT_TRIGGER_ERROR_NONE) elm_check_state_set(obj, !info->enabled); } } static void view_create_error_popup(void *data) { rule_data_s *info = (rule_data_s *) data; char *err_msg = NULL; switch (info->result) { case CONTEXT_TRIGGER_ERROR_PERMISSION_DENIED: err_msg = ERR_MSG_PERMISSION_DENIED; break; case CONTEXT_TRIGGER_ERROR_NOT_SUPPORTED: err_msg = ERR_MSG_NOT_SUPPORTED; break; case CONTEXT_TRIGGER_ERROR_INVALID_RULE: err_msg = ERR_MSG_INVALID_RULE; break; default: err_msg = ERR_MSG_DEFAULT; break; } Evas_Object *popup = elm_popup_add(s_info.win); elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0); eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, eext_popup_back_cb, NULL); elm_object_part_text_set(popup, "title,text", info->name); elm_object_text_set(popup, err_msg); Evas_Object *btn = elm_button_add(popup); elm_object_style_set(btn, "popup"); elm_object_text_set(btn, "OK"); elm_object_part_content_set(popup, "button1", btn); evas_object_smart_callback_add(btn, "clicked", popup_btn_clicked_cb, popup); evas_object_show(popup); }