Add data-control data changed notification feature 02/61702/34 accepted/tizen/common/20160526.145807 accepted/tizen/ivi/20160523.103111 accepted/tizen/mobile/20160523.103115 accepted/tizen/tv/20160523.103029 accepted/tizen/wearable/20160523.103107 submit/tizen/20160523.082558
authorHyunho Kang <hhstark.kang@samsung.com>
Thu, 21 Apr 2016 08:46:18 +0000 (17:46 +0900)
committerHyunho Kang <hhstark.kang@samsung.com>
Mon, 23 May 2016 07:40:00 +0000 (00:40 -0700)
Change-Id: Ifffe22f5f1312e84f73cb7f5f80257541d879904
Signed-off-by: Hyunho Kang <hhstark.kang@samsung.com>
18 files changed:
CMakeLists.txt
data-control.conf.in [new file with mode: 0644]
doc/data_control_doc.h
include/data-control-noti.h [new file with mode: 0644]
include/data-control-provider.h
include/data-control-types.h
include/data_control_noti.h [new file with mode: 0644]
include/data_control_provider.h
include/data_control_types.h
packaging/data-control.spec
src/data-control-internal.c
src/data-control-internal.h
src/data-control-map.c
src/data-control-noti.c [new file with mode: 0644]
src/data-control-provider.c
src/data-control-sql.c
src/data_control_noti.c [new file with mode: 0644]
src/data_control_provider.c

index 9718b76e7d00e7499529c57b79d2a7d81fba573e..5a36d03559fef870797a653449aefb3bc608bf6e 100644 (file)
@@ -20,12 +20,14 @@ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -fPIC -Werror -fvisibi
 SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
 
 ADD_LIBRARY (${PROJECT_NAME} SHARED
+       src/data-control-noti.c
        src/data-control-map.c
        src/data-control-sql.c
        src/data-control-sql-cursor.c
        src/data-control-provider.c
        src/data-control-internal.c
        src/data_control_internal.c
+       src/data_control_noti.c
        src/data_control_map.c
        src/data_control_sql.c
        src/data_control_sql_cursor.c
@@ -47,6 +49,9 @@ ADD_CUSTOM_COMMAND(
 
 SET(VERSION ${FULLVER})
 CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.pc @ONLY)
+CONFIGURE_FILE(${PROJECT_NAME}.conf.in ${PROJECT_NAME}.conf @ONLY)
+
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.conf DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/session.d/)
 INSTALL(FILES ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
 CONFIGURE_FILE(capi-${PROJECT_NAME}.pc.in ${CMAKE_SOURCE_DIR}/capi-${PROJECT_NAME}.pc @ONLY)
 INSTALL(FILES ${CMAKE_SOURCE_DIR}/capi-${PROJECT_NAME}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
diff --git a/data-control.conf.in b/data-control.conf.in
new file mode 100644 (file)
index 0000000..c24dd11
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+        "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+       <policy user="user">
+       </policy>
+       <policy context="default">
+               <check receive_type="signal" receive_interface="org.tizen.data_control_service" privilege="http://tizen.org/privilege/datasharing" />
+               <check send_type="signal" send_interface="org.tizen.data_control_service" privilege="http://tizen.org/privilege/datasharing" />
+       </policy>
+</busconfig>
index 025783105501d8c93ff1187c275b01f541188b4e..b51eecaaf89c82ac76ce9af186036363b95f3b20 100755 (executable)
@@ -66,6 +66,7 @@
  *   -  data_control_sql_get_int64_data()
  *   -  data_control_sql_get_double_data()
  *   -  data_control_sql_get_text_data()
+ * Note: All callbacks are called in the main loop context, unless stated otherwise.
  */
 
 /**
@@ -80,6 +81,7 @@
  * The service application providing its own database file must register the provider callback using data_control_provider_sql_register_cb().
  * The service application providing its own registry file or key-value pairs data set must register the provider callback using the data_control_provider_map_register_cb().
  * The service application sends SQL-type or Map-type data control result to the other application, by using methods such as data_control_provider_send_select_result(),data_control_provider_send_insert_result(), data_control_provider_send_update_result(), or data_control_provider_send_delete_result().
+ * Note: All callbacks are called in the main loop context, unless stated otherwise.
  */
 
 
diff --git a/include/data-control-noti.h b/include/data-control-noti.h
new file mode 100644 (file)
index 0000000..93009a9
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _APPFW_DATA_CONTROL_DATA_CHANGE_H_
+#define _APPFW_DATA_CONTROL_DATA_CHANGE_H_
+
+#include <data_control_types.h>
+#include <data_control_noti.h>
+#include <data-control-types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Adds data changed callback which called when provider's data is changed.
+ * @param [in] provider                Target provider handle
+ * @param [in] callback                The callback function to be called when consumer receive data changed notification
+ * @param [in] user_data               The user data to be passed to the callback function
+ * @param [in] result_callback         The callback function to be called when consumer receive add data changed callback process result
+ * @param [in] result_cb_user_data     The user data to be passed to the result_callback function
+ * @param [out]        callback_id             Added callback ID
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #DATACONTROL_ERROR_NONE          Successful
+ * @retval #DATACONTROL_ERROR_IO_ERROR      I/O error
+ * @retval #DATACONTROL_ERROR_OUT_OF_MEMORY Out of memory
+ */
+EXPORT_API int datacontrol_add_data_change_cb(datacontrol_h provider,
+               data_control_data_change_cb callback,
+               void *user_data,
+               data_control_add_callback_result_cb result_callback,
+               void *result_cb_user_data,
+               int *callback_id);
+
+/**
+ * @brief Removes the data changed callback function.
+ * @param [in] provider        Target provider handle
+ * @param [in] callback_id     Target callback ID
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #DATACONTROL_ERROR_NONE          Successful
+ * @retval #DATACONTROL_ERROR_IO_ERROR      I/O error
+ * @retval #DATACONTROL_ERROR_OUT_OF_MEMORY Out of memory
+ */
+EXPORT_API int datacontrol_remove_data_change_cb(datacontrol_h provider, int callback_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _APPFW_DATA_CONTROL_DATA_CHANGE_H__ */
index 957627d3924a92be90131e9976b88daccbbac312..e3b3416c2229d039085c74cb1af586dfbe93ab5c 100644 (file)
 #define _APPFW_DATA_CONTROL_PROVIDER_H_
 
 #include <data-control-types.h>
+#include <data_control_types.h>
+#include <data_control_provider.h>
 #include <data-control-sql-cursor.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-
 /**
  * @brief      Called when the insert request is received from an application using SQL-friendly interface based data control.
  *
@@ -280,6 +281,69 @@ EXPORT_API int datacontrol_provider_send_map_result(int request_id);
  */
 EXPORT_API int datacontrol_provider_send_map_get_value_result(int request_id, char **value_list, int value_count);
 
+/**
+ * @brief  Send data changed notification to consumer apps which are successfully add data changed callback.
+ * @param[in]  provider                Target provider handle
+ * @param[in]  type            Changed data type
+ * @param[in]  data            Customized data, intend to contains information about changed data
+ *
+ * @return  @c 0 on success,
+ *          otherwise a negative error value
+ *
+ * @retval #DATACONTROL_ERROR_NONE              Successful
+ * @retval #DATACONTROL_ERROR_IO_ERROR          I/O error
+ */
+EXPORT_API int datacontrol_provider_send_data_change_noti(
+               datacontrol_h provider,
+               datacontrol_data_change_type_e type,
+               bundle *data);
+
+/**
+ * @brief  Add consumer filter for add data changed callback process.
+ * @param[in]  callback        Consumer        filter callback filtering consumers which try to add data changed callback
+ * @param[in]  user_data               The user data to be passed to the list_cb function
+ * @param[out]  callback_id            Added callback ID
+ *
+ * @return  @c 0 on success,
+ *          otherwise a negative error value
+ *
+ * @retval #DATACONTROL_ERROR_NONE              Successful
+ * @retval #DATACONTROL_ERROR_IO_ERROR          I/O error
+ */
+EXPORT_API int datacontrol_provider_add_data_change_consumer_filter_cb(
+               data_control_provider_data_change_consumer_filter_cb callback,
+               void *user_data,
+               int *callback_id);
+
+/**
+ * @brief  Remove consumer filter for add data changed callback process.
+ * @param[in]  callback_id     Target callback ID
+ *
+ * @return  @c 0 on success,
+ *          otherwise a negative error value
+ *
+ * @retval #DATACONTROL_ERROR_NONE              Successful
+ * @retval #DATACONTROL_ERROR_IO_ERROR          I/O error
+ */
+EXPORT_API int datacontrol_provider_remove_data_change_consumer_filter_cb(int callback_id);
+
+/**
+ * @brief  Get consumer list which successfully add data changed callback.
+ * @param[in]  provider         The provider handle
+ * @param[in]  list_cb          Callback for each consumer info
+ * @param[in]  user_data        The user data to be passed to the list_cb function
+ *
+ * @return  @c 0 on success,
+ *          otherwise a negative error value
+ *
+ * @retval #DATACONTROL_ERROR_NONE              Successful
+ * @retval #DATACONTROL_ERROR_IO_ERROR          I/O error
+ */
+EXPORT_API int datacontrol_provider_foreach_data_change_consumer(
+               datacontrol_h provider,
+               void *list_cb,
+               void *user_data);
+
 #ifdef __cplusplus
 }
 #endif
index a59e6239f4854d462c328179b7c704049108d35d..b2947996520733126bde4f6567ac4a945415a90d 100644 (file)
@@ -61,5 +61,42 @@ typedef enum {
        DATACONTROL_ERROR_MAX_EXCEEDED  = -EMSGSIZE /**< Too long argument */
 } datacontrol_error_e;
 
+/**
+ * @brief Enumerations of different type of data control requests.
+ */
+typedef enum
+{
+       DATACONTROL_TYPE_ERROR = -1,
+       DATACONTROL_TYPE_UNDEFINED,
+       DATACONTROL_TYPE_SQL_SELECT,
+       DATACONTROL_TYPE_SQL_INSERT,
+       DATACONTROL_TYPE_SQL_UPDATE,
+       DATACONTROL_TYPE_SQL_DELETE,
+       DATACONTROL_TYPE_MAP_GET,
+       DATACONTROL_TYPE_MAP_SET,
+       DATACONTROL_TYPE_MAP_ADD,
+       DATACONTROL_TYPE_MAP_REMOVE,
+       DATACONTROL_TYPE_ADD_DATA_CHANGED_CB,
+       DATACONTROL_TYPE_REMOVE_DATA_CHANGED_CB,
+       DATACONTROL_TYPE_MAX = 255
+} datacontrol_request_type;
+
+
+/**
+ * @brief Enumerations of the various datacontrol noti type.
+ */
+typedef enum {
+       DATACONTROL_DATA_CHANGE_SQL_UPDATE,
+       DATACONTROL_DATA_CHANGE_SQL_INSERT,
+       DATACONTROL_DATA_CHANGE_SQL_DELETE,
+       DATACONTROL_DATA_CHANGE_MAP_SET,
+       DATACONTROL_DATA_CHANGE_MAP_ADD,
+       DATACONTROL_DATA_CHANGE_MAP_REMOVE,
+       DATACONTROL_DATA_CHANGE_CALLBACK_ADD_RESULT,
+       DATACONTROL_DATA_CHANGE_CALLBACK_REMOVE_RESULT
+} datacontrol_data_change_type_e;
+
+typedef struct datacontrol_s *datacontrol_h;
+
 #endif /* _APPFW_DATA_CONTROL_TYPES_H_ */
 
diff --git a/include/data_control_noti.h b/include/data_control_noti.h
new file mode 100644 (file)
index 0000000..564b247
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2013 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_APPFW_DATA_CONTROL_NOTI_H__
+#define __TIZEN_APPFW_DATA_CONTROL_NOTI_H__
+
+#include <data_control_types.h>
+#include <bundle.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file       data_control_noti.h
+ * @brief      This is the header file for data change notifications of the Data Control module. \n
+ *             All callbacks are called in the main loop context, unless stated otherwise.
+ */
+
+/**
+ * @addtogroup CAPI_DATA_CONTROL_CONSUMER_MODULE
+ * @{
+ */
+
+
+/**
+ * @brief  Called when received data changed notification from provider application.
+ * @since_tizen 3.0
+ *
+ * @param[in]  provider                The provider handle. @a provider is valid only inside this function. \n
+ *                             @a provider should not be freed.
+ * @param[in]  type            Changed data type.
+ * @param[in]  data            Data from provider, intended to contain information about changed data \n
+ *                             @a data is valid only inside this function. \n
+ *                             To use outside the callback, make a copy. @a data should not be freed.
+ * @param[in]  user_data       The user data passed from the add function.
+ *
+ * @pre The callback must be registered using data_control_add_data_change_cb(). \n
+ *     data_control_provider_send_data_change_noti() must be called to invoke this callback.
+ *
+ * @see  data_control_add_data_change_cb()
+ * @see         data_control_provider_send_data_change_noti()
+ */
+typedef void (*data_control_data_change_cb) (
+               data_control_h provider,
+               data_control_data_change_type_e type,
+               bundle *data,
+               void *user_data);
+
+/**
+ * @brief  Called when the consumer receives the result of the data change callback adding operation.
+ * @details The following error codes can be delivered. \n
+ *                     #DATA_CONTROL_ERROR_NONE, \n
+ *                     #DATA_CONTROL_ERROR_OUT_OF_MEMORY, \n
+ *                     #DATA_CONTROL_ERROR_IO_ERROR, \n
+ *                     #DATA_CONTROL_ERROR_PERMISSION_DENIED, \n
+ *                     #DATA_CONTROL_ERROR_MAX_EXCEEDED
+ *
+ * @since_tizen 3.0
+ *
+ * @remarks DATA_CONTROL_ERROR_PERMISSION_DENIED will be returned when the provider denies to add the callback.
+ *
+ * @param[in]  provider                The provider handle. @a provider is valid only inside this function. \n
+ *                             @a provider should not be freed.
+ * @param[in]  result                  Add data changed callback result.
+ * @param[in]  callback_id     Added callback ID.
+ * @param[in]  user_data       The user data passed from the add function.
+ *
+ * @pre  The callback must be registered using data_control_add_data_change_cb().
+ *
+ * @see  data_control_add_data_change_cb()
+ */
+typedef void (*data_control_add_callback_result_cb) (
+               data_control_h provider,
+               data_control_error_e result,
+               int callback_id,
+               void *user_data);
+
+/**
+ * @brief      Asynchronously adds a data changed callback which is called whenever the provider's data is changed.
+ * @details    The function attempts to add the callback asynchronously and calls result_callback to inform about the result of the attempt. \n
+ *             If the function is successful, result_callback will be called. \n
+ *             The provider will call any filters which were added for the callback addition process.
+ * @since_tizen 3.0
+ * @privlevel   public
+ * @privilege   %http://tizen.org/privilege/datasharing \n
+ *              %http://tizen.org/privilege/appmanager.launch
+ *
+ * @remarks If you want to use this function, you must add privileges.
+ *
+ * @param [in] provider                Target provider handle
+ * @param [in] callback                The callback function to be called when consumer receive data changed notification
+ * @param [in] user_data               The user data to be passed to the callback function
+ * @param [in] result_callback         The callback function to be called when consumer receive add data changed callback process result
+ * @param [in] result_cb_user_data     The user data to be passed to the result_callback function
+ * @param [out]        callback_id             Added callback ID, it can be used to remove the callback
+ *
+ * @return  @c 0 on success,
+ *          otherwise a negative error value
+ *
+ * @retval #DATA_CONTROL_ERROR_NONE          Successful
+ * @retval #DATA_CONTROL_ERROR_IO_ERROR      I/O error
+ * @retval #DATA_CONTROL_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #DATA_CONTROL_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #DATA_CONTROL_ERROR_PERMISSION_DENIED Permission denied
+ *
+ * @see  data_control_data_change_cb()
+ * @see  data_control_add_callback_result_cb()
+ * @see data_control_provider_add_data_change_consumer_filter_cb()
+ *
+ */
+int data_control_add_data_change_cb(
+               data_control_h provider,
+               data_control_data_change_cb callback,
+               void *user_data,
+               data_control_add_callback_result_cb result_callback,
+               void *result_cb_user_data,
+               int *callback_id);
+
+/**
+ * @brief  Removes data changed callback function.
+ * @since_tizen 3.0
+ * @privlevel   public
+ * @privilege   %http://tizen.org/privilege/datasharing \n
+ *              %http://tizen.org/privilege/appmanager.launch
+ *
+ * @remarks If you want to use this function, you must add privileges.
+ *
+ * @param [in] provider        Target provider handle
+ * @param [in] callback_id     Target callback ID
+ *
+ * @return  @c 0 on success,
+ *          otherwise a negative error value
+ *
+ * @retval #DATA_CONTROL_ERROR_NONE          Successful
+ * @retval #DATA_CONTROL_ERROR_IO_ERROR      I/O error
+ * @retval #DATA_CONTROL_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #DATA_CONTROL_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #DATA_CONTROL_ERROR_PERMISSION_DENIED Permission denied
+ */
+int data_control_remove_data_change_cb(data_control_h provider, int callback_id);
+
+
+/**
+* @}
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TIZEN_APPFW_DATA_CONTROL_NOTI_H__ */
index ccfdf482e639bc12a74076a6a7b15d16c5f33571..1e5dcf7384d48bd17a31f916a0e6d761d4364a47 100644 (file)
@@ -26,8 +26,9 @@ extern "C" {
 #endif
 
 /**
- * @file   data_control_provider.h
- * @brief  This is the header file for the data control provider.
+ * @file       data_control_provider.h
+ * @brief      This is the header file for the data control provider.\n
+ *             All callbacks are called in the main loop context, unless stated otherwise.
  */
 
 /**
@@ -35,6 +36,51 @@ extern "C" {
  * @{
  */
 
+
+/**
+ * @brief  Called for each application which successfully added a data change callback.
+ * @since_tizen 3.0
+ *
+ * @param[in]  provider                 The provider handle. @a provider is valid only inside this function. \n
+ *                                     @a provider should not be freed.
+ * @param[in]  consumer_appid           The id of the consumer application. @a consumer_appid is valid only inside this function. \n
+ *                                     To use outside the callback, make a copy. @a consumer_appid should not be freed.
+ * @param[in]  user_data                The user data.
+ * @return @c true to continue with the next iteration of the loop,
+ *         otherwise @c false to break out of the loop
+ *
+ * @pre  data_control_provider_foreach_data_change_consumer() must be called to invoke this callback.
+ * @see  data_control_provider_foreach_data_change_consumer()
+ */
+typedef bool (*data_control_provider_data_change_consumer_cb)(
+               data_control_h provider,
+               char *consumer_appid,
+               void *user_data);
+
+/**
+ * @brief  Called when a consumer requests a data change callback addition.
+ * @since_tizen 3.0
+ * @details    The callback decides - through the return value - whether a consumer application should be allowed to add a data change callback. \n
+ *             If it returns true, it means the application should be allowed to do so, if it returns false, it means it should be denied.
+ *
+ * @param[in]  provider                 The provider handle. @a provider is valid only inside this function. \n
+ *                                     @a provider should not be freed.
+ * @param[in]  consumer_appid           The id of the consumer application which requested to add the callback. @a consumer_appid is valid only inside this function. \n
+ *                                     To use outside the callback, make a copy. @a consumer_appid should not be freed.
+ * @param[in]  user_data                The user data.
+ * @return  @c A boolean value indicating whether the consumer application should be allowed to add data change callbacks.
+ *
+ * @pre The callback must be registered using data_control_provider_add_data_change_consumer_filter_cb(). \n
+ * data_control_add_data_change_cb() must be called to invoke this callback.
+ *
+ * @see  data_control_provider_add_data_change_consumer_filter_cb()
+ * @see  data_control_provider_remove_data_change_consumer_filter_cb()
+ */
+typedef bool (*data_control_provider_data_change_consumer_filter_cb)(
+               data_control_h provider,
+               char *consumer_appid,
+               void *user_data);
+
 /**
  * @brief  Called when the insert request is received from an application using SQL-friendly interface based data control.
  * @since_tizen 2.3
@@ -464,6 +510,96 @@ bool data_control_provider_match_provider_id(data_control_h provider, const char
  */
 bool data_control_provider_match_data_id(data_control_h provider, const char *data_id);
 
+/**
+ * @brief  Sends a data change notification to consumer applications which have successfully added a data change callback.
+ * @details If the function is successful, data_control_data_change_cb() callback will be called under certain conditions.
+ * @since_tizen 3.0
+ * @privlevel   public
+ * @privilege   %http://tizen.org/privilege/datasharing
+ *
+ * @param[in]  provider                Target provider handle
+ * @param[in]  type            Changed data type
+ * @param[in]  data            Customized information about changed data
+ *
+ * @return  @c 0 on success,
+ *          otherwise a negative error value
+ *
+ * @retval #DATA_CONTROL_ERROR_NONE              Successful
+ * @retval #DATA_CONTROL_ERROR_IO_ERROR          I/O error
+ * @retval #DATA_CONTROL_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #DATA_CONTROL_ERROR_PERMISSION_DENIED Permission denied
+ *
+ * @pre  The consumer should call data_control_add_data_change_cb() to receive data change notifications,
+ * @see  data_control_data_change_cb()
+ * @see  data_control_add_data_change_cb()
+ */
+int data_control_provider_send_data_change_noti(
+               data_control_h provider,
+               data_control_data_change_type_e type,
+               bundle *data);
+
+/**
+ * @brief  Adds a consumer filter for the data changed callback addition process.
+ * @since_tizen 3.0
+ * @remarks    If the provider does not add any filters by calling this function, all requests to add a data change callback will be granted. \n
+ *             If filters are added, and at least one filter returns false for a consumer application, the application will not be able to add data change callbacks.
+ *
+ * @param[in]  callback                Consumer filter callback, filtering consumers which try to add data changed callback
+ * @param[in]  user_data       The user data to be passed to the list_cb function
+ * @param[out] callback_id     Added callback ID
+ *
+ * @return  @c 0 on success,
+ *          otherwise a negative error value
+ *
+ * @retval #DATA_CONTROL_ERROR_NONE              Successful
+ * @retval #DATA_CONTROL_ERROR_IO_ERROR          I/O error
+ * @retval #DATA_CONTROL_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see  data_control_provider_data_change_consumer_filter_cb()
+ */
+int data_control_provider_add_data_change_consumer_filter_cb(
+               data_control_provider_data_change_consumer_filter_cb callback,
+               void *user_data,
+               int *callback_id);
+
+/**
+ * @brief  Removes a consumer filter for the data changed callback addition process.
+ * @since_tizen 3.0
+ *
+ * @param[in]  callback_id     Target callback ID
+ *
+ * @return  @c 0 on success,
+ *          otherwise a negative error value
+ *
+ * @retval #DATA_CONTROL_ERROR_NONE              Successful
+ * @retval #DATA_CONTROL_ERROR_IO_ERROR          I/O error
+ * @retval #DATA_CONTROL_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int data_control_provider_remove_data_change_consumer_filter_cb(int callback_id);
+
+/**
+ * @brief  Retrieves ids of all applications which receive data change notifications from a given provider.
+ * @since_tizen 3.0
+ * @details    This function calls data_control_provider_data_change_consumer_cb() once for each provider's notification target consumer id. \n
+ *             If the data_control_provider_data_change_consumer_cb() callback function returns @c false, then iteration will be finished.
+ *
+ * @param[in]  provider  Target provider handle
+ * @param[in]  list_cb   The iteration callback function
+ * @param[in]  user_data The user data to be passed to the list_cb function
+ *
+ * @return  @c 0 on success,
+ *          otherwise a negative error value
+ *
+ * @retval #DATA_CONTROL_ERROR_NONE              Successful
+ * @retval #DATA_CONTROL_ERROR_IO_ERROR          I/O error
+ * @retval #DATA_CONTROL_ERROR_INVALID_PARAMETER Invalid parameter
+ * @post This function invokes data_control_provider_data_change_consumer_cb().
+ * @see  data_control_provider_data_change_consumer_cb()
+ */
+int data_control_provider_foreach_data_change_consumer(
+               data_control_h provider,
+               data_control_provider_data_change_consumer_cb list_cb,
+               void *user_data);
+
 /**
 * @}
 */
index 63545b85da7d8d9bb38e3210ce8da567f5bd7051..3c4c61f3a96957dadd505e72cfd964cb0f28e3e6 100644 (file)
@@ -61,6 +61,19 @@ typedef enum {
        DATA_CONTROL_ERROR_MAX_EXCEEDED  = TIZEN_ERROR_DATA_CONTROL | 0x01    /**< Too long argument */
 } data_control_error_e;
 
+/**
+ * @brief Enumeration for the various data changed notification types.
+ * @since_tizen 3.0
+ */
+typedef enum {
+       DATA_CONTROL_DATA_CHANGE_SQL_UPDATE,      /**< Update notification */
+       DATA_CONTROL_DATA_CHANGE_SQL_INSERT,      /**< Insert notification */
+       DATA_CONTROL_DATA_CHANGE_SQL_DELETE,      /**< Delete notification */
+       DATA_CONTROL_DATA_CHANGE_MAP_SET,         /**< Set notification */
+       DATA_CONTROL_DATA_CHANGE_MAP_ADD,         /**< Add notification */
+       DATA_CONTROL_DATA_CHANGE_MAP_REMOVE       /**< Remove notification */
+} data_control_data_change_type_e;
+
 /**
 * @}
 */
index e8a7cee7e28dd9659fc62ed4f61e7cf836cc8e36..6dd85d236de4b3c8d5df48336042b55635b28216 100644 (file)
@@ -62,6 +62,8 @@ install LICENSE.APLv2  %{buildroot}/usr/share/license/%{name}
 %files
 %{_libdir}/lib%{name}.so.*
 %{_libdir}/libcapi-data-control.so.*
+%config %{_sysconfdir}/dbus-1/session.d/data-control.conf
+
 %manifest %{name}.manifest
 /usr/share/license/%{name}
 
index b9f6a9e0bd6182c20b6bffb7d88de3395d65196d..9d39ec083c88ab80cbd6f91c3145c0af8713986c 100755 (executable)
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <dlog.h>
+#include <sqlite3.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -23,6 +23,9 @@
 #include <glib.h>
 #include <gio/gio.h>
 #include <pthread.h>
+#include <sys/socket.h>
+
+#include <dlog.h>
 #include <appsvc/appsvc.h>
 #include <aul/aul.h>
 
@@ -36,6 +39,7 @@
 
 #include "data-control-sql-cursor.h"
 #include "data-control-internal.h"
+#include "data-control-types.h"
 
 #define MAX_COLUMN_SIZE                                512
 #define MAX_STATEMENT_SIZE                     1024
 
 #define ERR_BUFFER_SIZE         1024
 #define BUFSIZE 512
+#define DATA_CONTROL_DBUS_PATH_PREFIX "/org/tizen/data_control_service_"
+#define DATA_CONTROL_OBJECT_PATH "/org/tizen/data_control_service"
+#define DATA_CONTROL_INTERFACE_NAME "org.tizen.data_control_service"
+#define DATA_CONTROL_DB_NAME_PREFIX "._data_control_list_"
+#define DATA_CONTROL_DB_NAME "DATA_CONTROL_DATA_CHANGE_TABLE"
+
+static GDBusConnection *_gdbus_conn = NULL;
+
+datacontrol_data_change_type_e _get_internal_noti_type(data_control_data_change_type_e type)
+{
+       datacontrol_data_change_type_e ret_type = DATACONTROL_DATA_CHANGE_SQL_UPDATE;
+       switch (type) {
+       case DATA_CONTROL_DATA_CHANGE_SQL_UPDATE:
+               ret_type = DATACONTROL_DATA_CHANGE_SQL_UPDATE;
+               break;
+       case DATA_CONTROL_DATA_CHANGE_SQL_INSERT:
+               ret_type = DATACONTROL_DATA_CHANGE_SQL_INSERT;
+               break;
+       case DATA_CONTROL_DATA_CHANGE_SQL_DELETE:
+               ret_type = DATACONTROL_DATA_CHANGE_SQL_DELETE;
+               break;
+       case DATA_CONTROL_DATA_CHANGE_MAP_SET:
+               ret_type = DATACONTROL_DATA_CHANGE_MAP_SET;
+               break;
+       case DATA_CONTROL_DATA_CHANGE_MAP_ADD:
+               ret_type = DATACONTROL_DATA_CHANGE_MAP_ADD;
+               break;
+       case DATA_CONTROL_DATA_CHANGE_MAP_REMOVE:
+               ret_type = DATACONTROL_DATA_CHANGE_MAP_REMOVE;
+               break;
+       default:
+               LOGE("Invalid noti type");
+               break;
+       }
+       return ret_type;
+}
+
+data_control_data_change_type_e _get_public_noti_type(datacontrol_data_change_type_e type)
+{
+       data_control_data_change_type_e ret_type = DATA_CONTROL_DATA_CHANGE_SQL_UPDATE;
+       switch(type) {
+       case DATACONTROL_DATA_CHANGE_SQL_UPDATE:
+               ret_type = DATA_CONTROL_DATA_CHANGE_SQL_UPDATE;
+               break;
+       case DATACONTROL_DATA_CHANGE_SQL_INSERT:
+               ret_type = DATA_CONTROL_DATA_CHANGE_SQL_INSERT;
+               break;
+       case DATACONTROL_DATA_CHANGE_SQL_DELETE:
+               ret_type = DATA_CONTROL_DATA_CHANGE_SQL_DELETE;
+               break;
+       case DATACONTROL_DATA_CHANGE_MAP_SET:
+               ret_type = DATA_CONTROL_DATA_CHANGE_MAP_SET;
+               break;
+       case DATACONTROL_DATA_CHANGE_MAP_ADD:
+               ret_type = DATA_CONTROL_DATA_CHANGE_MAP_ADD;
+               break;
+       case DATACONTROL_DATA_CHANGE_MAP_REMOVE:
+               ret_type = DATA_CONTROL_DATA_CHANGE_MAP_REMOVE;
+               break;
+       default:
+               LOGE("Invalid noti type");
+               break;
+       }
+       return ret_type;
+}
 
 int _consumer_request_compare_cb(gconstpointer a, gconstpointer b)
 {
@@ -57,6 +126,70 @@ int _consumer_request_compare_cb(gconstpointer a, gconstpointer b)
        return 1;
 }
 
+int _create_datacontrol_h(datacontrol_h *provider)
+{
+       struct datacontrol_s *request;
+
+       if (provider == NULL)
+               return DATACONTROL_ERROR_INVALID_PARAMETER;
+
+       request = malloc(sizeof(struct datacontrol_s));
+       if (request == NULL)
+               return DATACONTROL_ERROR_OUT_OF_MEMORY;
+
+       request->provider_id = NULL;
+       request->data_id = NULL;
+
+       *provider = request;
+
+       return 0;
+}
+
+int _destroy_datacontrol_h(datacontrol_h provider)
+{
+       if (provider == NULL)
+               return DATACONTROL_ERROR_INVALID_PARAMETER;
+
+       if (provider->provider_id != NULL)
+               free(provider->provider_id);
+
+       if (provider->data_id != NULL)
+               free(provider->data_id);
+
+       free(provider);
+       return 0;
+}
+
+int _set_provider_id(datacontrol_h provider, const char *provider_id)
+{
+       if (provider == NULL || provider_id == NULL)
+               return DATACONTROL_ERROR_INVALID_PARAMETER;
+
+       if (provider->provider_id != NULL)
+               free(provider->provider_id);
+
+       provider->provider_id = strdup(provider_id);
+       if (provider->provider_id == NULL)
+               return DATACONTROL_ERROR_OUT_OF_MEMORY;
+
+       return 0;
+}
+
+int _set_data_id(datacontrol_h provider, const char *data_id)
+{
+       if (provider == NULL || data_id == NULL)
+               return DATACONTROL_ERROR_INVALID_PARAMETER;
+
+       if (provider->data_id != NULL)
+               free(provider->data_id);
+
+       provider->data_id = strdup(data_id);
+       if (provider->data_id == NULL)
+               return DATACONTROL_ERROR_OUT_OF_MEMORY;
+
+       return 0;
+}
+
 int _write_socket(int fd, void *buffer, unsigned int nbytes,
                unsigned int *bytes_write)
 {
@@ -158,6 +291,22 @@ int _datacontrol_create_request_id(void)
        return id;
 }
 
+int _datacontrol_get_data_changed_callback_id(void)
+{
+       static int id = 0;
+       g_atomic_int_inc(&id);
+
+       return id;
+}
+
+int _datacontrol_get_data_changed_filter_callback_id(void)
+{
+       static int id = 0;
+       g_atomic_int_inc(&id);
+
+       return id;
+}
+
 void _socket_info_free(gpointer socket)
 {
        datacontrol_socket_info *socket_info = (datacontrol_socket_info *)socket;
@@ -181,8 +330,8 @@ void _socket_info_free(gpointer socket)
 
 }
 
-datacontrol_socket_info *_get_socket_info(const char *caller_id,
-               const char *callee_id, const char *type, GIOFunc cb, void *data)
+datacontrol_socket_info *_add_watch_on_socket_info(const char *caller_id, const char *callee_id, const char *type,
+               GIOFunc cb, void *data)
 {
        char err_buf[ERR_BUFFER_SIZE];
        int socketpair = 0;
@@ -283,3 +432,106 @@ int _request_appsvc_run(const char *caller_id, const char *callee_id)
        return DATACONTROL_ERROR_NONE;
 }
 
+char *_get_encoded_db_path()
+{
+       char db_path[PATH_MAX];
+       char *dup_db_path = NULL;
+       char *encoded_appid = NULL;
+       char provider_appid[255];
+       if (aul_app_get_appid_bypid(getpid(), provider_appid, sizeof(provider_appid)) != 0) {
+               LOGE("Failed to get appid by pid");
+               return NULL;
+       }
+
+       encoded_appid = g_compute_checksum_for_string(G_CHECKSUM_MD5, provider_appid, -1);
+       snprintf(db_path, sizeof(db_path), "/run/user/%d/%s%s.db",
+                       getuid(), DATA_CONTROL_DB_NAME_PREFIX, encoded_appid);
+       dup_db_path = strdup(db_path);
+       if (dup_db_path == NULL)
+               LOGE("fail to dup db path. out of memory.");
+
+       free(encoded_appid);
+       LOGI("dup db path : %s ", dup_db_path);
+       return dup_db_path;
+}
+
+char *_get_encoded_path(datacontrol_h provider, char *consumer_appid)
+{
+       int prefix_len = strlen(DATA_CONTROL_DBUS_PATH_PREFIX);
+       char *encoded_path;
+       char *full_path;
+       int path_len = strlen(provider->provider_id) + strlen(provider->data_id) + strlen(consumer_appid) + 3;
+       int full_path_len = path_len + prefix_len;
+       char *path = (char *)calloc(path_len, sizeof(char));
+       if (path == NULL) {
+               LOGE("path calloc failed");
+               return 0;
+       }
+
+       snprintf(path, path_len, "%s_%s_%s", provider->provider_id, provider->data_id, consumer_appid);
+       encoded_path = g_compute_checksum_for_string(G_CHECKSUM_MD5, path, -1);
+
+       full_path = (char *)calloc(full_path_len, sizeof(char));
+       snprintf(full_path, full_path_len, "%s%s", DATA_CONTROL_DBUS_PATH_PREFIX, encoded_path);
+
+       free(path);
+       free(encoded_path);
+       LOGI("full path : %s ", full_path);
+       return full_path;
+}
+
+int _dbus_init()
+{
+       int ret = DATACONTROL_ERROR_NONE;
+       GError *error = NULL;
+
+       if (_gdbus_conn == NULL) {
+               _gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
+
+               if (_gdbus_conn == NULL) {
+                       if (error != NULL) {
+                               LOGE("Failed to get dbus [%s]", error->message);
+                               g_error_free(error);
+                       }
+                       return DATACONTROL_ERROR_IO_ERROR;
+               }
+               ret = DATACONTROL_ERROR_NONE;
+       }
+       return ret;
+}
+
+GDBusConnection *_get_dbus_connection()
+{
+       int result = _dbus_init();
+       if (result != DATACONTROL_ERROR_NONE) {
+               LOGE("Can't init dbus %d", result);
+               return NULL;
+       }
+       return _gdbus_conn;
+}
+
+int _dbus_signal_init(int *monitor_id, char *path, GDBusSignalCallback callback)
+{
+       int id;
+       id = g_dbus_connection_signal_subscribe(
+                       _get_dbus_connection(),
+                       NULL,
+                       DATA_CONTROL_INTERFACE_NAME,    /*      interface */
+                       NULL,                           /*      member */
+                       path,                           /*      path */
+                       NULL,                           /*      arg0 */
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       callback,
+                       NULL,
+                       NULL);
+
+       LOGI("subscribe id : %d", id);
+       if (id == 0) {
+               return DATACONTROL_ERROR_IO_ERROR;
+               LOGE("Failed to _register_noti_dbus_interface");
+       } else {
+               *monitor_id = id;
+       }
+
+       return DATACONTROL_ERROR_NONE;
+}
index a9be2ae694b7e89e92600720b5a9778465638c58..5483d01bd136dcab4f3cf4ba6756f86367c2aa97 100755 (executable)
@@ -19,6 +19,7 @@
  * @brief      This is the header file for private keys of the data-control.
  */
 #include <gio/gio.h>
+#include "data_control_types.h"
 
 #ifndef _APPFW_DATA_CONTROL_INTERNAL_H_
 #define _APPFW_DATA_CONTROL_INTERNAL_H_
@@ -39,6 +40,8 @@
 #define OSP_K_DATACONTROL_REQUEST_TYPE  "__OSP_DATACONTROL_REQUEST_TYPE__"
 #define OSP_K_DATACONTROL_PROTOCOL_VERSION     "__OSP_DATACONTROL_PROTOCOL_VERSION__"
 #define OSP_K_CALLER_TYPE   "__OSP_CALLER_TYPE__"
+#define OSP_K_DATACONTROL_UNIQUE_NAME  "__OSP_DATACONTROL_UNIQUE_NAME__"
+#define OSP_K_DATA_CHANGED_CALLBACK_ID    "__OSP_DATA_CHANGED_CALLBACK_ID__"
 
 #define DATACONTROL_SELECT_STATEMENT   "DATACONTROL_SELECT_STATEMENT"
 
 /**
  * @brief Enumerations of different type of data control requests.
  */
-typedef enum {
-       DATACONTROL_TYPE_ERROR = -1,
-       DATACONTROL_TYPE_UNDEFINED,
-       DATACONTROL_TYPE_SQL_SELECT,
-       DATACONTROL_TYPE_SQL_INSERT,
-       DATACONTROL_TYPE_SQL_UPDATE,
-       DATACONTROL_TYPE_SQL_DELETE,
-       DATACONTROL_TYPE_MAP_GET,
-       DATACONTROL_TYPE_MAP_SET,
-       DATACONTROL_TYPE_MAP_ADD,
-       DATACONTROL_TYPE_MAP_REMOVE,
-       DATACONTROL_TYPE_MAX = 255
-} datacontrol_request_type;
 
 typedef struct datacontrol_pkt {
        int len;
@@ -87,6 +77,18 @@ typedef struct datacontrol_consumer_request {
        datacontrol_request_type type;
 } datacontrol_consumer_request_info;
 
+typedef struct datacontrol_consumer {
+       int monitor_id;
+       char *appid;
+       char *object_path;
+       char *unique_id;
+} datacontrol_consumer_info;
+
+struct datacontrol_s {
+       char *provider_id;
+       char *data_id;
+};
+
 int _consumer_request_compare_cb(gconstpointer a, gconstpointer b);
 int _datacontrol_sql_set_cursor(const char *path);
 char *_datacontrol_create_select_statement(char *data_id,
@@ -94,21 +96,30 @@ char *_datacontrol_create_select_statement(char *data_id,
                const char *where, const char *order, int page_number,
                int count_per_page);
 int _datacontrol_create_request_id(void);
-int _datacontrol_send_async(int sockfd, bundle *kb,
-               datacontrol_request_type type, void *data);
-int _read_socket(int fd, char *buffer, unsigned int nbytes,
-               unsigned int *bytes_read);
-int _write_socket(int fd, void *buffer, unsigned int nbytes,
-               unsigned int *bytes_write);
-gboolean _datacontrol_recv_message(GIOChannel *channel, GIOCondition cond,
-               gpointer data);
-int _get_gdbus_shared_connection(GDBusConnection **connection,
-               char *provider_id);
+int _datacontrol_get_data_changed_callback_id(void);
+int _datacontrol_get_data_changed_filter_callback_id(void);
+
+int _datacontrol_send_async(int sockfd, bundle *kb, datacontrol_request_type type, void *data);
+int _read_socket(int fd, char *buffer, unsigned int nbytes, unsigned int *bytes_read);
+int _write_socket(int fd, void *buffer, unsigned int nbytes, unsigned int *bytes_write);
+
+gboolean _datacontrol_recv_message(GIOChannel *channel, GIOCondition cond, gpointer data);
+int _get_gdbus_shared_connection(GDBusConnection **connection, char *provider_id);
 void _socket_info_free(gpointer socket);
-datacontrol_socket_info *_get_socket_info(const char *caller_id,
-               const char *callee_id, const char *type, GIOFunc cb,
-               void *data);
+datacontrol_socket_info *_add_watch_on_socket_info(const char *caller_id, const char *callee_id, const char *type, GIOFunc cb, void *data);
 int _request_appsvc_run(const char *caller_id, const char *callee_id);
 
+GDBusConnection *_get_dbus_connection();
+int _dbus_signal_init(int *monitor_id, char *path, GDBusSignalCallback callback);
+char *_get_encoded_path(datacontrol_h provider, char *consumer_appid);
+char *_get_encoded_db_path();
+
+int _create_datacontrol_h(datacontrol_h *provider);
+int _destroy_datacontrol_h(datacontrol_h provider);
+int _set_provider_id(datacontrol_h provider, const char *provider_id);
+int _set_data_id(datacontrol_h provider, const char *data_id);
+datacontrol_data_change_type_e _get_internal_noti_type(data_control_data_change_type_e type);
+data_control_data_change_type_e _get_public_noti_type(datacontrol_data_change_type_e type);
+
 #endif /* _APPFW_DATA_CONTROL_INTERNAL_H_ */
 
index f927fe6cf71e7b54c64712f85ae5cdffb0048a70..70dee948ff58892a08044128bd284be4a588c6bf 100755 (executable)
 #include "data-control-map.h"
 #include "data-control-internal.h"
 
-struct datacontrol_s {
-       char *provider_id;
-       char *data_id;
-};
-
 typedef struct {
        char *provider_id;
        char *app_id;
@@ -549,7 +544,7 @@ static int __map_request_provider(datacontrol_h provider, datacontrol_request_ty
                        if (ret != DATACONTROL_ERROR_NONE)
                                return ret;
 
-                       socket_info = _get_socket_info(caller_app_id, app_id, "consumer", __recv_map_message, data);
+                       socket_info = _add_watch_on_socket_info(caller_app_id, app_id, "consumer", __recv_map_message, data);
                        if (socket_info == NULL)
                                return DATACONTROL_ERROR_IO_ERROR;
 
diff --git a/src/data-control-noti.c b/src/data-control-noti.c
new file mode 100644 (file)
index 0000000..fe8421e
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <search.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <glib.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <gio/gio.h>
+#include <sys/socket.h>
+
+#include <dlog.h>
+#include <appsvc/appsvc.h>
+#include <aul/aul.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <pkgmgr-info.h>
+
+#include "data-control-noti.h"
+#include "data-control-internal.h"
+
+typedef struct {
+       GList *cb_list;
+       char *provider_appid;
+       char *provider_id;
+       char *data_id;
+       int monitor_id;
+} provider_info_s;
+
+typedef struct {
+       void *user_data;
+       int callback_id;
+       data_control_data_change_cb changed_cb;
+} changed_cb_info_s;
+
+typedef struct {
+       void *user_data;
+       int callback_id;
+       char *provider_id;
+       char *data_id;
+       int timeout_id;
+       data_control_add_callback_result_cb callback;
+} add_callback_result_cb_info_s;
+
+static GList *__add_callback_result_cb_list = NULL;
+static GList *__changed_provider_list = NULL;
+
+static int __callback_result_info_compare_cb(gconstpointer a, gconstpointer b)
+{
+       add_callback_result_cb_info_s *key1 =
+               (add_callback_result_cb_info_s *)a;
+       add_callback_result_cb_info_s *key2 =
+               (add_callback_result_cb_info_s *)b;
+
+       return !(key1->callback_id == key2->callback_id);
+}
+
+static int __provider_info_compare_cb(gconstpointer a, gconstpointer b)
+{
+       provider_info_s *key1 = (provider_info_s *)a;
+       provider_info_s *key2 = (provider_info_s *)b;
+       return (strcmp(key1->provider_id, key2->provider_id) || strcmp(key1->data_id, key2->data_id));
+}
+
+static int __changed_cb_info_compare_cb(gconstpointer a, gconstpointer b)
+{
+       changed_cb_info_s *key1 = (changed_cb_info_s *)a;
+       changed_cb_info_s *key2 = (changed_cb_info_s *)b;
+
+       return !(key1->callback_id == key2->callback_id);
+}
+
+static void __free_result_cb_info(
+               add_callback_result_cb_info_s *result_cb_info)
+{
+       if (result_cb_info) {
+               if (result_cb_info->provider_id)
+                       free(result_cb_info->provider_id);
+               if (result_cb_info->data_id)
+                       free(result_cb_info->data_id);
+               if (result_cb_info->timeout_id > 0)
+                       g_source_remove(result_cb_info->timeout_id);
+               free(result_cb_info);
+       }
+}
+
+static void __free_provider_info(
+               provider_info_s *provider_info)
+{
+       if (provider_info) {
+               if (provider_info->provider_appid)
+                       free(provider_info->provider_appid);
+               if (provider_info->provider_id)
+                       free(provider_info->provider_id);
+               if (provider_info->data_id)
+                       free(provider_info->data_id);
+               if (provider_info->monitor_id > 0)
+                       g_dbus_connection_signal_unsubscribe(_get_dbus_connection(), provider_info->monitor_id);
+               g_list_free(provider_info->cb_list);
+               free(provider_info);
+       }
+}
+
+static void __noti_process(GVariant *parameters)
+{
+       char *provider_id = NULL;
+       char *data_id = NULL;
+       bundle_raw *raw = NULL;
+       bundle *noti_data = NULL;
+       int len = 0;
+       datacontrol_h provider = NULL;
+       GList *find_list;
+       changed_cb_info_s *cb_info = NULL;
+       provider_info_s find_info;
+       provider_info_s *provider_info;
+       GList *callback_list = NULL;
+       datacontrol_data_change_type_e type;
+
+       g_variant_get(parameters, "(i&s&s&si)", &type, &provider_id, &data_id, &raw, &len);
+       LOGI("__noti_process : %d %s %s %d", type, provider_id, data_id, len);
+
+       if (provider_id == NULL || data_id == NULL)
+               return;
+
+       find_info.provider_id = provider_id;
+       find_info.data_id = data_id;
+
+       find_list = g_list_find_custom(__changed_provider_list, &find_info,
+                       (GCompareFunc)__provider_info_compare_cb);
+       if (find_list != NULL) {
+               _create_datacontrol_h(&provider);
+               _set_provider_id(provider, provider_id);
+               _set_data_id(provider, data_id);
+               noti_data = bundle_decode(raw, len);
+               provider_info = (provider_info_s *)find_list->data;
+               callback_list = g_list_first(provider_info->cb_list);
+               for (; callback_list != NULL; callback_list = callback_list->next) {
+                       cb_info = callback_list->data;
+                       cb_info->changed_cb((data_control_h)provider, _get_public_noti_type(type), noti_data, cb_info->user_data);
+                       LOGI("callback called: %s, %s", provider_info->provider_id, provider_info->data_id);
+               }
+               bundle_free(noti_data);
+               _destroy_datacontrol_h(provider);
+
+       } else {
+               LOGE("data_control_data_change_cb is null");
+       }
+       LOGI("__noti_process done");
+}
+
+static void __call_result_callback(int callback_id, int callback_result)
+{
+       add_callback_result_cb_info_s *result_cb_info;
+       add_callback_result_cb_info_s find_info;
+       datacontrol_h provider;
+       GList *find_list;
+       find_info.callback_id = callback_id;
+       find_list = g_list_find_custom(__add_callback_result_cb_list, &find_info,
+                       (GCompareFunc)__callback_result_info_compare_cb);
+
+       if (find_list != NULL) {
+               result_cb_info = (add_callback_result_cb_info_s *)find_list->data;
+               _create_datacontrol_h(&provider);
+               _set_provider_id(provider, result_cb_info->provider_id);
+               _set_data_id(provider, result_cb_info->data_id);
+               result_cb_info->callback(
+                               (data_control_h)provider,
+                               callback_result,
+                               callback_id,
+                               result_cb_info->user_data);
+               __add_callback_result_cb_list = g_list_remove_link(__add_callback_result_cb_list, find_list);
+               __free_result_cb_info((add_callback_result_cb_info_s *)find_list->data);
+               _destroy_datacontrol_h(provider);
+       } else {
+               LOGE("add_callback_result_cb_info_s is null");
+       }
+}
+
+static gboolean __add_callback_result_timeout_handler(gpointer user_data)
+{
+       LOGE("add data changed callback time out !!!");
+       add_callback_result_cb_info_s *result_cb_info =
+                       (add_callback_result_cb_info_s *)user_data;
+       __call_result_callback(result_cb_info->callback_id, DATA_CONTROL_ERROR_IO_ERROR);
+       return FALSE;
+}
+
+static void __noti_add_remove_data_changed_cb_result_process(
+               GVariant *parameters)
+{
+       int callback_id;
+       data_control_error_e callback_result;
+       datacontrol_data_change_type_e type;
+
+       g_variant_get(parameters, "(iii)", &type, &callback_id, &callback_result);
+       LOGI("__noti_add_remove_data_changed_cb_result_process: %d %d %d", type, callback_id, callback_result);
+
+       if (type == DATACONTROL_DATA_CHANGE_CALLBACK_ADD_RESULT)
+               __call_result_callback(callback_id, callback_result);
+}
+
+static void __handle_noti(GDBusConnection *connection,
+               const gchar     *sender_name,
+               const gchar     *object_path,
+               const gchar     *interface_name,
+               const gchar     *signal_name,
+               GVariant        *parameters,
+               gpointer         user_data)
+{
+       LOGI("signal_name: %s", signal_name);
+
+       if (g_strcmp0(signal_name, "noti_data_changed") == 0)
+               __noti_process(parameters);
+       else if (g_strcmp0(signal_name, "noti_add_remove_result") == 0)
+               __noti_add_remove_data_changed_cb_result_process(parameters);
+}
+
+static int __noti_request_appsvc_run(const char *callee_id,
+               char *provider_id, char *data_id, const char *unique_id, int callback_id, int request_type)
+{
+       int pid = -1;
+       char callback_id_str[32] = {0,};
+       char request_type_str[MAX_LEN_DATACONTROL_REQ_TYPE] = {0,};
+       bundle *arg_list = bundle_create();
+       if (!arg_list) {
+               LOGE("unable to create bundle: %d", errno);
+               return DATACONTROL_ERROR_OUT_OF_MEMORY;
+       }
+
+       snprintf(callback_id_str, 32, "%d", callback_id);
+       snprintf(request_type_str, MAX_LEN_DATACONTROL_REQ_TYPE, "%d", (int)(request_type));
+
+       appsvc_set_operation(arg_list, APPSVC_OPERATION_DEFAULT);
+       appsvc_set_appid(arg_list, callee_id);
+
+       bundle_add_str(arg_list, OSP_K_DATACONTROL_REQUEST_TYPE, request_type_str);
+       bundle_add_str(arg_list, OSP_K_DATACONTROL_UNIQUE_NAME, unique_id);
+       bundle_add_str(arg_list, OSP_K_DATACONTROL_PROVIDER, provider_id);
+       bundle_add_str(arg_list, OSP_K_DATACONTROL_DATA, data_id);
+       bundle_add_str(arg_list, OSP_K_DATA_CHANGED_CALLBACK_ID, callback_id_str);
+
+       bundle_add_str(arg_list, OSP_K_CALLER_TYPE, OSP_V_CALLER_TYPE_OSP);
+       bundle_add_str(arg_list, OSP_K_LAUNCH_TYPE, OSP_V_LAUNCH_TYPE_DATACONTROL);
+       bundle_add_str(arg_list, AUL_K_CALLEE_APPID, callee_id);
+       bundle_add_str(arg_list, AUL_K_NO_CANCEL, "1");
+       LOGI("callee_id %s", callee_id);
+       LOGI("provider_id %s, data_id %s", provider_id, data_id);
+
+       /* For DataControl CAPI */
+       bundle_add_str(arg_list, AUL_K_DATA_CONTROL_TYPE, "CORE");
+
+       pid = appsvc_run_service(arg_list, 0, NULL, NULL);
+       if (pid >= 0) {
+               LOGI("Launch the provider app successfully: %d", pid);
+               bundle_free(arg_list);
+       } else if (pid == APPSVC_RET_EINVAL) {
+               LOGE("not able to launch service: %d", pid);
+               bundle_free(arg_list);
+               return DATACONTROL_ERROR_INVALID_PARAMETER;
+       } else {
+               LOGE("unable to launch service: %d", pid);
+               return DATACONTROL_ERROR_IO_ERROR;
+       }
+       return DATACONTROL_ERROR_NONE;
+}
+
+int datacontrol_add_data_change_cb(datacontrol_h provider,
+               data_control_data_change_cb callback,
+               void *user_data,
+               data_control_add_callback_result_cb result_callback,
+               void *result_cb_user_data,
+               int *callback_id)
+{
+       int ret = DATACONTROL_ERROR_NONE;
+       changed_cb_info_s *cb_info = NULL;
+       provider_info_s *provider_info = NULL;
+       provider_info_s find_provider_info;
+       int monitor_id = 0;
+       GList *find_list;
+       char *path = NULL;
+       const char *unique_id = NULL;
+       char caller_app_id[255];
+       pid_t pid;
+       add_callback_result_cb_info_s *result_cb_info = NULL;
+       char *provider_app_id = NULL;
+       char *access = NULL;
+
+       LOGI("provider_id : %s, data_id : %s", provider->provider_id, provider->data_id);
+       ret = pkgmgrinfo_appinfo_usr_get_datacontrol_info(provider->provider_id, "Sql", getuid(), &provider_app_id, &access);
+       if (ret != PMINFO_R_OK) {
+               LOGE("unable to get sql data control information, retry with map: %d", ret);
+               ret = pkgmgrinfo_appinfo_usr_get_datacontrol_info(provider->provider_id, "Map", getuid(), &provider_app_id, &access);
+               if (ret != PMINFO_R_OK) {
+                       LOGE("unable to get map data control information: %d", ret);
+                       return DATACONTROL_ERROR_IO_ERROR;
+               }
+       }
+
+       *callback_id = _datacontrol_get_data_changed_callback_id();
+       unique_id = g_dbus_connection_get_unique_name(_get_dbus_connection());
+       LOGI("unique_id : %s, callback_id %d", unique_id, *callback_id);
+
+       find_provider_info.provider_id = provider->provider_id;
+       find_provider_info.data_id = provider->data_id;
+       find_list = g_list_find_custom(__changed_provider_list, &find_provider_info,
+                       (GCompareFunc)__provider_info_compare_cb);
+       if (find_list == NULL) {
+
+               pid = getpid();
+               if (aul_app_get_appid_bypid(pid, caller_app_id, sizeof(caller_app_id)) != 0) {
+                       LOGE("Failed to get appid by pid(%d).", pid);
+                       ret = DATACONTROL_ERROR_INVALID_PARAMETER;
+                       goto err;
+               }
+               path = _get_encoded_path(provider, caller_app_id);
+               if (path == NULL) {
+                       LOGE("cannot get encoded path. out of memory.");
+                       ret = DATACONTROL_ERROR_OUT_OF_MEMORY;
+                       goto err;
+               }
+
+               ret = _dbus_signal_init(&monitor_id, path, __handle_noti);
+               if (ret != DATACONTROL_ERROR_NONE) {
+                       LOGE("fail to init dbus signal.");
+                       ret = DATACONTROL_ERROR_IO_ERROR;
+                       goto err;
+               }
+
+               provider_info = (provider_info_s *)calloc(1, sizeof(provider_info_s));
+               if (provider_info == NULL) {
+                       LOGE("provider_info_s alloc fail out of memory.");
+                       ret = DATACONTROL_ERROR_OUT_OF_MEMORY;
+                       goto err;
+               }
+               provider_info->provider_appid = strdup(provider_app_id);
+               provider_info->provider_id = strdup(provider->provider_id);
+               provider_info->data_id = strdup(provider->data_id);
+               provider_info->monitor_id = monitor_id;
+               if (provider_info->provider_id == NULL || provider_info->data_id == NULL) {
+                       LOGE("data_id alloc fail out of memory.");
+                       ret = DATACONTROL_ERROR_OUT_OF_MEMORY;
+                       __free_provider_info(provider_info);
+                       goto err;
+               }
+               __changed_provider_list = g_list_append(__changed_provider_list, provider_info);
+       } else {
+               provider_info = (provider_info_s *)find_list->data;
+       }
+
+       ret = __noti_request_appsvc_run(
+                       provider_app_id,
+                       provider_info->provider_id,
+                       provider_info->data_id,
+                       unique_id,
+                       *callback_id,
+                       DATACONTROL_TYPE_ADD_DATA_CHANGED_CB);
+       if (ret != DATACONTROL_ERROR_NONE) {
+               LOGE("__noti_request_appsvc_run error !!!");
+               goto err;
+       }
+
+       cb_info = (changed_cb_info_s *)calloc(1,
+                       sizeof(changed_cb_info_s));
+       if (cb_info == NULL) {
+               LOGE("changed_cb_info_s alloc fail out of memory.");
+               ret = DATACONTROL_ERROR_OUT_OF_MEMORY;
+               goto err;
+       }
+
+       cb_info->changed_cb = callback;
+       cb_info->user_data = user_data;
+       cb_info->callback_id = *callback_id;
+       provider_info->cb_list = g_list_append(
+                       provider_info->cb_list, cb_info);
+
+       result_cb_info =
+               (add_callback_result_cb_info_s *)calloc(1, sizeof(add_callback_result_cb_info_s));
+       result_cb_info->callback_id = *callback_id;
+       result_cb_info->callback = result_callback;
+       result_cb_info->user_data = result_cb_user_data;
+       result_cb_info->provider_id = strdup(provider_info->provider_id);
+       result_cb_info->data_id = strdup(provider_info->data_id);
+       result_cb_info->timeout_id = g_timeout_add(5000, __add_callback_result_timeout_handler, result_cb_info);
+       __add_callback_result_cb_list = g_list_append(__add_callback_result_cb_list, result_cb_info);
+       LOGI("datacontrol_add_data_change_cb done");
+
+       return ret;
+err:
+       if (access)
+               free(access);
+       if (provider_app_id)
+               free(provider_app_id);
+       if (path)
+               free(path);
+       if (monitor_id > 0)
+               g_dbus_connection_signal_unsubscribe(_get_dbus_connection(), monitor_id);
+
+       return ret;
+}
+
+int datacontrol_remove_data_change_cb(datacontrol_h provider, int callback_id)
+{
+       changed_cb_info_s *removed_cb_info = NULL;
+       changed_cb_info_s cb_info;
+       provider_info_s info;
+       provider_info_s *target_provider_info;
+       add_callback_result_cb_info_s result_cb_info;
+       GList *provider_list = NULL;
+       GList *callback_list = NULL;
+       GList *result_cb_list = NULL;
+       const char *unique_id = NULL;
+       int ret = DATACONTROL_ERROR_NONE;
+
+       info.provider_id = provider->provider_id;
+       info.data_id = provider->data_id;
+
+       provider_list = g_list_find_custom(__changed_provider_list, &info,
+                       (GCompareFunc)__provider_info_compare_cb);
+       if (provider_list == NULL) {
+               LOGE("Cannot find provider info");
+               return DATACONTROL_ERROR_INVALID_PARAMETER;
+       }
+
+       cb_info.callback_id = callback_id;
+       target_provider_info = (provider_info_s *)provider_list->data;
+       callback_list = g_list_find_custom(
+                       target_provider_info->cb_list,
+                       &cb_info,
+                       (GCompareFunc)__changed_cb_info_compare_cb);
+       if (callback_list == NULL) {
+               LOGE("Cannot find changed callback info");
+               return DATACONTROL_ERROR_INVALID_PARAMETER;
+       }
+
+       removed_cb_info = (changed_cb_info_s *)callback_list->data;
+       target_provider_info->cb_list
+               = g_list_remove(target_provider_info->cb_list, removed_cb_info);
+
+       if (g_list_length(target_provider_info->cb_list) == 0) {
+               unique_id = g_dbus_connection_get_unique_name(_get_dbus_connection());
+               LOGI("unique_id : %s", unique_id);
+               ret = __noti_request_appsvc_run(
+                                       target_provider_info->provider_appid,
+                                       target_provider_info->provider_id,
+                                       target_provider_info->data_id,
+                                       unique_id,
+                                       callback_id,
+                                       DATACONTROL_TYPE_REMOVE_DATA_CHANGED_CB);
+               if (ret != DATACONTROL_ERROR_NONE) {
+                       LOGE("__sql_request_provider fail %d", ret);
+                       return ret;
+               }
+
+               __changed_provider_list = g_list_remove_link(__changed_provider_list, provider_list);
+               __free_provider_info((provider_info_s *)provider_list->data);
+       }
+
+       result_cb_info.callback_id = callback_id;
+       result_cb_list = g_list_find_custom(__add_callback_result_cb_list, &result_cb_info,
+                       (GCompareFunc)__callback_result_info_compare_cb);
+       if (result_cb_list) {
+               __add_callback_result_cb_list = g_list_remove_link(__add_callback_result_cb_list, result_cb_list);
+               __free_result_cb_info((add_callback_result_cb_info_s *)result_cb_list->data);
+       }
+       return DATACONTROL_ERROR_NONE;
+}
index 80ca6d278acf3758c98264ed9cf74a69b6aa88e9..de9ee84014dbc47374af6c960cf0a4d710f7687f 100755 (executable)
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <dlog.h>
 #include <errno.h>
 #include <search.h>
 #include <stdlib.h>
@@ -29,6 +28,7 @@
 #include <fcntl.h>
 #include <sys/socket.h>
 
+#include <dlog.h>
 #include <appsvc/appsvc.h>
 #include <aul/aul.h>
 #include <bundle.h>
@@ -39,8 +39,9 @@
 #include "data-control-provider.h"
 #include "data-control-internal.h"
 
-#define ROW_ID_SIZE                            32
-#define RESULT_PATH_MAX                                512
+#define QUERY_MAXLEN                   4096
+#define ROW_ID_SIZE                    32
+#define RESULT_PATH_MAX                        512
 
 #define RESULT_PAGE_NUMBER             "RESULT_PAGE_NUMBER"
 #define MAX_COUNT_PER_PAGE             "MAX_COUNT_PER_PAGE"
 #define PACKET_INDEX_MAP_PAGE_NO       2
 #define PACKET_INDEX_MAP_COUNT_PER_PAGE        3
 
+#define DATA_CONTROL_BUS_NAME "org.tizen.data_control_service"
+#define DATA_CONTROL_OBJECT_PATH "/org/tizen/data_control_service"
+#define DATA_CONTROL_INTERFACE_NAME "org.tizen.data_control_service"
+#define DATA_CONTROL_DATA_CHANGE_DATA_CHANGED "noti_data_changed"
+#define DATA_CONTROL_DATA_CHANGE_ADD_REMOVE_RESULT "noti_add_remove_result"
+
 static GHashTable *__request_table = NULL;
 static GHashTable *__socket_pair_hash = NULL;
+static sqlite3 *__provider_db = NULL;
 
-/* static pthread_mutex_t provider_lock = PTHREAD_MUTEX_INITIALIZER; */
-
-struct datacontrol_s {
-       char *provider_id;
-       char *data_id;
-};
+void *provider_sql_user_data;
+void *provider_map_user_data;
 
+/* static pthread_mutex_t provider_lock = PTHREAD_MUTEX_INITIALIZER; */
+typedef int (*provider_handler_cb) (bundle *b, int request_id, void *data);
 
-typedef int (*provider_handler_cb)(bundle *b, int request_id, void *data);
+typedef struct {
+       void *user_data;
+       int callback_id;
+       data_control_provider_data_change_consumer_filter_cb callback;
+} changed_noti_consumer_filter_info_s;
 
 static datacontrol_provider_sql_cb *provider_sql_cb = NULL;
 static datacontrol_provider_map_cb *provider_map_cb = NULL;
-static void *provider_map_user_data = NULL;
-static void *provider_sql_user_data = NULL;
+
+static GList *__noti_consumer_app_list = NULL;
+static GList *__noti_consumer_filter_info_list = NULL;
+static int __create_consumer_list_db();
+static int __delete_consumer_list_db_info(char *object_path);
+
+static int __data_changed_filter_cb_info_compare_cb(gconstpointer a, gconstpointer b)
+{
+       changed_noti_consumer_filter_info_s *key1 = (changed_noti_consumer_filter_info_s *)a;
+       changed_noti_consumer_filter_info_s *key2 = (changed_noti_consumer_filter_info_s *)b;
+
+       return !(key1->callback_id == key2->callback_id);
+}
+
+static int __noti_consumer_app_list_compare_cb(gconstpointer a, gconstpointer b)
+{
+       datacontrol_consumer_info *info_a = (datacontrol_consumer_info *)a;
+       datacontrol_consumer_info *info_b = (datacontrol_consumer_info *)b;
+
+       return strcmp(info_a->unique_id, info_b->unique_id);
+}
+
+static void __free_consumer_info(const gchar *name)
+{
+       datacontrol_consumer_info find_key;
+       datacontrol_consumer_info *info;
+       GList *find_list = NULL;
+       int result;
+
+       find_key.unique_id = (char *)name;
+       find_list = g_list_find_custom(__noti_consumer_app_list, &find_key,
+                       (GCompareFunc)__noti_consumer_app_list_compare_cb);
+       if (find_list == NULL) {
+               LOGI("__free_consumer_info %s not exist", name);
+               return;
+       }
+
+       info = (datacontrol_consumer_info *)find_list->data;
+       result = __delete_consumer_list_db_info(info->object_path);
+       if (result != DATACONTROL_ERROR_NONE)
+               LOGE("__delete_consumer_list_db_info fail %d", result);
+
+       if (info->appid)
+               free(info->appid);
+       if (info->object_path)
+               free(info->object_path);
+       if (info->unique_id)
+               free(info->unique_id);
+       g_bus_unwatch_name(info->monitor_id);
+
+       __noti_consumer_app_list = g_list_remove(__noti_consumer_app_list, find_list->data);
+       LOGI("__free_consumer_info done");
+}
 
 static void __free_data(gpointer data)
 {
@@ -94,8 +155,12 @@ static void __free_data(gpointer data)
 
 static void __initialize_provider(void)
 {
+       int result;
        __request_table = g_hash_table_new_full(g_int_hash, g_int_equal, __free_data, __free_data);
        __socket_pair_hash = g_hash_table_new_full(g_str_hash, g_str_equal, free, _socket_info_free);
+       result = __create_consumer_list_db();
+       if (result != DATACONTROL_ERROR_NONE)
+               LOGE("fail to create consumer list db");
 }
 
 static int __provider_new_request_id(void)
@@ -607,6 +672,19 @@ static bundle *__set_result(bundle *b, datacontrol_request_type type, void *data
 
                break;
        }
+       case DATACONTROL_TYPE_ADD_DATA_CHANGED_CB:
+       {
+               const char *list[2];
+               char result_str[2] = {0,};
+               bool result = *(bool *)data;
+               snprintf(result_str, 2, "%d", result);
+
+               list[PACKET_INDEX_REQUEST_RESULT] = result_str;         /* request result */
+               list[PACKET_INDEX_ERROR_MSG] = DATACONTROL_EMPTY;
+
+               bundle_add_str_array(res, OSP_K_ARG, list, 2);
+               break;
+       }
        case DATACONTROL_TYPE_UNDEFINED:        /* DATACONTROL_TYPE_MAP_SET || ADD || REMOVE */
        {
                const char *list[2];
@@ -654,6 +732,281 @@ static int __send_result(bundle *b, datacontrol_request_type type, void *data)
        return ret;
 }
 
+static int __insert_consumer_list_db_info(char *app_id, char *provider_id, char *data_id, char *unique_id, char *object_path)
+{
+       int r;
+       int result = DATACONTROL_ERROR_NONE;
+       char query[QUERY_MAXLEN];
+       sqlite3_stmt *stmt = NULL;
+       sqlite3_snprintf(QUERY_MAXLEN, query,
+                       "INSERT OR REPLACE INTO data_control_consumer_path_list(app_id, provider_id, data_id, unique_id, object_path)" \
+                       "VALUES (?,?,?,?,?)");
+       LOGI("consumer list db insert sql : %s", query);
+       r = sqlite3_prepare(__provider_db, query, sizeof(query), &stmt, NULL);
+       if (r != SQLITE_OK) {
+               LOGE("sqlite3_prepare error(%d , %d, %s)", r, sqlite3_extended_errcode(__provider_db), sqlite3_errmsg(__provider_db));
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       r = sqlite3_bind_text(stmt, 1, app_id, strlen(app_id), SQLITE_STATIC);
+       if (r != SQLITE_OK) {
+               LOGE("app_id bind error(%d) \n", r);
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       r = sqlite3_bind_text(stmt, 2, provider_id, strlen(provider_id), SQLITE_STATIC);
+       if (r != SQLITE_OK) {
+               LOGE("provider_id bind error(%d) \n", r);
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       r = sqlite3_bind_text(stmt, 3, data_id, strlen(data_id), SQLITE_STATIC);
+       if (r != SQLITE_OK) {
+               LOGE("data_id bind error(%d) \n", r);
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       r = sqlite3_bind_text(stmt, 4, unique_id, strlen(unique_id), SQLITE_STATIC);
+       if (r != SQLITE_OK) {
+               LOGE("unique_id bind error(%d) \n", r);
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       r = sqlite3_bind_text(stmt, 5, object_path, strlen(object_path), SQLITE_STATIC);
+       if (r != SQLITE_OK) {
+               LOGE("object_path bind error(%d) \n", r);
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       r = sqlite3_step(stmt);
+       if (r != SQLITE_DONE) {
+               LOGE("step error(%d) \n", r);
+               LOGE("sqlite3_step error(%d, %s)",
+                               sqlite3_extended_errcode(__provider_db),
+                               sqlite3_errmsg(__provider_db));
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+out :
+       if (stmt)
+               sqlite3_finalize(stmt);
+
+       return result;
+}
+
+static int __delete_consumer_list_db_info(char *object_path)
+{
+       int r;
+       char query[QUERY_MAXLEN];
+       int result = DATACONTROL_ERROR_NONE;
+       sqlite3_stmt *stmt = NULL;
+       sqlite3_snprintf(QUERY_MAXLEN, query,
+                       "DELETE FROM data_control_consumer_path_list WHERE object_path = ?");
+       LOGI("consumer list db DELETE : %s, object_path : %s", query, object_path);
+       r = sqlite3_prepare(__provider_db, query, sizeof(query), &stmt, NULL);
+       if (r != SQLITE_OK) {
+               LOGE("sqlite3_prepare error(%d , %d, %s)", r,
+                               sqlite3_extended_errcode(__provider_db), sqlite3_errmsg(__provider_db));
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       r = sqlite3_bind_text(stmt, 1, object_path, strlen(object_path), SQLITE_STATIC);
+       if (r != SQLITE_OK) {
+               LOGE("caller bind error(%d) \n", r);
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       r = sqlite3_step(stmt);
+       if (r != SQLITE_DONE) {
+               LOGE("step error(%d) \n", r);
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+out :
+       if (stmt)
+               sqlite3_finalize(stmt);
+
+       LOGI("__delete_consumer_list_db_info done");
+       return result;
+}
+
+static void __on_name_appeared(GDBusConnection *connection,
+               const gchar     *name,
+               const gchar     *name_owner,
+               gpointer         user_data)
+{
+       LOGI("name appeared : %s", name);
+}
+
+static void __on_name_vanished(GDBusConnection *connection,
+               const gchar     *name,
+               gpointer         user_data)
+{
+       LOGI("name vanished : %s", name);
+       __free_consumer_info(name);
+}
+
+static int __init_changed_noti_consumer_list()
+{
+       char *app_id = NULL;
+       char *unique_id = NULL;
+       char *object_path = NULL;
+       int ret = DATACONTROL_ERROR_NONE;
+       sqlite3_stmt *stmt = NULL;
+       char query[QUERY_MAXLEN];
+       datacontrol_consumer_info *consumer_info = NULL;
+
+       sqlite3_snprintf(QUERY_MAXLEN, query,
+                       "SELECT app_id, object_path, unique_id " \
+                       "FROM data_control_consumer_path_list");
+
+       LOGI("__init_changed_noti_consumer_list query : %s", query);
+       ret = sqlite3_prepare_v2(__provider_db, query, -1, &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               LOGE("prepare stmt fail");
+               return DATACONTROL_ERROR_IO_ERROR;
+       }
+
+       while (SQLITE_ROW == sqlite3_step(stmt)) {
+               app_id = (char *)sqlite3_column_text(stmt, 0);
+               if (!app_id) {
+                       LOGE("Failed to get package name\n");
+                       continue;
+               }
+
+               object_path = (char *)sqlite3_column_text(stmt, 1);
+               if (!object_path) {
+                       LOGE("Failed to get object_path\n");
+                       continue;
+               }
+
+               unique_id = (char *)sqlite3_column_text(stmt, 2);
+               if (!unique_id) {
+                       LOGE("Failed to get unique_id\n");
+                       continue;
+               }
+               LOGI("sql : app_id : %s, object_path : %s, unique_id : %s",
+                               app_id, object_path, unique_id);
+
+               consumer_info = (datacontrol_consumer_info *)
+                       calloc(1, sizeof(datacontrol_consumer_info));
+               consumer_info->appid = strdup(app_id);
+               consumer_info->object_path = strdup(object_path);
+               consumer_info->unique_id = strdup(unique_id);
+
+               consumer_info->monitor_id = g_bus_watch_name_on_connection(
+                               _get_dbus_connection(),
+                               consumer_info->unique_id,
+                               G_BUS_NAME_WATCHER_FLAGS_NONE,
+                               __on_name_appeared,
+                               __on_name_vanished,
+                               consumer_info,
+                               NULL);
+
+               LOGI("noti consumer_app_list append %s", consumer_info->object_path);
+               __noti_consumer_app_list =
+                       g_list_append(__noti_consumer_app_list, consumer_info);
+       }
+       sqlite3_reset(stmt);
+       sqlite3_finalize(stmt);
+
+       return ret;
+}
+
+static int __create_consumer_list_db()
+{
+       char *db_path = NULL;
+       int ret = SQLITE_OK;
+       int open_flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+       char *table_command =
+               "CREATE TABLE IF NOT EXISTS data_control_consumer_path_list" \
+               "(app_id TEXT NOT NULL, provider_id TEXT NOT NULL, data_id TEXT NOT NULL, " \
+               "unique_id TEXT NOT NULL, object_path TEXT NOT NULL, " \
+               "PRIMARY KEY(object_path))";
+
+       if (__provider_db == NULL) {
+               db_path = _get_encoded_db_path();
+               if (db_path == NULL)
+                       return DATACONTROL_ERROR_IO_ERROR;
+               LOGI("data-control provider db path : %s", db_path);
+
+               ret = sqlite3_open_v2(db_path, &__provider_db, open_flags, NULL);
+               free(db_path);
+               if (ret != SQLITE_OK) {
+                       LOGE("database creation failed with error: %d", ret);
+                       return DATACONTROL_ERROR_IO_ERROR;
+               }
+               ret = sqlite3_exec(__provider_db, table_command, NULL, NULL, NULL);
+               if (ret != SQLITE_OK) {
+                       LOGE("database table creation failed with error: %d", ret);
+                       return DATACONTROL_ERROR_IO_ERROR;
+               }
+               ret = __init_changed_noti_consumer_list();
+               if (ret != DATACONTROL_ERROR_NONE) {
+                       LOGE("__init_changed_noti_consumer_list fail %d", ret);
+                       return ret;
+               }
+       }
+       return DATACONTROL_ERROR_NONE;
+}
+
+static int __set_consumer_app_list(
+               char *caller,
+               char *object_path,
+               char *unique_id)
+{
+       datacontrol_consumer_info find_key;
+       datacontrol_consumer_info *consumer_info;
+       GList *find_list = NULL;
+       int ret = DATACONTROL_ERROR_NONE;
+       LOGI("set consumer_app_list caller : %s, path : %s, unique_id : %s",
+                       caller, object_path, unique_id);
+
+       find_key.unique_id = unique_id;
+       find_list = g_list_find_custom(__noti_consumer_app_list,
+                       &find_key,
+                       (GCompareFunc)__noti_consumer_app_list_compare_cb);
+
+       if (!find_list) {
+               consumer_info = (datacontrol_consumer_info *)
+                       calloc(1, sizeof(datacontrol_consumer_info));
+               consumer_info->appid = strdup(caller);
+               consumer_info->object_path = strdup(object_path);
+               consumer_info->unique_id = strdup(unique_id);
+
+               consumer_info->monitor_id = g_bus_watch_name_on_connection(
+                               _get_dbus_connection(),
+                               consumer_info->unique_id,
+                               G_BUS_NAME_WATCHER_FLAGS_NONE,
+                               __on_name_appeared,
+                               __on_name_vanished,
+                               consumer_info,
+                               NULL);
+               if (consumer_info->monitor_id == 0) {
+                       LOGE("g_bus_watch_name_on_connection fail");
+
+                       free(consumer_info->appid);
+                       free(consumer_info->object_path);
+                       free(consumer_info->unique_id);
+                       free(consumer_info);
+
+                       return DATACONTROL_ERROR_IO_ERROR;
+               }
+               LOGI("new noti consumer_app_list append %s", consumer_info->object_path);
+               __noti_consumer_app_list = g_list_append(__noti_consumer_app_list, consumer_info);
+       }
+       return ret;
+}
 
 int __provider_process(bundle *b, int fd)
 {
@@ -686,7 +1039,7 @@ int __provider_process(bundle *b, int fd)
                }
 
        } else {
-               LOGE("Invalid requeste type");
+               LOGE("Invalid request type");
                return DATACONTROL_ERROR_INVALID_PARAMETER;
        }
 
@@ -922,25 +1275,259 @@ error:
        return FALSE;
 }
 
+static int __send_add_callback_result(
+               datacontrol_data_change_type_e result_type,
+               char *unique_id,
+               char *path,
+               int callback_id,
+               int callback_result)
+{
+       GError *err = NULL;
+       int result = DATACONTROL_ERROR_NONE;
+       gboolean signal_result = TRUE;
+       LOGI("add callback_result type : %d, callback_id : %d, result : %d",
+                       result_type, callback_id, callback_result);
+
+       signal_result = g_dbus_connection_emit_signal(
+                       _get_dbus_connection(),
+                       unique_id,
+                       path,
+                       DATA_CONTROL_INTERFACE_NAME,
+                       DATA_CONTROL_DATA_CHANGE_ADD_REMOVE_RESULT,
+                       g_variant_new("(iii)",
+                               result_type,
+                               callback_id,
+                               callback_result), &err);
+       if (signal_result == FALSE) {
+               LOGE("g_dbus_connection_emit_signal() is failed");
+               if (err != NULL) {
+                       LOGE("g_dbus_connection_emit_signal() err : %s",
+                                       err->message);
+                       g_error_free(err);
+               }
+               return DATACONTROL_ERROR_IO_ERROR;
+       }
+
+       LOGI("Send __send_add_callback_result done %d", result);
+       return result;
+}
+
+
+static int __get_sender_pid(const char *sender_name)
+{
+       GDBusMessage *msg = NULL;
+       GDBusMessage *reply = NULL;
+       GError *err = NULL;
+       GVariant *body;
+       int pid = 0;
+
+       msg = g_dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus",
+                       "org.freedesktop.DBus", "GetConnectionUnixProcessID");
+       if (!msg) {
+               LOGE("Can't allocate new method call");
+               goto out;
+       }
+
+       g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
+       reply = g_dbus_connection_send_message_with_reply_sync(_get_dbus_connection(), msg,
+                                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err);
+
+       if (!reply) {
+               if (err != NULL) {
+                       LOGE("Failed to get pid [%s]", err->message);
+                       g_error_free(err);
+               }
+               goto out;
+       }
+
+       body = g_dbus_message_get_body(reply);
+       g_variant_get(body, "(u)", &pid);
+
+out:
+       if (msg)
+               g_object_unref(msg);
+       if (reply)
+               g_object_unref(reply);
+
+       return pid;
+}
+
+static int __provider_noti_process(bundle *b, datacontrol_request_type type)
+{
+       datacontrol_h provider = NULL;
+       bool noti_allow = true;
+       char *path = NULL;
+       int result = DATACONTROL_ERROR_NONE;
+       char *unique_id = NULL;
+       datacontrol_data_change_type_e result_type = DATACONTROL_DATA_CHANGE_CALLBACK_ADD_RESULT;
+       char *callback_id_str = NULL;
+       int callback_id = -1;
+       GList *filter_iter;
+       changed_noti_consumer_filter_info_s *filter_info;
+       char caller_app_id[255];
+       const char *pid_str;
+       int pid;
+       int sender_pid;
+
+       pid_str = bundle_get_val(b, AUL_K_CALLER_PID);
+       if (pid_str == NULL) {
+               LOGE("fail to get caller pid");
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+       pid = atoi(pid_str);
+       if (pid <= 1) {
+               LOGE("invalid caller pid %s", pid_str);
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+       if (aul_app_get_appid_bypid(pid, caller_app_id, sizeof(caller_app_id)) != 0) {
+               LOGE("Failed to get appid by pid");
+               return DATACONTROL_ERROR_IO_ERROR;
+       }
+
+       unique_id = (char *)bundle_get_val(b, OSP_K_DATACONTROL_UNIQUE_NAME);
+       LOGI("unique_id : %s", unique_id);
+       sender_pid = __get_sender_pid(unique_id);
+       if (sender_pid != pid) {
+               LOGE("invalid unique id. sender does not have unique_id %s", unique_id);
+               return DATACONTROL_ERROR_PERMISSION_DENIED;
+       }
+
+       result = __create_consumer_list_db();
+       if (result != DATACONTROL_ERROR_NONE) {
+               LOGE("fail to create consumer list db");
+               return result;
+       }
+
+       provider = malloc(sizeof(struct datacontrol_s));
+       if (provider == NULL) {
+               LOGE("Out of memory. fail to alloc provider.");
+               return DATACONTROL_ERROR_OUT_OF_MEMORY;
+       }
+       provider->provider_id = (char *)bundle_get_val(b, OSP_K_DATACONTROL_PROVIDER);
+       provider->data_id = (char *)bundle_get_val(b, OSP_K_DATACONTROL_DATA);
+       LOGI("Noti Provider ID: %s, data ID: %s, request type: %d", provider->provider_id, provider->data_id, type);
+       path = _get_encoded_path(provider, caller_app_id);
+       if (path == NULL) {
+               LOGE("can not get encoded path out of memory");
+               free(provider);
+               return DATACONTROL_ERROR_OUT_OF_MEMORY;
+       }
+
+       callback_id_str = (char *)bundle_get_val(b, OSP_K_DATA_CHANGED_CALLBACK_ID);
+       if (callback_id_str == NULL) {
+               LOGE("callback_id is NULL");
+               result = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+       callback_id = atoi(callback_id_str);
+
+       switch (type) {
+       case DATACONTROL_TYPE_ADD_DATA_CHANGED_CB:
+       {
+               LOGI("DATACONTROL_TYPE_ADD_DATA_CHANGED_CB called");
+               result_type = DATACONTROL_DATA_CHANGE_CALLBACK_ADD_RESULT;
+               filter_iter = g_list_first(__noti_consumer_filter_info_list);
+               for (; filter_iter != NULL; filter_iter = filter_iter->next) {
+                       filter_info = (changed_noti_consumer_filter_info_s *)filter_iter->data;
+                       noti_allow = filter_info->callback((data_control_h)provider, caller_app_id, filter_info->user_data);
+                       if (!noti_allow)
+                               break;
+               }
+               LOGI("provider_sql_consumer_filter_cb result %d", noti_allow);
+
+               if (noti_allow) {
+                       result = __insert_consumer_list_db_info(
+                                       caller_app_id,
+                                       provider->provider_id,
+                                       provider->data_id,
+                                       unique_id,
+                                       path);
+                       if (result != DATACONTROL_ERROR_NONE) {
+                               LOGE("fail to set consumer list db info %d", result);
+                               result = DATACONTROL_ERROR_PERMISSION_DENIED;
+                               break;
+                       }
+
+                       result = __set_consumer_app_list(
+                                       caller_app_id,
+                                       path,
+                                       unique_id);
+                       if (result != DATACONTROL_ERROR_NONE)
+                               LOGE("fail to __set_consumer_app_list");
+
+               } else {
+                       result = DATACONTROL_ERROR_PERMISSION_DENIED;
+                       break;
+               }
+               break;
+       }
+       case DATACONTROL_TYPE_REMOVE_DATA_CHANGED_CB:
+       {
+               LOGI("DATACONTROL_NOTI_REMOVE_DATA_CHANGED_CB called");
+               result_type = DATACONTROL_DATA_CHANGE_CALLBACK_REMOVE_RESULT;
+               if (__noti_consumer_app_list) {
+                       __free_consumer_info(unique_id);
+                       LOGI("unregister %s from __noti_consumer_app_list", unique_id);
+               } else {
+                       LOGI("empty __consumer_app_list");
+               }
+               result = __delete_consumer_list_db_info(path);
+               if (result != DATACONTROL_ERROR_NONE) {
+                       LOGE("__delete_consumer_list_db_info fail %d", result);
+                       result = DATACONTROL_ERROR_IO_ERROR;
+                       goto out;
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+out:
+       __send_add_callback_result(
+                       result_type, unique_id, path, callback_id, result);
+
+       if (provider)
+               free(provider);
+
+       return result;
+}
+
 int __datacontrol_handler_cb(bundle *b, int request_id, void *data)
 {
        datacontrol_socket_info *socket_info;
-       char *caller = (char *)bundle_get_val(b, AUL_K_CALLER_APPID);
-       char *callee = (char *)bundle_get_val(b, AUL_K_CALLEE_APPID);
+       int ret = DATACONTROL_ERROR_NONE;
 
-       LOGI("datacontrol_handler_cb");
-       socket_info = g_hash_table_lookup(__socket_pair_hash, caller);
+       const char *request_type = bundle_get_val(b, OSP_K_DATACONTROL_REQUEST_TYPE);
+       if (request_type == NULL) {
+               char *caller = (char *)bundle_get_val(b, AUL_K_CALLER_APPID);
+               char *callee = (char *)bundle_get_val(b, AUL_K_CALLEE_APPID);
 
-       if (socket_info != NULL)
-               g_hash_table_remove(__socket_pair_hash, caller);
+               socket_info = g_hash_table_lookup(__socket_pair_hash, caller);
 
-       socket_info = _get_socket_info(caller, callee, "provider", __provider_recv_message, caller);
-       if (socket_info == NULL)
-               return DATACONTROL_ERROR_IO_ERROR;
+               if (socket_info != NULL)
+                       g_hash_table_remove(__socket_pair_hash, caller);
 
-       g_hash_table_insert(__socket_pair_hash, strdup(caller), socket_info);
+               socket_info = _add_watch_on_socket_info(caller, callee, "provider", __provider_recv_message, caller);
+               if (socket_info == NULL)
+                       return DATACONTROL_ERROR_IO_ERROR;
 
-       return DATACONTROL_ERROR_NONE;
+               g_hash_table_insert(__socket_pair_hash, strdup(caller), socket_info);
+       } else {
+               /* Get the request type */
+               datacontrol_request_type type = atoi(request_type);
+               if (type == DATACONTROL_TYPE_ADD_DATA_CHANGED_CB ||
+                               type == DATACONTROL_TYPE_REMOVE_DATA_CHANGED_CB) {
+                       __provider_noti_process(b, type);
+               } else {
+                       LOGE("Invalid data control request");
+                       return DATACONTROL_ERROR_INVALID_PARAMETER;
+               }
+       }
+
+       return ret;
 }
 
 int datacontrol_provider_sql_register_cb(datacontrol_provider_sql_cb *callback, void *user_data)
@@ -1085,6 +1672,7 @@ int datacontrol_provider_send_insert_result(int request_id, long long row_id)
        g_hash_table_remove(__request_table, &request_id);
 
        return ret;
+
 }
 
 int datacontrol_provider_send_update_result(int request_id)
@@ -1212,3 +1800,174 @@ int datacontrol_provider_send_map_get_value_result(int request_id, char **value_
        return ret;
 }
 
+static int __send_signal_to_consumer(datacontrol_h provider,
+               char *unique_id,
+               char *path,
+               datacontrol_data_change_type_e type,
+               bundle *data)
+{
+       int result = DATACONTROL_ERROR_NONE;
+       int len = 0;
+       bundle_raw *raw = NULL;
+       GError *err = NULL;
+       gboolean signal_result = TRUE;
+
+       if (data) {
+               if (bundle_encode(data, &raw, &len) != BUNDLE_ERROR_NONE) {
+                       LOGE("bundle_encode fail");
+                       result = DATACONTROL_ERROR_IO_ERROR;
+                       goto out;
+               }
+       }
+
+       LOGI("emit signal to object path %s", path);
+       signal_result = g_dbus_connection_emit_signal(
+                       _get_dbus_connection(),
+                       unique_id,
+                       path,
+                       DATA_CONTROL_INTERFACE_NAME,
+                       DATA_CONTROL_DATA_CHANGE_DATA_CHANGED,
+                       g_variant_new("(isssi)",
+                               type,
+                               provider->provider_id,
+                               provider->data_id,
+                               ((raw) ? (char *)raw : ""),
+                               len), &err);
+
+       if (signal_result == FALSE) {
+               LOGE("g_dbus_connection_emit_signal() is failed");
+               if (err != NULL) {
+                       LOGE("g_dbus_connection_emit_signal() err : %s",
+                                       err->message);
+                       g_error_free(err);
+               }
+               return DATACONTROL_ERROR_IO_ERROR;
+       }
+
+out:
+       if (raw)
+               free(raw);
+
+       return result;
+}
+
+int datacontrol_provider_send_data_change_noti(
+               datacontrol_h provider,
+               datacontrol_data_change_type_e type,
+               bundle *data)
+{
+       int result = DATACONTROL_ERROR_NONE;
+       GList *consumer_iter = NULL;
+       datacontrol_consumer_info *consumer_info = NULL;
+
+       LOGE("datacontrol_provider_send_data_change_noti %d, %d", g_list_length(__noti_consumer_app_list), type);
+       consumer_iter = g_list_first(__noti_consumer_app_list);
+       for (; consumer_iter != NULL; consumer_iter = consumer_iter->next) {
+               consumer_info = (datacontrol_consumer_info *)consumer_iter->data;
+               result = __send_signal_to_consumer(
+                               provider,
+                               consumer_info->unique_id,
+                               consumer_info->object_path,
+                               type,
+                               data);
+               if (result != DATACONTROL_ERROR_NONE) {
+                       LOGE("__send_signal_to_consumer fail : %d", result);
+                       break;
+               }
+       }
+       return result;
+}
+
+int datacontrol_provider_add_data_change_consumer_filter_cb(
+               data_control_provider_data_change_consumer_filter_cb callback,
+               void *user_data,
+               int *callback_id)
+{
+       changed_noti_consumer_filter_info_s *filter_info = (changed_noti_consumer_filter_info_s *)calloc(1,
+                       sizeof(changed_noti_consumer_filter_info_s));
+
+       *callback_id = _datacontrol_get_data_changed_filter_callback_id();
+
+       filter_info->callback_id = *callback_id;
+       filter_info->callback = callback;
+       filter_info->user_data = user_data;
+       __noti_consumer_filter_info_list = g_list_append(__noti_consumer_filter_info_list, filter_info);
+
+       return DATACONTROL_ERROR_NONE;
+}
+
+int datacontrol_provider_remove_data_change_consumer_filter_cb(int callback_id)
+{
+       GList *find_list;
+       changed_noti_consumer_filter_info_s filter_info;
+       filter_info.callback_id = callback_id;
+       find_list = g_list_find_custom(__noti_consumer_filter_info_list, &filter_info,
+                       (GCompareFunc)__data_changed_filter_cb_info_compare_cb);
+       if (find_list != NULL) {
+               __noti_consumer_filter_info_list = g_list_remove(__noti_consumer_filter_info_list, find_list->data);
+       } else {
+               LOGE("invalid callback_id : %d", callback_id);
+               return DATACONTROL_ERROR_INVALID_PARAMETER;
+       }
+
+       return DATACONTROL_ERROR_NONE;
+}
+
+int datacontrol_provider_foreach_data_change_consumer(
+               datacontrol_h provider,
+               void *list_cb,
+               void *user_data)
+{
+       char *app_id = NULL;
+       int ret = DATACONTROL_ERROR_NONE;
+       sqlite3_stmt *stmt = NULL;
+       char query[QUERY_MAXLEN];
+       bool callback_result;
+       data_control_provider_data_change_consumer_cb consumer_list_cb;
+       consumer_list_cb = (data_control_provider_data_change_consumer_cb)list_cb;
+
+       sqlite3_snprintf(QUERY_MAXLEN, query,
+                       "SELECT app_id " \
+                       "FROM data_control_consumer_path_list WHERE provider_id = ? AND data_id = ?");
+       LOGI("get_changed_noti_consumer_list query : %s", query);
+
+       ret = sqlite3_prepare_v2(__provider_db, query, -1, &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               LOGE("prepare stmt fail");
+               ret = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       ret = sqlite3_bind_text(stmt, 1, provider->provider_id, -1, SQLITE_TRANSIENT);
+       if (ret != SQLITE_OK) {
+               LOGE("bind provider id fail: %s", sqlite3_errmsg(__provider_db));
+               ret = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       ret = sqlite3_bind_text(stmt, 2, provider->data_id, -1, SQLITE_TRANSIENT);
+       if (ret != SQLITE_OK) {
+               LOGE("bind data id fail: %s", sqlite3_errmsg(__provider_db));
+               ret = DATACONTROL_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       while (SQLITE_ROW == sqlite3_step(stmt)) {
+               app_id = (char *)sqlite3_column_text(stmt, 0);
+               if (!app_id) {
+                       LOGE("Failed to get package name\n");
+                       continue;
+               }
+               callback_result = consumer_list_cb((data_control_h)provider, app_id, user_data);
+               LOGI("app_id : %s, result : %d ", app_id, callback_result);
+               if (!callback_result)
+                       break;
+       }
+out:
+       sqlite3_reset(stmt);
+       sqlite3_clear_bindings(stmt);
+       sqlite3_finalize(stmt);
+
+       return ret;
+}
+
index debdbb8b7bf329bd2d1cf8d1ceef152420aa3782..849e9b7c6c5b64051e911d97df6921b24853c167 100755 (executable)
 #define REQUEST_PATH_MAX               512
 #define MAX_REQUEST_ARGUMENT_SIZE      1048576 /* 1MB */
 
-struct datacontrol_s {
-       char *provider_id;
-       char *data_id;
-};
-
 typedef struct {
        char *provider_id;
        char *app_id;
@@ -679,7 +674,7 @@ out:
 static int __sql_request_provider(datacontrol_h provider, datacontrol_request_type type, bundle *request_data, bundle *extra_kb, int request_id)
 {
        char *app_id = NULL;
-       void *data = NULL;
+       void *response_cb_data = NULL;
        int ret = DATACONTROL_ERROR_NONE;
        sql_response_cb_s *sql_dc_temp;
        void *sql_dc_returned = NULL;
@@ -751,7 +746,7 @@ static int __sql_request_provider(datacontrol_h provider, datacontrol_request_ty
                request_info->type = type;
                sql_dc->request_info_list = g_list_append(sql_dc->request_info_list, request_info);
 
-               data = sql_dc;
+               response_cb_data = sql_dc;
 
                LOGI("SQL datacontrol appid: %s", sql_dc->app_id);
        }
@@ -781,7 +776,7 @@ static int __sql_request_provider(datacontrol_h provider, datacontrol_request_ty
                                return ret;
                        }
 
-                       socket_info = _get_socket_info(caller_app_id, app_id, "consumer", __consumer_recv_sql_message, data);
+                       socket_info = _add_watch_on_socket_info(caller_app_id, app_id, "consumer", __consumer_recv_sql_message, response_cb_data);
                        if (socket_info == NULL) {
                                LOGE("_get_socket_info error !!!");
                                return DATACONTROL_ERROR_IO_ERROR;
diff --git a/src/data_control_noti.c b/src/data_control_noti.c
new file mode 100644 (file)
index 0000000..853eab3
--- /dev/null
@@ -0,0 +1,46 @@
+#include <dlog.h>
+#include <errno.h>
+#include <glib.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "data_control_internal.h"
+#include "data_control_log.h"
+#include "data_control_noti.h"
+#include "data-control-noti.h"
+
+EXPORT_API int data_control_add_data_change_cb(
+               data_control_h provider,
+               data_control_data_change_cb callback,
+               void *user_data,
+               data_control_add_callback_result_cb result_callback,
+               void *result_cb_user_data,
+               int *callback_id)
+{
+       int retval = datacontrol_check_privilege(PRIVILEGE_CONSUMER);
+       if (retval != DATA_CONTROL_ERROR_NONE)
+               return retval;
+
+       if (callback == NULL || provider == NULL || callback_id == NULL)
+               return DATA_CONTROL_ERROR_INVALID_PARAMETER;
+
+       return datacontrol_add_data_change_cb(
+                       (datacontrol_h)provider,
+                       callback,
+                       user_data,
+                       result_callback,
+                       result_cb_user_data,
+                       callback_id);
+}
+
+EXPORT_API int data_control_remove_data_change_cb(data_control_h provider, int callback_id)
+{
+       if (callback_id < 1 || provider == NULL)
+               return DATA_CONTROL_ERROR_INVALID_PARAMETER;
+
+       int retval = datacontrol_check_privilege(PRIVILEGE_CONSUMER);
+       if (retval != DATA_CONTROL_ERROR_NONE)
+               return retval;
+
+       return datacontrol_remove_data_change_cb((datacontrol_h)provider, callback_id);
+}
index 86ace9b09b29d5f342e60cf2250040a33b1886e3..b51cdee925d189fcb60a426a8e0ee76cde15a79d 100755 (executable)
 #include <dlog.h>
 #include <bundle.h>
 #include <data-control-provider.h>
+#include <data-control-types.h>
 
 #include "data_control_provider.h"
 #include "data_control_sql.h"
 #include "data_control_log.h"
 #include "data_control_internal.h"
+#include "data-control-internal.h"
 
 #define INSERT_STMT_CONST_LEN 25
 #define DELETE_STMT_CONST_LEN 12
@@ -37,11 +39,6 @@ struct data_control_s {
        char *data_id;
 };
 
-struct datacontrol_s {
-       char *provider_id;
-       char *data_id;
-};
-
 typedef struct {
        int no_of_elements;
        int length;
@@ -569,3 +566,56 @@ EXPORT_API int data_control_provider_send_map_get_value_result(int request_id, c
        return datacontrol_provider_send_map_get_value_result(request_id, value_list, value_count);
 }
 
+EXPORT_API int data_control_provider_add_data_change_consumer_filter_cb(
+               data_control_provider_data_change_consumer_filter_cb callback,
+               void *user_data,
+               int *callback_id)
+{
+       if (!callback)
+               return DATA_CONTROL_ERROR_INVALID_PARAMETER;
+       if (callback_id == NULL)
+               return DATA_CONTROL_ERROR_INVALID_PARAMETER;
+
+       return datacontrol_provider_add_data_change_consumer_filter_cb(callback, user_data, callback_id);
+}
+
+EXPORT_API int data_control_provider_remove_data_change_consumer_filter_cb(int callback_id)
+{
+       if (callback_id < 1)
+               return DATA_CONTROL_ERROR_INVALID_PARAMETER;
+
+       return  datacontrol_provider_remove_data_change_consumer_filter_cb(callback_id);
+}
+
+EXPORT_API int data_control_provider_send_data_change_noti(
+               data_control_h provider,
+               data_control_data_change_type_e type,
+               bundle *data)
+{
+       if (!provider)
+               return DATA_CONTROL_ERROR_INVALID_PARAMETER;
+       if (provider->provider_id == NULL || provider->data_id == NULL)
+               return DATA_CONTROL_ERROR_INVALID_PARAMETER;
+
+       if (type < DATA_CONTROL_DATA_CHANGE_SQL_UPDATE || type > DATA_CONTROL_DATA_CHANGE_MAP_REMOVE)
+               return DATA_CONTROL_ERROR_INVALID_PARAMETER;
+
+       return datacontrol_provider_send_data_change_noti(
+                       (datacontrol_h)provider,
+                       _get_internal_noti_type(type),
+                       data);
+}
+
+EXPORT_API int data_control_provider_foreach_data_change_consumer(
+               data_control_h provider,
+               data_control_provider_data_change_consumer_cb list_cb,
+               void *user_data)
+{
+       if (!provider || !list_cb)
+               return DATA_CONTROL_ERROR_INVALID_PARAMETER;
+       if (provider->provider_id == NULL || provider->data_id == NULL)
+               return DATA_CONTROL_ERROR_INVALID_PARAMETER;
+
+       return datacontrol_provider_foreach_data_change_consumer(
+                       (datacontrol_h)provider, list_cb, user_data);
+}