Update package version to 0.1.56
[platform/core/uifw/capi-ui-sticker.git] / receiver / src / ft.cpp
index d03495d..670d30c 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <pwd.h>
+#include <json-glib/json-glib.h>
+#include <vconf.h>
+#include <queue>
+#include <thumbnail_util.h>
+#include <Ecore.h>
+#include <app_preference.h>
 
+#include "ft.h"
 #include "log.h"
 #include "sticker_info.h"
+#include "../inc/sticker_data.h"
+#include "sticker_request.h"
+#include "message.h"
+#include "config.h"
+#include "receiver_preference.h"
 
-#define ACCESSORY_SERVICE_PROFILE_ID "/sample/filetransfersender"
+#define STICKER_SYNC_FEATURE_REQ "sticker-sync-feature-req"
+#define STICKER_SYNC_FEATURE_RSP "sticker-sync-feature-rsp"
+#define STICKER_REQUEST_SYNC_REQ "sticker-request-sync-req"
+#define STICKER_REQUEST_NOTI_REQ "sticker-request-noti-req"
+#define STICKER_SYNC_START_REQ "sticker-sync-start-req"
+#define STICKER_SYNC_START_RSP "sticker-sync-start-rsp"
+#define STICKER_SEND_START_REQ "sticker-send-start-req"
+#define STICKER_SEND_START_RSP "sticker-send-start-rsp"
+#define STICKER_SEND_FACE_DATA "sticker-send-face-data"
+#define STICKER_SEND_STOP_REQ  "sticker-send-stop-req"
+#define STICKER_SEND_STOP_RSP  "sticker-send-stop-rsp"
+#define STICKER_SEND_DISCONNECT_REQ "sticker-send-disconnect-req"
+
+#ifndef VCONFKEY_STICKER_SYNC_COMPLETE_DONE
+#define VCONFKEY_STICKER_SYNC_COMPLETE_DONE 0x1
+#endif
 
 using namespace std;
 
-struct priv {
+enum {
+    SYNC_START_RSP_SUCCESS = 1000,
+    SYNC_START_RSP_NO_STICKER = 1001,
+    SYNC_START_RSP_BITMOJI_ALL_DELETE = 1002,
+    SYNC_START_RSP_AREMOJI_ALL_DELETE = 1003,
+    SYNC_START_RSP_SYNC_AFTER_DELETING_AREMOJI = 1004
+};
+
+struct sap_info_s {
     sap_agent_h agent;
-    sap_file_transaction_h socket;
+    sap_socket_h socket;
+    sap_peer_agent_h peer_agent;
+    sap_file_transaction_h file_socket;
 };
 
-static struct priv priv_data = { 0 };
+static struct sap_info_s priv_data = { 0 };
+static struct sticker_info sticker_data;
+static queue<StickerRequest> ReqQueue;
+static StickerRequest current_request;
 
-gboolean file_on_progress = 0;
+static gboolean file_on_progress = FALSE;
 static string incoming_file_name;
-static string recv_filepath;
+static int t_id = 0;
+static int rec_file_cnt_in_group = 0;
+static int total_file_count_in_group = 0;
+static int sync_success_cnt = 0;
+static gboolean job_progress = FALSE;
+static int sync_complete_flags = 0;
 
-static void _on_send_completed(sap_file_transaction_h file_transaction,
-                               sap_ft_transfer_e result,
-                               const char *file_path,
-                               void *user_data)
+static void save_last_sync_time()
+{
+    // save last sync time in preference
+    double current_time = ecore_time_unix_get();
+    if (preference_set_double(LAST_SYNC_TIME, current_time) == PREFERENCE_ERROR_NONE) {
+        LOGI("Succeed to set last sync time : %f", current_time);
+    }
+    else {
+        LOGW("Failed to set last sync time");
+    }
+}
+
+static void set_sync_first_complete()
+{
+    int complete_flags = 0;
+    if (vconf_get_int(VCONFKEY_STICKER_SYNC_COMPLETE, &complete_flags) == 0 && complete_flags == 0) {
+        // first sync
+        if (vconf_set_int(VCONFKEY_STICKER_SYNC_COMPLETE, VCONFKEY_STICKER_SYNC_COMPLETE_DONE) == 0)
+            LOGD("Succeed to set sync complete");
+        else
+            LOGW("Fail to set sync complete");
+    }
+}
+
+static void set_sync_complete()
+{
+    set_sync_first_complete();
+    save_last_sync_time();
+}
+
+static void set_sync_progressing(gboolean flag)
 {
-    char error_message[100];
+    job_progress = flag;
+#ifdef VCONFKEY_STICKER_SYNC_STATE
+    LOGD("sync progressing : %d", flag);
+    if (vconf_set_int(VCONFKEY_STICKER_SYNC_STATE, flag ? VCONFKEY_STICKER_SYNC_STATE_IN_PROGRESS :  VCONFKEY_STICKER_SYNC_STATE_WAITING) == 0)
+        LOGD("Succeed to set sync state");
+    else
+        LOGW("Fail to set sync state");
+#else
+    LOGW("No vconf sync state definition");
+#endif
+}
+
+static gboolean _send_json_data(JsonObject *obj)
+{
+    JsonGenerator *j_generator = NULL;
+    JsonNode *j_node = NULL;
+    gsize size = 0;
+    gchar *data = NULL;
+    int result = 1;
+
+    j_generator = json_generator_new();
+    if (j_generator == NULL) {
+        LOGE("Unable to json_generator_new");
+        goto cleanup;
+    }
+
+    j_node = json_node_new(JSON_NODE_OBJECT);
+    if (j_node == NULL) {
+        LOGE("Unable to json_node_new");
+        goto cleanup;
+    }
+
+    json_node_set_object(j_node, obj);
+    json_generator_set_root(j_generator, j_node);
 
-    LOGI("# transfer completed");
+    data = json_generator_to_data(j_generator, &size);
+    if (data == NULL) {
+        LOGE("Unable to json_generator_to_data");
+        goto cleanup;
+    }
 
     if (priv_data.socket) {
+        LOGD("Send JSON data : %s", data);
+        result = sap_socket_send_data(priv_data.socket, ACCESSORY_SERVICE_CHANNEL_ID, strlen(data), (void *)data);
+    }
+
+cleanup:
+    if (data)
+        g_free(data);
+
+    if (j_node)
+        json_node_free(j_node);
+
+    if (j_generator)
+        g_object_unref(j_generator);
+
+    return result ? FALSE : TRUE;
+}
+
+static void notify_sync_progress(unsigned int file_progress)
+{
+    if (total_file_count_in_group == 0)
+        return;
+
+    LOGI("(%2d / %2d), file progress : %3u%%", rec_file_cnt_in_group+1, total_file_count_in_group, file_progress);
+    send_message("sync_progress", NULL);
+}
+
+static void _on_transfer_completed(sap_file_transaction_h file_transaction,
+                                   sap_ft_transfer_e result,
+                                   const char *file_path,
+                                   void *user_data)
+{
+    if (priv_data.file_socket) {
         sap_file_transfer_destroy(file_transaction);
-        priv_data.socket = NULL;
+        priv_data.file_socket = NULL;
     }
 
     if (result == SAP_FT_TRANSFER_SUCCESS) {
-        sprintf(error_message, "Transfer Completed");
         LOGI("Transfer Completed");
 
-        if (chmod(recv_filepath.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
-            LOGE("Failed to change permission : %s. error : %s", recv_filepath.c_str(), strerror(errno));
+        if (chmod(sticker_data.file_path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
+            LOGE("Failed to change permission : %s. error : %s", sticker_data.file_path.c_str(), strerror(errno));
         }
         else {
-            LOGI("Succeed to change permission : %s", recv_filepath.c_str());
-            if (create_sticker_provider_handle() == STICKER_ERROR_NONE) {
-                insert_sticker_data(recv_filepath.c_str(), "keyword", "group", "test icon");
-                destroy_sticker_provider_handle();
+            LOGI("Succeed to change permission : %s", sticker_data.file_path.c_str());
+            char thumb_path[PATH_MAX];
+            char *data_path = NULL;
+            data_path = app_get_shared_data_path();
+            snprintf(thumb_path, sizeof(thumb_path), "%s/thumbnail/%s", data_path, incoming_file_name.c_str());
+            sticker_data.thumbnail_path = string(thumb_path);
+
+            if (data_path)
+                free(data_path);
+
+            int ret = thumbnail_util_extract_to_file(sticker_data.file_path.c_str(), THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, sticker_data.thumbnail_path.c_str());
+            if (ret != THUMBNAIL_UTIL_ERROR_NONE) {
+                LOGE("Failed to create thumbnail. msg : %s", get_error_message(ret));
+                sticker_data.thumbnail_path.clear();
+            }
+
+            insert_sticker_data(sticker_data.file_path.c_str(), sticker_data.keyword.c_str(), sticker_data.group.c_str(), sticker_data.description.c_str(),
+                                sticker_data.thumbnail_path.c_str(), sticker_data.disp_type.c_str());
 
-                if (unlink(recv_filepath.c_str()) == -1)
-                    LOGE("Failed to remove sticker file");
+            if (unlink(sticker_data.file_path.c_str()) == -1)
+                LOGE("Failed to remove sticker file");
+
+            if (!sticker_data.thumbnail_path.empty()) {
+                if (unlink(sticker_data.thumbnail_path.c_str()) == -1)
+                    LOGE("Failed to remove sticker thumbnail");
             }
         }
+
+        rec_file_cnt_in_group++;
     } else {
         switch (result) {
             case (SAP_FT_TRANSFER_FAIL_CHANNEL_IO): {
-                sprintf(error_message, "Channel IO Error.");
                 LOGW("Channel IO Error.");
                 break;
             }
 
             case (SAP_FT_TRANSFER_FAIL_FILE_IO): {
-                sprintf(error_message, "File IO Error.");
                 LOGW("File IO Error.");
                 break;
             }
 
             case (SAP_FT_TRANSFER_FAIL_CMD_DROPPED):
             {
-                sprintf(error_message, "Transfer dropped.");
                 LOGW("Transfer dropped.");
                 break;
             }
 
             case (SAP_FT_TRANSFER_FAIL_PEER_UNRESPONSIVE):
             {
-                sprintf(error_message, "Peer Un Responsive.");
                 LOGW("Peer Un Responsive.");
                 break;
             }
 
             case (SAP_FT_TRANSFER_FAIL_PEER_CONN_LOST):
             {
-                sprintf(error_message, "Connection Lost.");
                 LOGW("Connection Lost.");
                 break;
             }
 
             case (SAP_FT_TRANSFER_FAIL_PEER_CANCELLED):
             {
-                sprintf(error_message, "Peer Cancelled.");
                 LOGW("Peer Cancelled.");
                 break;
             }
 
             case (SAP_FT_TRANSFER_FAIL_SPACE_NOT_AVAILABLE):
             {
-                sprintf(error_message, "No Space.");
                 LOGW("No Space.");
                 break;
             }
 
             default:
-                sprintf(error_message, "Unknown Error");
                 LOGW("Unknown Error");
                 break;
         }
     }
 
-    file_on_progress = 0;
+    file_on_progress = FALSE;
+    sticker_data.reset();
 }
 
-static void _on_sending_file_in_progress(sap_file_transaction_h file_transaction,
-                                         unsigned short int percentage_progress,
-                                         void *user_data)
+static void _on_transfer_file_in_progress(sap_file_transaction_h file_transaction,
+                                          unsigned short int percentage_progress,
+                                          void *user_data)
 {
-    LOGI("# progress %d", percentage_progress);
+    notify_sync_progress(percentage_progress);
 }
 
 static void __set_file_transfer_cb(sap_file_transaction_h file_socket)
 {
     LOGI("# set callbacks");
-    sap_file_transfer_set_progress_cb(file_socket, _on_sending_file_in_progress, NULL);
+    sap_file_transfer_set_progress_cb(file_socket, _on_transfer_file_in_progress, NULL);
 
-    sap_file_transfer_set_done_cb(file_socket, _on_send_completed, NULL);
+    sap_file_transfer_set_done_cb(file_socket, _on_transfer_completed, NULL);
+}
+
+bool get_job_progress()
+{
+    return job_progress;
 }
 
 void accept_file()
@@ -161,12 +319,14 @@ void accept_file()
 
     data_path = app_get_shared_data_path();
     LOGI("Path : %s", data_path);
-    sprintf(file_path, "%s/%s", data_path, incoming_file_name.c_str());
+    snprintf(file_path, sizeof(file_path), "%s/%s", data_path, incoming_file_name.c_str());
     LOGI("Receive filepath : %s", file_path);
-    recv_filepath = string(file_path);
-    free(data_path);
+    sticker_data.file_path = string(file_path);
+
+    if (data_path)
+        free(data_path);
 
-    ret = sap_file_transfer_receive(priv_data.socket, file_path);
+    ret = sap_file_transfer_receive(priv_data.file_socket, file_path);
     switch(ret) {
         case SAP_RESULT_PERMISSION_DENIED:
             LOGW("permission denied");
@@ -179,31 +339,247 @@ void accept_file()
             break;
     }
 
-    file_on_progress = 1;
+    file_on_progress = TRUE;
+}
+
+static int _create_thumbnail_directory()
+{
+    char thumb_path[PATH_MAX];
+    char *data_path = NULL;
+    data_path = app_get_shared_data_path();
+    snprintf(thumb_path, sizeof(thumb_path), "%s/thumbnail", data_path);
+
+    if (data_path)
+        free(data_path);
+
+    if (access(thumb_path, F_OK) == 0)
+        return 0;
+
+    if (mkdir(thumb_path, 0755) == -1) {
+        LOGE("directory create error");
+        return -1;
+    }
+
+    return 0;
+}
+
+bool request_sticker_data(const char *mode, const char *category, const char *type)
+{
+    bool result = false;
+    JsonObject *j_object = NULL;
+
+    if (!priv_data.socket) {
+        job_progress = TRUE;
+        StickerRequest pending_request;
+        pending_request.req_type = REQUEST_TYPE_SYNC;
+        pending_request.mode = string(mode ? mode : "manual");
+        pending_request.category = string(category ? category : "arsticker");
+        pending_request.type = string(type ? type : "input");
+
+        ReqQueue.push(pending_request);
+        LOGI("Push sync request");
+
+        return false;
+    }
+
+    j_object = json_object_new();
+    if (j_object == NULL) {
+        LOGE("json object create error");
+        return false;
+    }
+
+    if (_create_thumbnail_directory() != 0)
+        LOGE("Failed to create thumbnail directory");
+
+    json_object_set_string_member(j_object, "msgId", STICKER_SYNC_START_REQ);
+    json_object_set_int_member(j_object, "tID", ++t_id);
+    json_object_set_string_member(j_object, "mode", mode);
+    json_object_set_string_member(j_object, "category", category);
+    json_object_set_string_member(j_object, "type", type);
+
+    if (_send_json_data(j_object) == FALSE) {
+        LOGE("Failed to send STICKER_SYNC_START_REQ");
+        result = false;
+    }
+    else {
+        current_request.req_type = REQUEST_TYPE_SYNC;
+        current_request.mode = string(mode ? mode : "manual");
+        current_request.category = string(category ? category : "arsticker");
+        current_request.type = string(type ? type : "input");
+        set_sync_progressing(TRUE);
+        result = true;
+    }
+
+    json_object_unref(j_object);
+
+    return result;
+}
+
+static bool process_request_queue()
+{
+    if (ReqQueue.empty())
+        return false;
+
+    StickerRequest request = ReqQueue.front();
+
+    if (request.req_type == REQUEST_TYPE_FEATURE_REQ) {
+        LOGD("[Request feature exchange]");
+        request_sticker_feature();
+        ReqQueue.pop();
+    }
+    else if (request.req_type == REQUEST_TYPE_SYNC) {
+        LOGD("[Request to sync sticker] mode: %s, category: %s, type : %s", request.mode.c_str(),
+                request.category.c_str(),
+                request.type.c_str());
+
+        if (request_sticker_data(request.mode.c_str(), request.category.c_str(), request.type.c_str()))
+            ReqQueue.pop();
+    }
+    else if (request.req_type == REQUEST_TYPE_SHOW_NOTIFICATION) {
+        LOGD("[Request to show notification]");
+        request_show_sync_notification();
+        ReqQueue.pop();
+    }
+
+    return true;
 }
 
-void sap_file_transfer_get_receive_filepath(char **filepath)
+void request_all_sticker_data(const char *mode, const char *type)
 {
-    *filepath = strdup(recv_filepath.c_str());
+    StickerRequest pending_request;
+    pending_request.req_type = REQUEST_TYPE_SYNC;
+    pending_request.mode = string(mode);
+    pending_request.type = string(type);
+
+#ifdef VCONFKEY_STICKER_SUPPORTED_FEATURE
+    int feature_flag = 0;
+    if (vconf_get_int(VCONFKEY_STICKER_SUPPORTED_FEATURE, &feature_flag) == 0)
+    {
+        if (feature_flag & VCONFKEY_STICKER_FEATURE_AREMOJI) {
+            pending_request.category = string("arsticker");
+            ReqQueue.push(pending_request);
+        }
+
+        if (feature_flag & VCONFKEY_STICKER_FEATURE_BITMOJI) {
+            pending_request.category = string("bitmoji");
+            ReqQueue.push(pending_request);
+        }
+    }
+    else
+        LOGW("Failed to get value of VCONFKEY_STICKER_SUPPORTED_FEATURE");
+#else
+    pending_request.category = string("arsticker");
+    ReqQueue.push(pending_request);
+    pending_request.category = string("bitmoji");
+    ReqQueue.push(pending_request);
+#endif
+
+    if (priv_data.socket)
+        process_request_queue();
+}
+
+void request_sticker_feature()
+{
+    JsonObject *j_object = NULL;
+
+    if (!priv_data.socket) {
+        job_progress = TRUE;
+        StickerRequest pending_request;
+        pending_request.req_type = REQUEST_TYPE_FEATURE_REQ;
+        ReqQueue.push(pending_request);
+        LOGI("Push sync feature request");
+        return;
+    }
+
+    j_object = json_object_new();
+    if (j_object == NULL) {
+        LOGE("json object create error");
+        return;
+    }
+
+    json_object_set_string_member(j_object, "msgId", STICKER_SYNC_FEATURE_REQ);
+    json_object_set_int_member(j_object, "tID", ++t_id);
+
+    if (_send_json_data(j_object) == FALSE) {
+        LOGE("Failed to send STICKER_SYNC_FEATURE_REQ");
+    }
+    else {
+        job_progress = TRUE;
+    }
+
+    json_object_unref(j_object);
+
+    if (_create_thumbnail_directory() != 0)
+        LOGE("Failed to create thumbnail directory");
+}
+
+void send_disconnect_message()
+{
+    JsonObject *j_object = NULL;
+    j_object = json_object_new();
+    if (j_object == NULL) {
+        LOGE("json object create error");
+        return;
+    }
+
+    json_object_set_string_member(j_object, "msgId", STICKER_SEND_DISCONNECT_REQ);
+    json_object_set_int_member(j_object, "tID", t_id);
+
+    if (_send_json_data(j_object) == FALSE) {
+        LOGE("Failed to send STICKER_SEND_DISCONNECT_REQ");
+    }
+
+    json_object_unref(j_object);
+}
+
+void request_show_sync_notification()
+{
+    JsonObject *j_object = NULL;
+
+    if (!priv_data.socket) {
+        job_progress = TRUE;
+        StickerRequest pending_request;
+        pending_request.req_type = REQUEST_TYPE_SHOW_NOTIFICATION;
+        ReqQueue.push(pending_request);
+        LOGI("Push show notification request");
+        return;
+    }
+
+    j_object = json_object_new();
+    if (j_object == NULL) {
+        LOGE("json object create error");
+        return;
+    }
+
+    json_object_set_string_member(j_object, "msgId", STICKER_REQUEST_NOTI_REQ);
+    json_object_set_int_member(j_object, "tID", ++t_id);
+
+    if (_send_json_data(j_object) == FALSE) {
+        LOGE("Failed to send STICKER_REQUEST_NOTI_REQ");
+    } else {
+        job_progress = TRUE;
+    }
+
+    json_object_unref(j_object);
 }
 
 void reject_file()
 {
-    int ret = sap_file_transfer_reject(priv_data.socket);
+    int ret = sap_file_transfer_reject(priv_data.file_socket);
     LOGI("ret : %d", ret);
 
-    file_on_progress = 0;
+    file_on_progress = FALSE;
 }
 
-static void _on_receive_file_cb(sap_peer_agent_h peer_agent_h,
-                                sap_file_transaction_h socket,
-                                const char *file_path,
-                                void *user_data)
+static void _on_transfer_file_cb(sap_peer_agent_h peer_agent_h,
+                                 sap_file_transaction_h socket,
+                                 const char *file_path,
+                                 void *user_data)
 {
-    file_on_progress = 1;
-    priv_data.socket = socket;
+    file_on_progress = TRUE;
+    priv_data.file_socket = socket;
     LOGI("# incoming file request.");
-    __set_file_transfer_cb(priv_data.socket);
+    __set_file_transfer_cb(priv_data.file_socket);
 
     incoming_file_name = file_path;
     std::size_t found = incoming_file_name.find_last_of("/");
@@ -219,15 +595,377 @@ void conn_terminated(sap_peer_agent_h peer_agent,
                      sap_service_connection_terminated_reason_e result,
                      void *user_data)
 {
-    LOGI("connection terminated");
+    sap_info_s *priv = NULL;
+    priv = (sap_info_s *)user_data;
+
+    switch (result)
+    {
+    case SAP_CONNECTION_TERMINATED_REASON_PEER_DISCONNECTED:
+        LOGW("Peer Disconnected");
+        break;
+    case SAP_CONNECTION_TERMINATED_REASON_DEVICE_DETACHED:
+        LOGW("Disconnected Device Detached");
+        break;
+    case SAP_CONNECTION_TERMINATED_REASON_UNKNOWN:
+        LOGW("Disconnected Unknown Reason");
+        break;
+    default:
+        LOGW("connection terminated. reason : %d", result);
+        break;
+    }
+
+    sap_socket_destroy(priv->socket);
+    priv->socket = NULL;
+
+    set_sync_progressing(FALSE);
+    send_message("sync_stop_result", "cancel");
+    service_app_exit();
+}
+
+static void quit()
+{
+    job_progress = FALSE;
+    send_disconnect_message();
     service_app_exit();
 }
 
+static void send_sync_start_response(int result_code)
+{
+    int feature_flag = 0;
+    string response_to_app;
+    switch (result_code) {
+        case SYNC_START_RSP_SUCCESS:
+        {
+            response_to_app = "success";
+            if (current_request.category == string("arsticker"))
+                sync_complete_flags |= VCONFKEY_STICKER_FEATURE_AREMOJI;
+            else if (current_request.category == string("bitmoji"))
+                sync_complete_flags |= VCONFKEY_STICKER_FEATURE_BITMOJI;
+        }
+        break;
+        case SYNC_START_RSP_NO_STICKER:
+            response_to_app = "no_sticker";
+            break;
+        case SYNC_START_RSP_BITMOJI_ALL_DELETE:
+        {
+            int is_synced = 0;
+            if (vconf_get_int(VCONFKEY_STICKER_SYNC_COMPLETE, &is_synced) != 0)
+                LOGW("Failed to read sync completion");
+
+            if (is_synced == VCONFKEY_STICKER_SYNC_COMPLETE_NONE)
+                response_to_app = "no_sticker";
+            else
+                response_to_app = "success";
+            break;
+        }
+        case SYNC_START_RSP_AREMOJI_ALL_DELETE:
+            response_to_app = "success";
+            break;
+        case SYNC_START_RSP_SYNC_AFTER_DELETING_AREMOJI:
+            response_to_app = "success";
+            break;
+        default:
+            response_to_app = "unknown_error";
+            break;
+    }
+
+    LOGD("result code : %d, sync complete flag : %d", result_code, sync_complete_flags);
+
+#ifdef VCONFKEY_STICKER_SUPPORTED_FEATURE
+    if (vconf_get_int(VCONFKEY_STICKER_SUPPORTED_FEATURE, &feature_flag) != 0)
+    {
+        LOGW("Failed to read support feature");
+        return;
+    }
+
+    LOGD("feature : %d, current request category : %s", feature_flag, current_request.category.c_str());
+    if (feature_flag == VCONFKEY_STICKER_FEATURE_AREMOJI ||
+        feature_flag == VCONFKEY_STICKER_FEATURE_BITMOJI)
+    {
+        LOGD("only standalone sync mode");
+        send_message("sync_start_response", response_to_app.c_str());
+    }
+    else {
+        if (current_request.category == string("arsticker"))
+        {
+            if (result_code == SYNC_START_RSP_SUCCESS)
+                send_message("sync_start_response", response_to_app.c_str());
+        }
+        else if (current_request.category == string("bitmoji"))
+        {
+            if (sync_complete_flags == 0 ||
+                sync_complete_flags == VCONFKEY_STICKER_FEATURE_BITMOJI)
+                send_message("sync_start_response", response_to_app.c_str());
+        }
+    }
+#endif
+}
+
 void
 on_data_received(sap_socket_h socket, unsigned short int channel_id, unsigned int payload_length, void *buffer,
                  void *user_data) /* message exchange on_receive callback (sap_agent_data_received_cb) */
 {
-    LOGI("received data: %s, len:%d", (char *)buffer, payload_length);
+    unsigned int buf_len = strlen((char *)buffer);
+    LOGI("received data: %s, len: %d, buffer len : %d", (char *)buffer, payload_length, buf_len);
+
+    JsonParser *parser = json_parser_new();
+    GError *err_msg = NULL;
+    JsonNode *root = NULL;
+    JsonObject *root_obj = NULL;
+    string msg_id;
+    const char *json_msgid = NULL;
+
+    json_parser_load_from_data(parser, (char *)buffer, payload_length, &err_msg);
+    if (err_msg) {
+        LOGE("failed to load json file. error message: %s", err_msg->message);
+        goto cleanup;
+    }
+
+    root = json_parser_get_root(parser);
+    if (root == NULL) {
+        LOGE("failed to get root");
+        goto cleanup;
+    }
+
+    root_obj = json_node_get_object(root);
+    if (root_obj == NULL) {
+        LOGE("failed to get object");
+        goto cleanup;
+    }
+
+    json_msgid = json_object_get_string_member(root_obj, "msgId");
+    msg_id = string(json_msgid ? json_msgid : "");
+    if (msg_id == STICKER_REQUEST_SYNC_REQ) {
+        request_all_sticker_data("manual", "input");
+    } else if (msg_id == STICKER_SYNC_FEATURE_RSP) {
+        LOGD("msg : %s", msg_id.c_str());
+#ifdef VCONFKEY_STICKER_SUPPORTED_FEATURE
+        const char *json_aremoji = json_object_get_string_member(root_obj, "arEmoji");
+        const char *json_bitmoji = json_object_get_string_member(root_obj, "bitmoji");
+        string support_aremoji = string(json_aremoji ? json_aremoji : "");
+        string support_bitmoji = string(json_bitmoji ? json_bitmoji : "");
+        int supported_feature = VCONFKEY_STICKER_FEATURE_NONE;
+
+        if (support_aremoji == "support")
+            supported_feature |= VCONFKEY_STICKER_FEATURE_AREMOJI;
+
+        if (support_bitmoji == "support")
+            supported_feature |= VCONFKEY_STICKER_FEATURE_BITMOJI;
+
+        if (vconf_set_int(VCONFKEY_STICKER_SUPPORTED_FEATURE, supported_feature) == 0)
+            LOGD("Succeed to set supported feature");
+        else
+            LOGW("Fail to set supported feature");
+#else
+        LOGW("No vconf supported feature");
+#endif
+
+        if (!process_request_queue()) {
+            quit();
+        }
+    } else if (msg_id == STICKER_SYNC_START_RSP) {
+        LOGD("msg : %s", msg_id.c_str());
+        const char *json_result = json_object_get_string_member(root_obj, "result");
+        string result = string(json_result ? json_result : "");
+        int result_code = json_object_get_int_member(root_obj, "resultCode");
+        LOGD("result : %s, resultCode : %d", result.c_str(), result_code);
+
+        if(result_code == SYNC_START_RSP_SUCCESS) {
+            send_sync_start_response(result_code);
+            if (current_request.category == string("bitmoji")) {
+                LOGD("Delete all bitmoji stickers");
+                delete_all_stickers("bitmoji");
+            }
+        } else if (result_code == SYNC_START_RSP_SYNC_AFTER_DELETING_AREMOJI) {
+            send_sync_start_response(result_code);
+            LOGD("Delete all AR Emoji stickers");
+            delete_all_stickers("arsticker");
+        } else {
+            if (result_code == SYNC_START_RSP_BITMOJI_ALL_DELETE) {
+                LOGD("Delete all bitmoji stickers");
+                delete_all_stickers("bitmoji");
+            } else if (result_code == SYNC_START_RSP_AREMOJI_ALL_DELETE) {
+                LOGD("Delete all AR Emoji stickers");
+                delete_all_stickers("arsticker");
+            }
+
+            if (!process_request_queue()) {
+#ifdef VCONFKEY_STICKER_SUPPORTED_FEATURE
+                int feature_flag = 0;
+
+                if (vconf_get_int(VCONFKEY_STICKER_SUPPORTED_FEATURE, &feature_flag) == 0)
+                {
+                    LOGD("feature : %d, current request category : %s", feature_flag, current_request.category.c_str());
+                    if (feature_flag & VCONFKEY_STICKER_FEATURE_BITMOJI)
+                    {
+                        if (current_request.category == string("bitmoji"))
+                        {
+                            /* other sticker group(s) has been synchronized completely */
+                            if (sync_success_cnt > 0) {
+                                set_sync_complete();
+                            }
+                        }
+                    }
+                }
+                else {
+                    LOGW("Failed to read support feature");
+                }
+#else
+                LOGW("No vconf supported feature");
+#endif /* VCONFKEY_STICKER_SUPPORTED_FEATURE */
+
+                send_sync_start_response(result_code);
+                set_sync_progressing(FALSE);
+                save_last_sync_time();
+
+                quit();
+            }
+        }
+    } else if (msg_id == STICKER_SEND_START_REQ) {
+        LOGD("msg : %s", msg_id.c_str());
+        total_file_count_in_group = 0;
+        rec_file_cnt_in_group = 0;
+        t_id = json_object_get_int_member(root_obj, "tID");
+        JsonArray *file_list = json_object_get_array_member(root_obj, "list");
+        if (file_list) {
+            int arr_len = json_array_get_length(file_list);
+            for (int i = 0; i < arr_len; i++) {
+                JsonObject *file_obj = json_array_get_object_element(file_list, i);
+                int file_len = json_object_get_int_member(file_obj, "size");
+                const char *json_filename = json_object_get_string_member(file_obj, "fileName");
+                string file_name = string(json_filename ? json_filename : "");
+
+                if (file_len > 0) {
+                    LOGD("Add file : %s, len : %d", file_name.c_str(), file_len);
+                    total_file_count_in_group++;
+                } else {
+                    char *app_id = NULL;
+                    char file_path[PATH_MAX];
+                    char del_path[PATH_MAX];
+                    std::size_t found = file_name.find_last_of("/");
+                    string del_file_name = file_name.substr(found+1);
+                    char *data_path = app_get_shared_data_path();
+                    app_get_id(&app_id);
+                    snprintf(file_path, sizeof(file_path), "%s/%s", data_path, del_file_name.c_str());
+                    snprintf(del_path, sizeof(del_path), "%s/%s%s",STICKER_DIRECTORY, app_id, file_path);
+
+                    LOGD("Delete file : %s, len : %d", del_path, file_len);
+                    delete_sticker_data(del_path);
+
+                    if (app_id)
+                        free(app_id);
+                }
+            }
+        }
+
+        JsonObject *j_object = json_object_new();
+        if (j_object == NULL) {
+            LOGE("Unable to json_object_new");
+            goto cleanup;
+        }
+
+        json_object_set_string_member(j_object, "msgId", STICKER_SEND_START_RSP);
+        json_object_set_int_member(j_object, "tID", t_id);
+        json_object_set_string_member(j_object, "result", "success");
+
+        if (_send_json_data(j_object) == FALSE)
+            LOGE("Failed to send message");
+
+        json_object_unref(j_object);
+    } else if (msg_id == STICKER_SEND_FACE_DATA) {
+        LOGD("msg : %s", msg_id.c_str());
+        const char *type_data = json_object_get_string_member(root_obj, "type");
+        if (type_data)
+            sticker_data.disp_type = string(type_data);
+
+        const char *category = json_object_get_string_member(root_obj, "category");
+        if (category) {
+            sticker_data.group = string(category);
+            sticker_data.keyword = string(category);
+        }
+    } else if (msg_id == STICKER_SEND_STOP_REQ) {
+        LOGD("msg : %s", msg_id.c_str());
+        const char *json_reason = json_object_get_string_member(root_obj, "reason");
+        string reason = string(json_reason ? json_reason : "");
+        int file_len = json_object_get_int_member(root_obj, "count");
+
+        JsonObject *j_object = json_object_new();
+        if (j_object == NULL) {
+            LOGE("Unable to json_object_new");
+            goto cleanup;
+        }
+
+        json_object_set_string_member(j_object, "msgId", STICKER_SEND_STOP_RSP);
+        json_object_set_int_member(j_object, "tID", t_id);
+
+        if (reason == "complete") {
+            if (rec_file_cnt_in_group == file_len) {
+#ifdef VCONFKEY_STICKER_SUPPORTED_FEATURE
+                int feature_flag = 0;
+
+                if (vconf_get_int(VCONFKEY_STICKER_SUPPORTED_FEATURE, &feature_flag) == 0)
+                {
+                    LOGD("feature : %d, current request category : %s", feature_flag, current_request.category.c_str());
+                    if (feature_flag == VCONFKEY_STICKER_FEATURE_AREMOJI)
+                    {
+                        if (current_request.category == string("arsticker"))
+                        {
+                            set_sync_complete();
+                            set_sync_progressing(FALSE);
+                        }
+                    }
+                    else if (feature_flag & VCONFKEY_STICKER_FEATURE_BITMOJI)
+                    {
+                        if (current_request.category == string("bitmoji"))
+                        {
+                            set_sync_complete();
+                            set_sync_progressing(FALSE);
+                        }
+                    }
+                }
+                else {
+                    LOGW("Failed to read support feature");
+                }
+#else
+                LOGW("No vconf supported feature");
+#endif /* VCONFKEY_STICKER_SUPPORTED_FEATURE */
+
+                json_object_set_string_member(j_object, "result", "success");
+                sync_success_cnt++;
+            }
+            else {
+                json_object_set_string_member(j_object, "result", "failure");
+            }
+        }
+        else {
+            json_object_set_string_member(j_object, "result", "failure");
+        }
+
+        if (_send_json_data(j_object) == FALSE)
+            LOGE("Failed to send message");
+
+        json_object_unref(j_object);
+
+        send_message("sync_stop_result", reason.c_str());
+
+        current_request.mode.clear();
+        current_request.category.clear();
+        current_request.type.clear();
+
+        if (!process_request_queue()) {
+            sync_success_cnt = 0;
+
+            quit();
+        }
+    } else
+        LOGW("unknown msg id : %s", msg_id.c_str());
+
+cleanup:
+    if (err_msg)
+        g_error_free(err_msg);
+
+    if (parser)
+        g_object_unref(parser);
 }
 
 static void on_conn_req(sap_peer_agent_h peer_agent,
@@ -235,10 +973,170 @@ static void on_conn_req(sap_peer_agent_h peer_agent,
                         sap_service_connection_result_e result,
                         void *user_data)
 {
-    sap_peer_agent_accept_service_connection(peer_agent);
-    sap_peer_agent_set_service_connection_terminated_cb(peer_agent, conn_terminated, NULL);
+    switch (result)
+    {
+    case SAP_CONNECTION_SUCCESS:
+        LOGI("Connection success");
+        priv_data.socket = socket;
+        sap_peer_agent_accept_service_connection(peer_agent);
+        sap_peer_agent_set_service_connection_terminated_cb(peer_agent, conn_terminated, &priv_data);
+        sap_socket_set_data_received_cb(socket, on_data_received, peer_agent);
+        break;
+    case SAP_CONNECTION_ALREADY_EXIST:
+        priv_data.socket = socket;
+        LOGI("Connection Already Exist");
+        break;
+    case SAP_CONNECTION_FAILURE_DEVICE_UNREACHABLE:
+        LOGW("Connection failure device unreachable");
+        break;
+    case SAP_CONNECTION_FAILURE_INVALID_PEERAGENT:
+        LOGW("Connection failure invalid peer agent");
+        break;
+    case SAP_CONNECTION_FAILURE_NETWORK:
+        LOGW("Connection failure network");
+        break;
+    case SAP_CONNECTION_FAILURE_PEERAGENT_NO_RESPONSE:
+        LOGW("Connection failure peer agent no response");
+        break;
+    case SAP_CONNECTION_FAILURE_PEERAGENT_REJECTED:
+        LOGW("Connection failure peer agent rejected");
+        break;
+    case SAP_CONNECTION_FAILURE_UNKNOWN:
+        LOGW("Connection failure unknown");
+        break;
+    default:
+        LOGW("Connection failure. error code : %d", result);
+        break;
+    }
+}
+
+static void
+_on_service_connection_created(sap_peer_agent_h peer_agent,
+                               sap_socket_h socket,
+                               sap_service_connection_result_e result,
+                               void *user_data)
+{
+    sap_info_s *priv = (sap_info_s *)user_data;
+
+    switch (result)
+    {
+    case SAP_CONNECTION_SUCCESS:
+        sap_peer_agent_set_service_connection_terminated_cb(priv->peer_agent,
+                                                            conn_terminated,
+                                                            priv);
+
+        sap_socket_set_data_received_cb(socket, on_data_received, peer_agent);
+        priv->socket = socket;
+        LOGI("Connection Established");
+
+        process_request_queue();
+
+        break;
+
+    case SAP_CONNECTION_ALREADY_EXIST:
+        priv->socket = socket;
+        LOGI("Connection Already Exist");
+        break;
+
+    case SAP_CONNECTION_FAILURE_DEVICE_UNREACHABLE:
+        LOGW("Connection Failure device unreachable");
+        break;
+
+    case SAP_CONNECTION_FAILURE_INVALID_PEERAGENT:
+        LOGW("Connection Failure invalid peer agent");
+        break;
+
+    case SAP_CONNECTION_FAILURE_NETWORK:
+        LOGW("Connection Failure network");
+        break;
+
+    case SAP_CONNECTION_FAILURE_PEERAGENT_NO_RESPONSE:
+        LOGW("Connection Failure peer agent no response");
+        break;
+
+    case SAP_CONNECTION_FAILURE_PEERAGENT_REJECTED:
+        LOGW("Connection Failure peer agent rejected");
+        break;
+
+    case SAP_CONNECTION_FAILURE_UNKNOWN:
+        LOGW("Connection Failure peer agent unknown");
+        break;
+
+    case SAP_CONNECTION_IN_PROGRESS:
+        LOGW("Connection in progress");
+        break;
+
+    case SAP_CONNECTION_PEER_AGENT_NOT_SUPPORTED:
+        LOGW("Connection peer agent not supported");
+        break;
+    }
+}
+
+static gboolean
+_create_service_connection(gpointer user_data)
+{
+    sap_info_s *priv = (sap_info_s *)user_data;
+    int result = sap_agent_request_service_connection(priv->agent,
+                                                      priv->peer_agent,
+                                                      _on_service_connection_created,
+                                                      priv);
+
+    LOGD("request connection result : %d", result);
 
-    sap_socket_set_data_received_cb(socket, on_data_received, peer_agent);
+    return FALSE;
+}
+
+static void
+_on_peer_agent_updated(sap_peer_agent_h peer_agent,
+                       sap_peer_agent_status_e peer_status,
+                       sap_peer_agent_found_result_e result,
+                       void *user_data)
+{
+    sap_info_s *priv = (sap_info_s *)user_data;
+
+    switch (result)
+    {
+    case SAP_PEER_AGENT_FOUND_RESULT_DEVICE_NOT_CONNECTED:
+        LOGW("SAP_PEER_AGENT_FOUND_RESULT_DEVICE_NOT_CONNECTED");
+        break;
+
+    case SAP_PEER_AGENT_FOUND_RESULT_FOUND:
+        if (peer_status == SAP_PEER_AGENT_STATUS_AVAILABLE)
+        {
+            LOGD("SAP_PEER_AGENT_FOUND_RESULT_FOUND");
+            priv->peer_agent = peer_agent;
+            g_idle_add(_create_service_connection, priv);
+        }
+        else
+        {
+            sap_peer_agent_destroy(peer_agent);
+        }
+        break;
+
+    case SAP_PEER_AGENT_FOUND_RESULT_SERVICE_NOT_FOUND:
+        LOGW("SAP_PEER_AGENT_FOUND_RESULT_SERVICE_NOT_FOUND");
+        break;
+
+    case SAP_PEER_AGENT_FOUND_RESULT_TIMEDOUT:
+        LOGW("SAP_PEER_AGENT_FOUND_RESULT_TIMEDOUT");
+        break;
+
+    case SAP_PEER_AGENT_FOUND_RESULT_INTERNAL_ERROR:
+        LOGW("SAP_PEER_AGENT_FOUND_RESULT_INTERNAL_ERROR");
+        break;
+
+    default:
+        break;
+    }
+}
+
+static gboolean
+_find_peer_agent(gpointer user_data)
+{
+    sap_info_s *priv = (sap_info_s *)user_data;
+    sap_agent_find_peer_agent(priv->agent, _on_peer_agent_updated, priv);
+
+    return FALSE;
 }
 
 static void on_agent_initialized(sap_agent_h agent,
@@ -251,7 +1149,7 @@ static void on_agent_initialized(sap_agent_h agent,
 
             priv_data.agent = agent;
 
-            sap_file_transfer_set_incoming_file_cb(agent, _on_receive_file_cb, NULL);
+            sap_file_transfer_set_incoming_file_cb(agent, _on_transfer_file_cb, NULL);
             sap_agent_set_service_connection_requested_cb(agent, on_conn_req, NULL);
 
             break;
@@ -307,9 +1205,11 @@ static void _on_device_status_changed(sap_device_status_e status,
     switch (status) {
         case SAP_DEVICE_STATUS_DETACHED:
             LOGD("device is not connected.");
+            send_message("sync_stop_result", "cancel");
             break;
         case SAP_DEVICE_STATUS_ATTACHED:
             LOGD("Attached calling find peer now");
+            g_idle_add(_find_peer_agent, &priv_data);
             break;
         default:
             LOGE("unknown status (%d)", status);
@@ -335,6 +1235,11 @@ gboolean initialize_sap(void)
 {
     sap_agent_h agent = NULL;
 
+    if (priv_data.agent) {
+        LOGW("duplicate initialize");
+        return FALSE;
+    }
+
     sap_agent_create(&agent);
 
     priv_data.agent = agent;
@@ -348,6 +1253,7 @@ gboolean initialize_sap(void)
 
 void deinitialize_sap(void)
 {
+    LOGD("deinitialize");
     if (priv_data.agent) {
         int ret = sap_agent_deinitialize(priv_data.agent, on_agent_deinitialized, NULL);
         switch (ret) {
@@ -369,3 +1275,8 @@ void deinitialize_sap(void)
         priv_data.agent = NULL;
     }
 }
+
+gboolean is_init_sap()
+{
+    return priv_data.agent ? TRUE : FALSE;
+}
\ No newline at end of file