Data Control: Exchanging Specific Data Between Applications
This tutorial demonstrates how you can get, set, add, and remove map data, and insert, select, update, and delete SQL data.
Warm-up
Become familiar with the Data Control API basics by learning about:
-
Initializing Data Controls
Initialize data controls for use.
-
Working with Map-type Data Controls
Work with Map-type data controls.
-
Working with SQL-type Data Controls
Work with SQL-type data controls.
Initializing Data Controls
To use the functions and data types of the Data Control API (in mobile and wearable applications), include the <data_control.h> header file in your application:
#include <data_control.h> #include <sqlite3.h> #include <stdlib.h> #include <glib.h> #include <string.h>
To execute this application, the <sqlite3.h>, <stdlib.h>, <glib.h>, and <string.h> header files have to be included too.
This data control use cases run 2 applications. Each application plays a different role: one for the consumer, the other for the provider. For the consumer application, the http://tizen.org/privilege/datasharing and http://tizen.org/privilege/appmanager.launch privileges must be added. For the provider application, in the IDE, go to tizen-manifest.xml > Advanced > Data Control > Add (Read, Write SQL and Read, Write Map) access rights.
Working with Map-type Data Controls
To get, add, remove, and set map-type data using the Data Control API:
- Implement the provider application.
The provider application stores and provides data to the consumer application.
The provider application has 4 operations: get, add, remove, and set. To use the map-type Data Control API, these 4 operation callbacks must be implemented.
typedef struct map_data { char **str_arr; int arr_size; } map_data_s; static GHashTable *map_repository_test; void get_value_request_cb(int request_id, data_control_h provider, const char *key, void *user_data) { map_data_s* map_data = (map_data_s*)g_hash_table_lookup(map_repository_test, key); int ret_value_count = 0; char **val_arr = NULL; if (map_data != NULL) { val_arr = map_data->str_arr; ret_value_count = map_data->arr_size; } int ret = data_control_provider_send_map_get_value_result(request_id, val_arr, ret_value_count); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "send_map_get_result failed with error: %d", ret); } else { dlog_print(DLOG_INFO, LOG_TAG, "Get value success request_id : %d", request_id); } } void set_value_request_cb(int request_id, data_control_h provider, const char *key, const char *old_value, const char *new_value, void *user_data) { map_data_s* map_data = (map_data_s*)g_hash_table_lookup(map_repository_test, key); if (map_data != NULL) { for (int i = 0; i<map_data->arr_size; i++) { if (strcmp(map_data->str_arr[i], old_value) == 0) { map_data->str_arr[i] = g_strdup(new_value); } } } int ret = data_control_provider_send_map_result(request_id); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "send_map_result failed with error: %d", ret); } else { dlog_print(DLOG_INFO, LOG_TAG, "Set value success request_id : %d", request_id); } } void add_value_request_cb(int request_id, data_control_h provider, const char *key, const char *value, void *user_data) { map_data_s* map_data = (map_data_s*)g_hash_table_lookup(map_repository_test, key); if (map_data == NULL) { map_data = (map_data_s*)(g_malloc(sizeof(*map_data))); map_data->arr_size = 0; map_data->str_arr = (char**) calloc(1, sizeof(char*)); map_data->str_arr[0] = g_strdup(value); g_hash_table_insert(map_repository_test, g_strdup(key), map_data); } else { char **new_arr = (char**) calloc(map_data->arr_size+2, sizeof(char*)); for (int i=0; i<map_data->arr_size; i++) { new_arr[i] = g_strdup(map_data->str_arr[i]); } free(map_data->str_arr); new_arr[map_data->arr_size] = g_strdup(value); map_data->str_arr = g_strdupv(new_arr); free(new_arr); } map_data->arr_size+=1; int ret = data_control_provider_send_map_result(request_id); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "send_map_result failed with error: %d", ret); } else { dlog_print(DLOG_INFO, LOG_TAG, "Add value success request_id : %d %d %s", request_id, map_data->arr_size, map_data->str_arr[0]); } } void remove_value_request_cb(int request_id, data_control_h provider, const char *key, const char *value, void *user_data) { map_data_s* map_data = (map_data_s*)g_hash_table_lookup(map_repository_test, key); if (map_data != NULL) { int size = map_data->arr_size; for (int i = 0; i<size ;i++) { if (strcmp(map_data->str_arr[i], value) == 0) { free(map_data->str_arr[i]); map_data->arr_size--; } } if (map_data->arr_size == 0) { if (!g_hash_table_remove(map_repository_test, key)) { dlog_print(DLOG_ERROR, LOG_TAG, "remove value fail -%s", key); return; } } } int ret = data_control_provider_send_map_result(request_id); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "send_map_result failed with error: %d", ret); } else { dlog_print(DLOG_INFO, LOG_TAG, "Remove value Success"); } }
Register the callback within the app_create(void *data) function using the data_control_provider_map_register_cb() function:
void __free_key(gpointer data) { if (data) { g_free(data); data = NULL; dlog_print(DLOG_INFO, LOG_TAG, "Remove key"); } } void __free_data(gpointer data) { if (data) { g_free(data); data = NULL; dlog_print(DLOG_INFO, LOG_TAG, "Remove value"); } } data_control_provider_map_cb map_callback; void initialize_datacontrol_provider() { map_repository_test = g_hash_table_new_full(g_str_hash, g_str_equal, __free_key, __free_data); map_callback.get_cb = get_value_request_cb; map_callback.add_cb = add_value_request_cb; map_callback.remove_cb = remove_value_request_cb; map_callback.set_cb = set_value_request_cb; int result = data_control_provider_map_register_cb(&map_callback); if (result != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "data_control_provider_map_register_cb failed with error: %d", result); } else { dlog_print(DLOG_INFO, LOG_TAG, "Provider map register success"); } }
- Implement the consumer application.
The consumer application requests get, set, add, and remove functions to the provider application and receives the results from the provider application.
Implement the response callback. The response callback receives the request result and data from the provider.
// Callback functions void map_get_response_cb(int request_id, data_control_h provider, char **ret_value_list, int ret_value_count, bool provider_ret, const char *error, void *user_data) { if (provider_ret) { dlog_print(DLOG_INFO, LOG_TAG, "The get operation is successful. value count : %d ", ret_value_count); for (int i = 0; i<ret_value_count; i++) dlog_print(DLOG_INFO, LOG_TAG, "(%d) Return value : %s ", i , ret_value_list[i]); } else { dlog_print(DLOG_ERROR, LOG_TAG, "The get operation for the request %d is failed. error message: %s", request_id, error); } } void map_set_response_cb(int request_id, data_control_h provider, bool provider_ret, const char *error, void *user_data) { if (provider_ret) { dlog_print(DLOG_INFO, LOG_TAG, "The set operation is successful"); } else { dlog_print(DLOG_ERROR, LOG_TAG, "The set operation for the request %d is failed. error message: %s", request_id, error); } } void map_add_response_cb(int request_id, data_control_h provider, bool provider_ret, const char *error, void *user_data) { if (provider_ret) { dlog_print(DLOG_INFO, LOG_TAG, "The add operation is successful"); } else { dlog_print(DLOG_ERROR, LOG_TAG, "The add operation for the request %d is failed. error message: %s", request_id, error); } } void map_remove_response_cb(int request_id, data_control_h provider, bool provider_ret, const char *error, void *user_data) { if (provider_ret) { dlog_print(DLOG_INFO, LOG_TAG, "The remove operation is successful"); } else { dlog_print(DLOG_ERROR, LOG_TAG, "The remove operation for the request %d is failed. error message: %s", request_id, error); } }
To identify the provider and data, initialize a data control handler. The initializing process has to be performed within the app_create(void *data) function generated by the IDE.
To grant access to the provider ID, go to the provider application tizen-manifest.xml > Advanced > Data Control.
data_control_map_response_cb map_callback; void initialize_datacontrol_consumer(appdata_s *ad) { const char *provider_id = Your Provider ID; const char *data_id = "table"; int ret; // Create data control handler ret = data_control_map_create(&(ad->provider_h)); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "creating data control provider is failed with error: %d", ret); } ret = data_control_map_set_provider_id(ad->provider_h, provider_id); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "setting provider id is failed with error: %d", ret); } ret = data_control_map_set_data_id(ad->provider_h, data_id); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "setting data id is failed with error: %d", ret); } // Set response callback map_callback.get_cb = map_get_response_cb; map_callback.set_cb = map_set_response_cb; map_callback.add_cb = map_add_response_cb; map_callback.remove_cb = map_remove_response_cb; // Register response callback ret = data_control_map_register_response_cb(ad->provider_h, &map_callback, NULL); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "Registering the callback function is failed with error: %d", ret); if (ret == DATA_CONTROL_ERROR_IO_ERROR) { dlog_print(DLOG_ERROR, LOG_TAG, "I/O error"); } else { dlog_print(DLOG_ERROR, LOG_TAG, "Out of memory"); } } int req_id = 0; // Add value const char *key = "key"; const char *value = "value"; data_control_map_add(provider_map, key, value, &req_id); // Get value data_control_map_get(provider_map, key, &req_id); // Set value const char *old_value = "old value"; const char *new_value = "new value"; data_control_map_set(provider_map, key, old_value, new_value, &req_id); // Remove value data_control_map_remove(provider_map, key, value, &req_id); }
Working with SQL-type Data Controls
To insert, select, update, and delete SQL-type data using the Data Control API:
- Implement the provider application.
The provider application stores and provides data to the consumer application.
The provider application has 4 operations: insert, select, update, and delete. To use the SQL-type Data Control API, these operation callbacks have to be implemented.
data_control_provider_sql_cb *sql_callback; static sqlite3* db; void insert_request_cb(int request_id, data_control_h provider, bundle *insert_data, void *user_data) { char* command = data_control_provider_create_insert_statement(provider, insert_data); int ret = sqlite3_exec(db, command, NULL, NULL, NULL); if (ret != SQLITE_OK) { data_control_provider_send_error(request_id, sqlite3_errmsg(db)); free(command); return; } dlog_print(DLOG_INFO, LOG_TAG, "[insert_request_cb] insert success"); long long inserted_row_id = sqlite3_last_insert_rowid(db); ret = data_control_provider_send_insert_result(request_id, inserted_row_id); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "insert_send_result failed with error: %d", ret); } dlog_print(DLOG_INFO, LOG_TAG, "[insert_request_cb] send result success"); free(command); } void delete_request_cb(int request_id, data_control_h provider, const char *where, void *user_data) { dlog_print(DLOG_INFO, LOG_TAG, "[delete_request_cb] request_id(%d)", request_id); char* command = data_control_provider_create_delete_statement(provider, where); int ret = sqlite3_exec(db, command, NULL, NULL, NULL); if (ret != SQLITE_OK) { data_control_provider_send_error(request_id, sqlite3_errmsg(db)); free(command); return; } ret = data_control_provider_send_delete_result(request_id); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "delete_send_result failed with error: %d", ret); } dlog_print(DLOG_INFO, LOG_TAG, "[delete_request_cb] delete success"); free(command); } void select_request_cb(int request_id, data_control_h provider, const char **column_list, int column_count, const char *where, const char *order, void *user_data) { sqlite3_stmt* sql_stmt = NULL; char* command = data_control_provider_create_select_statement(provider, column_list, column_count, where, order); int ret = sqlite3_prepare_v2(db, command, strlen(command), &sql_stmt, NULL); if (ret != SQLITE_OK) { data_control_provider_send_error(request_id, sqlite3_errmsg(db)); free(command); return; } ret = data_control_provider_send_select_result(request_id, (void *)sql_stmt); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "select_send_result failed with error: %d", ret); } dlog_print(DLOG_INFO, LOG_TAG, "[select_request_cb] send result success"); sqlite3_finalize(sql_stmt); free(command); } void update_request_cb(int request_id, data_control_h provider, bundle *update_data, const char *where, void *user_data) { char* command = data_control_provider_create_update_statement(provider, update_data, where); int ret = sqlite3_exec(db, command, NULL, NULL, NULL); if (ret != SQLITE_OK) { data_control_provider_send_error(request_id, sqlite3_errmsg(db)); free(command); return; } ret = data_control_provider_send_update_result(request_id); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "update_send_result failed with error: %d", ret); } dlog_print(DLOG_INFO, LOG_TAG, "[update_request_cb] send result success"); free(command); }
Register the callback and create the database:
int create_database() { dlog_print(DLOG_INFO, LOG_TAG, "%s%s", app_get_data_path(), "test.db"); int open_flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); int ret = sqlite3_open_v2(Your DB Path , &db, open_flags, NULL); if (ret != SQLITE_OK) { dlog_print(DLOG_ERROR, LOG_TAG, "database creation failed with error: %d", ret); return ret; } char* sql_command = "CREATE TABLE IF NOT EXISTS Dictionary (WORD VARCHAR(30) , WORD_DESC TEXT, WORD_NUM INT, Point INT)"; ret = sqlite3_exec(db, sql_command, NULL, NULL, NULL); if (ret != SQLITE_OK) { dlog_print(DLOG_ERROR, LOG_TAG,"database table creation failed with error: %d", ret); } dlog_print(DLOG_INFO, LOG_TAG,"DB init Success."); return ret; } void initialize_datacontrol_provider() { dlog_print(DLOG_INFO, LOG_TAG, "initialize_datacontrol_provider "); int result = create_database(); if (result != SQLITE_OK) return; sql_callback = (data_control_provider_sql_cb *) malloc(sizeof(data_control_provider_sql_cb)); sql_callback->select_cb = select_request_cb; sql_callback->insert_cb = insert_request_cb; sql_callback->delete_cb = delete_request_cb; sql_callback->update_cb = update_request_cb; result = data_control_provider_sql_register_cb(sql_callback, NULL); if (result != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, "data_control_sql_response_c failed with error: %d", result); } else { dlog_print(DLOG_INFO, LOG_TAG, "Provider SQL register success"); } }
- Implement the consumer application.
The consumer application requests the insert, select, update, and delete functions to the provider application and receives the result from the provider application.
Implement the response callback. The response callback receives the request result and data from the provider.
void sql_delete_response_cb(int request_id, data_control_h provider, bool provider_result, const char *error, void *user_data) { if (provider_result) { dlog_print(DLOG_INFO, LOG_TAG, "The delete operation is successful"); } else { dlog_print(DLOG_ERROR, LOG_TAG, "The delete operation for the request %d is failed. error message: %s", request_id, error); } } void sql_insert_response_cb(int request_id, data_control_h provider, long long inserted_row_id, bool provider_result, const char *error, void *user_data) { if (provider_result) { dlog_print(DLOG_INFO, LOG_TAG, "The insert operation is successful"); } else { dlog_print(DLOG_ERROR, LOG_TAG, "The insert operation for the request %d is failed. error message: %s", request_id, error); } } void sql_select_response_cb(int request_id, data_control_h provider, result_set_cursor cursor, bool provider_result, const char *error, void *user_data) { if (provider_result) { dlog_print(DLOG_INFO, LOG_TAG, "The select operation is successful"); } else { dlog_print(DLOG_ERROR, LOG_TAG, "The select operation for the request %d is failed. error message: %s", request_id, error); } while (data_control_sql_step_next(cursor) == DATA_CONTROL_ERROR_NONE) { char word[32] = {0,}; char word_desc[32] = {0,}; long long word_number = -1; data_control_sql_get_text_data(cursor, 0, word); data_control_sql_get_text_data(cursor, 1, word_desc); data_control_sql_get_int64_data(cursor, 2, &word_number); dlog_print(DLOG_INFO, LOG_TAG, "Word : %s, Word DESC : %s, Word NUM : %ld ", word, word_desc, word_number); } } void sql_update_response_cb(int request_id, data_control_h provider, bool provider_result, const char *error, void *user_data) { if (provider_result) { dlog_print(DLOG_INFO, LOG_TAG, "The update operation is successful"); } else { dlog_print(DLOG_ERROR, LOG_TAG, "The update operation for the request %d is failed. error message: %s", request_id, error); } }
To identify the provider and data, initialize a data control handler. The initializing process has to be performed within the app_create(void *data) function generated by the IDE.
To grant access to the provider ID, go to the provider application tizen-manifest.xml > Advanced > Data Control.
data_control_sql_response_cb sql_callback; void initialize_datacontrol_consumer(appdata_s *ad) { int ret; const char *provider_id = Your Provider ID; const char *data_id = "Dictionary"; ret = data_control_sql_create(&(ad->provider_h)); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "creating data control provider is failed with error: %d", ret); } ret = data_control_sql_set_provider_id(ad->provider_h, provider_id); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "setting provider id is failed with error: %d", ret); } ret = data_control_sql_set_data_id(ad->provider_h, data_id); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "setting data id is failed with error: %d", ret); } sql_callback.delete_cb = sql_delete_response_cb; sql_callback.insert_cb = sql_insert_response_cb; sql_callback.select_cb = sql_select_response_cb; sql_callback.update_cb = sql_update_response_cb; ret = data_control_sql_register_response_cb(ad->provider_h, &sql_callback, NULL); if (ret != DATA_CONTROL_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "Registering the callback function is failed with error: %d", ret); } dlog_print(DLOG_INFO, LOG_TAG, "Init data control success"); int req_id = 0; // Insert row bundle *b = bundle_create(); bundle_add_str(b, "WORD", "'test'"); bundle_add_str(b, "WORD_DESC", "'test desc'"); data_control_sql_insert(provider_sql, b, &req_id); // Select row char *column_list[2]; column_list[0] = "WORD"; column_list[1] = "WORD_DESC"; const char *where = "WORD = 'test'"; const char *order = "WORD ASC"; data_control_sql_select(provider_sql, column_list, 2, where, order, &req_id); // Select row bundle_add_str(b, "WORD", "'test_new'"); data_control_sql_update(provider_sql, b, where, &req_id); // Delete row const char *where_delete = "WORD = 'test'"; result = data_control_sql_delete(provider_sql, where_delete, &req_id); // Free memory bundle_free(b); } static bool app_create(void *data) { // Take necessary actions before main event loop starts // Initialize UI resources and application data // If this function returns true, the main loop of application starts // If this function returns false, the application is terminated appdata_s *ad = data; create_base_gui(ad); initialize_datacontrol_consumer(ad); return true; }