Context Trigger Sample Overview

Mobile native

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

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:

  1. 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;
    }
    
  2. 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:

  1. 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);
    
  2. 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);
    }
    
  3. 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;
    }
    
  4. 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);
    }