revise apis for multi notification callback
authorJinWang An <jinwang.an@samsung.com>
Fri, 14 Feb 2020 05:48:31 +0000 (14:48 +0900)
committerYoungjae Shin <yj99.shin@samsung.com>
Wed, 18 Mar 2020 08:53:50 +0000 (17:53 +0900)
client/mdsc_noti_mode.c
include/modes.h
unittest/modes_test_noti.cpp

index 62fadd3bfc9d7283d16d290e3c962fc3ce6aeaa1..87c58a7543f0c18d061d74455bde7ab3bda2cdab 100644 (file)
  */
 #include "modes.h"
 
+#include <stdlib.h>
 #include <glib.h>
 #include "mdsc.h"
 #include "common/dbus.h"
 
-struct mdsc_noti_data_s {
+typedef struct {
        modes_noti_fn cb;
        void *user_data;
-};
+} mdsc_noti_data_s;
 
 static gulong mdsc_noti_signal_ID = 0;
-static struct mdsc_noti_data_s mdsc_noti_data;
+static GList *mdsc_noti_cb_list = NULL;
 
-static void _on_changed_mode(mdsDbus *mdsc_dbus, const char *mode, int state, gpointer user_data)
+static gint _compare_cb(gconstpointer a, gconstpointer b)
 {
-       //TODO:: should support multi callback
-       //RET_IF(NULL == user_data);
+       RETV_IF(NULL == a, 1);
+       RETV_IF(NULL == b, 1);
+
+       const mdsc_noti_data_s *a_data = a;
+       const mdsc_noti_data_s *b_data = b;
+       if ((a_data->cb == b_data->cb)
+               && (a_data->user_data == b_data->user_data))
+               return 0;
+       return -1;
+}
 
-       mdsc_noti_data.cb(mode, state, mdsc_noti_data.user_data);
+static void _on_changed_mode(mdsDbus *mdsc_dbus, const char *mode, int state, gpointer user_data)
+{
+       GList *it;
+       for (it = mdsc_noti_cb_list; it != NULL; it = g_list_next(it)) {
+               mdsc_noti_data_s *data = it->data;
+               if (data && data->cb)
+                       data->cb(mode, state, data->user_data);
+       }
 }
 
 API int modes_subscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data)
 {
-       RETV_IF(0 != mdsc_noti_signal_ID, MODES_ERROR_ALREADY);
        RETV_IF(NULL == handle, MODES_ERROR_INVALID_PARAMETER);
        RETV_IF(NULL == handle->conn, MODES_ERROR_INVALID_PARAMETER);
 
-       mdsc_noti_data.cb = cb;
-       mdsc_noti_data.user_data = user_data;
+       mdsc_noti_data_s search_data = { cb, user_data };
+       GList *found = g_list_find_custom(mdsc_noti_cb_list, &search_data, _compare_cb);
+       if (NULL != found) {
+               ERR("callback and user_data already exist in notification callback list");
+               return MODES_ERROR_ALREADY;
+       }
 
-       mdsc_noti_signal_ID = g_signal_connect(handle->conn,
-               "changed-mode",
-               G_CALLBACK(_on_changed_mode),
-               NULL);
+       mdsc_noti_data_s *data = malloc(sizeof(mdsc_noti_data_s));
+       if (NULL == data) {
+               ERR("malloc() Fail");
+               return MODES_ERROR_SYSTEM;
+       }
+
+       data->cb = cb;
+       data->user_data = user_data;
+
+       if (NULL == mdsc_noti_cb_list)
+               mdsc_noti_signal_ID = g_signal_connect(handle->conn,
+                       "changed-mode",
+                       G_CALLBACK(_on_changed_mode),
+                       NULL);
+       mdsc_noti_cb_list = g_list_append(mdsc_noti_cb_list, data);
 
        return MODES_ERROR_NONE;
 }
 
-//TODO: multi callbacks
-API void modes_unsubscribe_mode_changes(modes_h handle)
+API void modes_unsubscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data)
 {
        RET_IF(0 == mdsc_noti_signal_ID);
        RET_IF(NULL == handle);
        RET_IF(NULL == handle->conn);
 
-       g_signal_handler_disconnect(handle->conn, mdsc_noti_signal_ID);
-       mdsc_noti_signal_ID = 0;
-       mdsc_noti_data.cb = NULL;
-       mdsc_noti_data.user_data = NULL;
+       mdsc_noti_data_s search = { cb, user_data };
+       GList *found = g_list_find_custom(mdsc_noti_cb_list, &search, _compare_cb);
+       if (NULL == found) {
+               WARN("g_list_find_custom() Fail");
+               return;
+       }
+
+       mdsc_noti_data_s *data = found->data;
+       mdsc_noti_cb_list = g_list_remove(mdsc_noti_cb_list, found->data);
+       free(data);
+       if (NULL == mdsc_noti_cb_list) {
+               g_signal_handler_disconnect(handle->conn, mdsc_noti_signal_ID);
+               mdsc_noti_signal_ID = 0;
+       }
+
 }
index 24fb5b8670dab1684328288fd035d5cda558af5f..592075eca6b5f86c1945e7a45a90733418905a8c 100644 (file)
@@ -244,10 +244,13 @@ int modes_subscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_da
  * @brief stop recognizing the changed of mode.
  * @details Removes a function to be called when the mode is changed.
  * @since_tizen 6.0
+
+ * @param[in] cb The callback function to stop invoking
+ * @param[in] user_data The user data to pass to the function
  *
  * @see modes_subscribe_mode_changes()
  */
-void modes_unsubscribe_mode_changes(modes_h handle);
+void modes_unsubscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data);
 
 //TODO:it must be opaque type
 typedef struct {
index f488def54688cb7ab4ee8030f2dcee915afc2d53..fb7f738854e89bfa8c304d6c8c268e4098ef0b7e 100644 (file)
@@ -39,14 +39,14 @@ protected:
                int ret = modes_undo_mode(handle, (const char*)data);
                EXPECT_EQ(MODES_ERROR_NONE, ret);
 
-               return  G_SOURCE_REMOVE;
+               return G_SOURCE_REMOVE;
        }
 
        static int notiFunc(const char *modeName, int state, void *user_data)
        {
                char *requestMode = (char*)user_data;
 
-               std::cout << "Changed Mode : " << modeName << std::endl;
+               std::cout << "notiFunc Changed Mode : " << modeName << std::endl;
                EXPECT_EQ(requestMode, std::string(modeName));
                std::cout << "state : " << state << std::endl;
                EXPECT_EQ(expectedState, state);
@@ -60,7 +60,7 @@ protected:
        {
                char *requestMode = (char*)user_data;
 
-               std::cout << "Changed Mode : " << modeName << std::endl;
+               std::cout << "changeFn Changed Mode : " << modeName << std::endl;
                EXPECT_EQ(requestMode, std::string(modeName));
                std::cout << "state : " << state << std::endl;
 
@@ -69,14 +69,64 @@ protected:
 
                return MODES_ERROR_NONE;
        }
+
+       static int notiMultiFunc1(const char *modeName, int state, void *user_data)
+       {
+               std::cout << "notiMultiFunc1 Changed Mode : " << modeName << std::endl;
+               std::cout << "state : " << state << std::endl;
+
+               calledbit1 |= 0x1 << state;
+
+               return MODES_ERROR_NONE;
+       }
+
+       static int notiMultiFunc2(const char *modeName, int state, void *user_data)
+       {
+               std::cout << "notiMultiFunc2 Changed Mode : " << modeName << std::endl;
+               std::cout << "state : " << state << std::endl;
+
+               calledbit2 |= 0x1 << state;
+
+               return MODES_ERROR_NONE;
+       }
+
+       static int notiMultiFunc3(const char *modeName, int state, void *user_data)
+       {
+               std::cout << "notiMultiFunc3 Changed Mode : " << modeName << std::endl;
+               std::cout << "state : " << state << std::endl;
+
+               EXPECT_TRUE(NULL == user_data || notiTestMode == user_data);
+
+               if (NULL == user_data)
+                       calledbit3 |= 0x1 << state;
+               if (notiTestMode == user_data)
+                       calledbit4 |= 0x1 << state;
+
+               if (0x3 == calledbit3 && 0x3 == calledbit4)
+                       g_main_loop_quit(loop);
+
+               return MODES_ERROR_NONE;
+       }
+
+
        static modes_h handle;
        static int expectedState;
        static GMainLoop *loop;
+       static unsigned char calledbit1;
+       static unsigned char calledbit2;
+       static unsigned char calledbit3;
+       static unsigned char calledbit4;
+       static const char *notiTestMode;
 };
 
 modes_h ClientNotiTest::handle = NULL;
 int ClientNotiTest::expectedState = 1;
+unsigned char ClientNotiTest::calledbit1 = 0;
+unsigned char ClientNotiTest::calledbit2 = 0;
+unsigned char ClientNotiTest::calledbit3 = 0;
+unsigned char ClientNotiTest::calledbit4 = 0;
 GMainLoop *ClientNotiTest::loop = NULL;
+const char *ClientNotiTest::notiTestMode = "ex2";
 
 TEST_F(ClientNotiTest, notiConnect)
 {
@@ -92,7 +142,41 @@ TEST_F(ClientNotiTest, notiConnect)
 
        g_main_loop_run(loop);
 
-       modes_unsubscribe_mode_changes(handle);
+       modes_unsubscribe_mode_changes(handle, notiFunc, (void*)testMode);
+}
+TEST_F(ClientNotiTest, notiMultiCb)
+{
+       calledbit1 = 0;
+       calledbit2 = 0;
+       calledbit3 = 0;
+
+       int ret = modes_subscribe_mode_changes(handle, notiMultiFunc1, NULL);
+       EXPECT_EQ(MODES_ERROR_NONE, ret);
+
+       ret = modes_subscribe_mode_changes(handle, notiMultiFunc2, NULL);
+       EXPECT_EQ(MODES_ERROR_NONE, ret);
+
+       ret = modes_subscribe_mode_changes(handle, notiMultiFunc3, (void*)notiTestMode);
+       EXPECT_EQ(MODES_ERROR_NONE, ret);
+
+       ret = modes_subscribe_mode_changes(handle, notiMultiFunc3, NULL);
+       EXPECT_EQ(MODES_ERROR_NONE, ret);
+
+       ret = modes_apply_mode(handle, notiTestMode);
+       EXPECT_EQ(MODES_ERROR_NONE, ret);
+
+       g_timeout_add_seconds(1, undoTimeout, (void*)notiTestMode);
+       g_main_loop_run(loop);
+
+       modes_unsubscribe_mode_changes(handle, notiMultiFunc1, NULL);
+       modes_unsubscribe_mode_changes(handle, notiMultiFunc2, NULL);
+       modes_unsubscribe_mode_changes(handle, notiMultiFunc3, NULL);
+       modes_unsubscribe_mode_changes(handle, notiMultiFunc3, (void*)notiTestMode);
+
+       EXPECT_EQ(calledbit1, 1 << 0 | 1 << 1);
+       EXPECT_EQ(calledbit2, 1 << 0 | 1 << 1);
+       EXPECT_EQ(calledbit3, 1 << 0 | 1 << 1);
+       EXPECT_EQ(calledbit4, 1 << 0 | 1 << 1);
 }
 
 TEST_F(ClientNotiTest, essential)
@@ -106,5 +190,5 @@ TEST_F(ClientNotiTest, essential)
 
        g_main_loop_run(loop);
 
-       modes_unsubscribe_mode_changes(handle);
+       modes_unsubscribe_mode_changes(handle, changeFn, (void*)testMode);
 }