[Callhistory] Added listeners implementation.
authorTomasz Marciniak <t.marciniak@samsung.com>
Sat, 13 Dec 2014 14:54:50 +0000 (15:54 +0100)
committerTomasz Marciniak <t.marciniak@samsung.com>
Tue, 16 Dec 2014 09:28:09 +0000 (10:28 +0100)
[Verification] Code compiles without errors.
onadded, onchanged and onremoved are called.

Change-Id: I324600be3c6df5af8bbd0e3e2831208929cfdf39
Signed-off-by: Tomasz Marciniak <t.marciniak@samsung.com>
src/callhistory/callhistory.cc
src/callhistory/callhistory.h
src/callhistory/callhistory_api.js
src/callhistory/callhistory_extension.cc
src/callhistory/callhistory_instance.cc
src/callhistory/callhistory_instance.h
src/callhistory/callhistory_types.h [new file with mode: 0644]
src/callhistory/callhistory_utils.cc
src/callhistory/callhistory_utils.h

index 25870925161c397415a61cdb966bc3f9f21ce09f..c941eb29533f79f45c019b208f3149acf55d25c0 100644 (file)
@@ -4,15 +4,75 @@
 
 #include "callhistory.h"
 
+#include <tapi_common.h>
+#include <ITapiSim.h>
+
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include "callhistory_instance.h"
+#include "callhistory_types.h"
+#include "callhistory_utils.h"
+
+using namespace common;
+
 namespace extension {
 namespace callhistory {
 
-CallHistory::CallHistory()
+namespace {
+static void get_sim_msisdn_cb(TapiHandle *handle, int result, void *data, void *user_data)
 {
+    LoggerD("Entered");
+
+    TelSimMsisdnList_t *list;
+    std::promise<std::string> *prom = reinterpret_cast<std::promise<std::string> *>(user_data);
+    char *number = NULL;
+
+    if (TAPI_SIM_ACCESS_SUCCESS == result) {
+        list = static_cast<TelSimMsisdnList_t *>(data);
+        if (list->count) {
+            number = list->list[0].num;
+        }
+        LoggerD("Phone number: %s", number);
+    } else {
+        LoggerE("Failed to access sim: %d", result);
+    }
+
+    std::string n = number ? std::string(number) : "";
+    prom->set_value(n);
+}
+}
+
+CallHistory::CallHistory():
+        m_is_listener_set(false)
+{
+    LoggerD("Entered");
+    if (CONTACTS_ERROR_NONE == contacts_connect()) {
+        LoggerD("Successful to connect Call history DB");
+    } else {
+        LoggerD("Failed to connect Call history DB");
+    }
+
+    loadPhoneNumbers();
 }
 
 CallHistory::~CallHistory()
 {
+    LoggerD("Entered");
+
+    if (m_is_listener_set) {
+        int ret = contacts_db_remove_changed_cb_with_info(_contacts_phone_log._uri,
+                changeListenerCB, NULL);
+
+        if (CONTACTS_ERROR_NONE != ret) {
+            LoggerW("Failed to remove ChangeListener");
+        }
+    }
+
+    if (CONTACTS_ERROR_NONE == contacts_disconnect()) {
+        LoggerD("Successful to disconnect Call history DB");
+    } else {
+        LoggerD("Failed to disconnect Call history DB");
+    }
 }
 
 CallHistory* CallHistory::getInstance(){
@@ -40,14 +100,199 @@ void CallHistory::removeAll()
 
 }
 
-long CallHistory::addChangeListener()
+std::vector<std::string>& CallHistory::getPhoneNumbers()
+{
+    return m_phone_numbers;
+}
+
+void CallHistory::changeListenerCB(const char* view_uri, char *changes, void* user_data)
 {
+    LoggerD("Entered");
+
+    if (NULL == changes) {
+        LoggerW("changes is NULL");
+        return;
+    }
+    if (0 == strlen(changes)) {
+        LoggerW("changes is empty");
+        return;
+    }
+
+    char seps[] = ",:";
+    char* token_type = NULL;
+    char* token_id = NULL;
+    int change_type = 0;
+    int change_id = 0;
+
+    picojson::value added = picojson::value(picojson::object());
+    picojson::object& added_obj = added.get<picojson::object>();
+    picojson::array& added_array = added_obj.insert(std::make_pair(STR_DATA, picojson::value(
+                                   picojson::array()))).first->second.get<picojson::array>();
+
+    picojson::value changed = picojson::value(picojson::object());
+    picojson::object& changed_obj = changed.get<picojson::object>();
+    picojson::array& changed_array = changed_obj.insert(std::make_pair(STR_DATA, picojson::value(
+                                     picojson::array()))).first->second.get<picojson::array>();
+
+    picojson::value removed = picojson::value(picojson::object());
+    picojson::object& removed_obj = removed.get<picojson::object>();
+    picojson::array& removed_array = removed_obj.insert(std::make_pair(STR_DATA, picojson::value(
+                                     picojson::array()))).first->second.get<picojson::array>();
+
+    token_type = strtok(changes, seps);
+    while (NULL != token_type) {
+        token_id = strtok(NULL, seps);
+        change_type = atoi((const char*)token_type);
+
+        if (NULL != token_id) {
+            change_id = atoi((const char*)token_id);
+        } else {
+            LoggerD("There is no (more) changed Item : %s", token_id);
+            break;
+        }
+
+        contacts_query_h query = NULL;
+        contacts_filter_h filter = NULL;
+        contacts_list_h record_list = NULL;
+        int ret = CONTACTS_ERROR_NONE;
 
+        contacts_query_create(_contacts_phone_log._uri, &query);
+        contacts_filter_create(_contacts_phone_log._uri, &filter);
+        contacts_filter_add_int(filter, _contacts_phone_log.id, CONTACTS_MATCH_EQUAL, change_id);
+
+        contacts_query_set_filter(query, filter);
+        ret = contacts_query_set_sort(query, _contacts_phone_log.id, false);
+        if (CONTACTS_ERROR_NONE != ret) {
+            LoggerD("Callhistory query error: %d", ret);
+        }
+
+        ret = contacts_db_get_records_with_query(query, 0, 1, &record_list);
+        if (CONTACTS_ERROR_NONE != ret) {
+            contacts_list_destroy(record_list, true);
+            contacts_query_destroy(query);
+            contacts_filter_destroy(filter);
+            LoggerD("Callhistory query error: %d", ret);
+            return;
+        }
+
+        if (CONTACTS_CHANGE_INSERTED == change_type) {
+            CallHistoryUtils::parseRecordList(&record_list, added_array);
+        } else if (CONTACTS_CHANGE_UPDATED == change_type) {
+            CallHistoryUtils::parseRecordList(&record_list, changed_array);
+        } else if (CONTACTS_CHANGE_DELETED == change_type) {
+            removed_array.push_back(picojson::value(token_id));
+        }
+
+        contacts_list_destroy(record_list, true);
+        contacts_query_destroy(query);
+        contacts_filter_destroy(filter);
+
+        token_type = strtok( NULL, seps);
+    }
+
+    if (added_array.size() > 0) {
+        added_obj[STR_ACTION] = picojson::value("onadded");
+        CallHistoryInstance::getInstance().CallHistoryChange(added_obj);
+    }
+    if (changed_array.size() > 0) {
+        changed_obj[STR_ACTION] = picojson::value("onchanged");
+        CallHistoryInstance::getInstance().CallHistoryChange(changed_obj);
+    }
+    if (removed_array.size() > 0) {
+        removed_obj[STR_ACTION] = picojson::value("onremoved");
+        CallHistoryInstance::getInstance().CallHistoryChange(removed_obj);
+    }
+}
+
+void CallHistory::startCallHistoryChangeListener()
+{
+    LoggerD("Entered");
+
+    if (!m_is_listener_set) {
+        int ret = contacts_db_add_changed_cb_with_info(_contacts_phone_log._uri,
+                changeListenerCB, NULL);
+
+        if (CONTACTS_ERROR_NONE != ret) {
+            LoggerE("Failed to add ChangeListener");
+            throw UnknownException("Failed to add ChangeListener");
+        }
+    }
+
+    m_is_listener_set = true;
 }
 
-void CallHistory::removeChangeListener()
+void CallHistory::stopCallHistoryChangeListener()
 {
+    LoggerD("Entered");
+    if (m_is_listener_set) {
+        int ret = contacts_db_remove_changed_cb_with_info(_contacts_phone_log._uri,
+                changeListenerCB, NULL);
+
+        if (CONTACTS_ERROR_NONE != ret) {
+            LoggerE("Failed to remove ChangeListener");
+            throw UnknownException("Failed to remove ChangeListener");
+        }
+    }
+
+    m_is_listener_set = false;
+}
+
+void CallHistory::loadPhoneNumbers()
+{
+    LoggerD("Entered");
+
+    char **cp_list = NULL;
+    cp_list = tel_get_cp_name_list();
+
+    if (!cp_list) {
+        LoggerE("Failed to get cp name list.");
+        return;
+    }
+
+    unsigned int modem_num = 0;
+    while (cp_list[modem_num]) {
+        std::string n = "";
+        TapiHandle* handle;
+        do {
+            std::promise<std::string> prom;
+            handle = tel_init(cp_list[modem_num]);
+            if (!handle) {
+                LoggerE("Failed to init tapi handle.");
+                break;
+            }
+
+            int card_changed;
+            TelSimCardStatus_t card_status;
+            int ret = tel_get_sim_init_info(handle, &card_status, &card_changed);
+            if (TAPI_API_SUCCESS != ret) {
+                LoggerE("Failed to get sim init info: %d", ret);
+                break;
+            }
+            LoggerD("Card status: %d Card Changed: %d", card_status, card_changed);
+            if (TAPI_SIM_STATUS_SIM_INIT_COMPLETED != card_status) {
+                LoggerW("SIM is not ready, we can't get other properties");
+                break;
+            }
+
+            ret = tel_get_sim_msisdn(handle, get_sim_msisdn_cb, &prom);
+            if (TAPI_API_SUCCESS != ret) {
+                LoggerE("Failed to get msisdn : %d", ret);
+                break;
+            }
+
+            auto fut = prom.get_future();
+            LoggerD("wait...");
+            fut.wait();
+            n = fut.get();
+            LoggerD("Phone number [%d] : %s", modem_num, n.c_str());
+        } while(false);
+
+        m_phone_numbers.push_back(n);
+        tel_deinit(handle);
+        modem_num++;
+    }
 
+    g_strfreev(cp_list);
 }
 
 } // namespace callhistory
index 45a6ed22210583b7cd0aa29b78897a8f7a9dd2ea..2f4dcd11dc654e6c90256302fd571e7d69568c29 100644 (file)
@@ -5,25 +5,39 @@
 #ifndef CALLHISTORY_CALLHISTORY_H_
 #define CALLHISTORY_CALLHISTORY_H_
 
+#include <string>
+#include <vector>
+#include <future>
+#include <contacts.h>
+#include <contacts_internal.h>
+
 namespace extension {
 namespace callhistory {
 
+class CallHistoryInstance;
+
 class CallHistory
 {
 public:
     static CallHistory* getInstance();
+    std::vector<std::string>& getPhoneNumbers();
 
     void find();
     void remove();
     void removeBatch();
     void removeAll();
-    long addChangeListener();
-    void removeChangeListener();
+    void startCallHistoryChangeListener();
+    void stopCallHistoryChangeListener();
 
 private:
     CallHistory();
     virtual ~CallHistory();
 
+    static void changeListenerCB(const char* view_uri, char *changes, void* user_data);
+    void loadPhoneNumbers();
+
+    bool m_is_listener_set;
+    std::vector<std::string> m_phone_numbers;
 };
 
 } // namespace callhistory
index a934c4acc379eb4b32e51ed38d8934b7502ef73c..572a0a1977221b8f6203464c6033863c7d2ef740 100644 (file)
@@ -4,7 +4,7 @@
 
 var Common = function() {
 function _getException(type, msg) {
-    return new WebAPIException(type, msg || 'Unexpected exception');
+    return new tizen.WebAPIException(type, msg || 'Unexpected exception');
 }
 
 function _getTypeMismatch(msg) {
@@ -22,22 +22,21 @@ var _validator = xwalk.utils.validator;
 
 function Common() {}
 
-function _prepareRequest(module, method, args) {
+function _prepareRequest(cmd, args) {
     var request = {
-            module : module
-    };
-    request.data = {
-            method : method,
-            args : args
+            cmd : cmd,
+            args : args || {}
     };
+
     return request;
 }
 
-Common.prototype.getCallSync = function (msg) {
-    var ret = extension.internal.sendSyncMessage(JSON.stringify(msg));
+Common.prototype.callSync = function (cmd, args) {
+    var request = _prepareRequest(cmd, args);
+    var ret = extension.internal.sendSyncMessage(JSON.stringify(request));
     var obj = JSON.parse(ret);
     if (obj.error) {
-        throwException_(obj.error);
+        throw new tizen.throwException(obj.error);
     }
 
     return obj.result;
@@ -62,7 +61,7 @@ Common.prototype.isFailure = function (result) {
 };
 
 Common.prototype.getErrorObject = function (result) {
-    return new WebAPIException(result.error);
+    return new tizen.WebAPIException(0, result.error.message, result.error.name);
 };
 
 Common.prototype.getResultObject = function (result) {
@@ -218,53 +217,170 @@ var AV = _common.ArgumentValidator;
 var C = _common.Common;
 
 var _listeners = {};
-var _nextId = 0;
+var _listenersId = 0;
+
+function _createCallHistoryEntries(e) {
+    var entries_array = [];
+    var entries = e.data;
+
+    entries.forEach(function (data) {
+        entries_array.push(new CallHistoryEntry(data));
+    });
+
+    return entries_array;
+};
 
 extension.setMessageListener(function(msg) {
+    var m = JSON.parse(msg);
+    if (m.cmd == 'CallHistoryChangeCallback') {
+        var d = null;
+
+        switch (m.action) {
+        case 'onadded':
+        case 'onchanged':
+            d = _createCallHistoryEntries(m);
+            break;
+
+        case 'onremoved':
+            d = m.data;
+            break;
+
+        default:
+            console.log('Unknown mode: ' + m.action);
+            return;
+        }
 
+        for (var watchId in _listeners) {
+            if (_listeners.hasOwnProperty(watchId) && _listeners[watchId][m.action]) {
+                _listeners[watchId][m.action](d);
+            }
+        }
+    }
 });
 
 function CallHistory() {
-}
+};
 
 CallHistory.prototype.find = function() {
 
-}
+};
 
 CallHistory.prototype.remove = function() {
 
-}
+};
 
 CallHistory.prototype.removeBatch = function() {
 
-}
+};
 
 CallHistory.prototype.removeAll = function() {
 
-}
+};
+
+CallHistory.prototype.addChangeListener = function() {
+    var args = AV.validateArgs(arguments, [
+        {
+            name : 'eventCallback',
+            type : AV.Types.LISTENER,
+            values : ['onadded', 'onchanged', 'onremoved']
+        }
+    ]);
 
-CallHistory.prototype.addChangeListener  = function() {
+    if (T.isEmptyObject(_listeners)) {
+        C.callSync('CallHistory_addChangeListener');
+    }
 
-}
+    var watchId = ++_listenersId;
+    _listeners[watchId] = args.eventCallback;
+
+     return watchId;
+};
 
 CallHistory.prototype.removeChangeListener = function() {
+    var args = AV.validateArgs(arguments, [
+        {
+            name : 'watchId',
+            type : AV.Types.LONG
+        }
+    ]);
 
-}
+    var id = args.watchId;
 
-function RemoteParty(data) {
+    if (T.isNullOrUndefined(_listeners[id])) {
+        throw new tizen.WebAPIException(0, 'NotFoundError', 'Watch id not found.');
+    }
 
-}
+    delete _listeners[id];
+
+    if (T.isEmptyObject(_listeners)) {
+       C.callSync('CallHistory_removeChangeListener');
+    }
+};
+
+function RemoteParty(data) {
+    Object.defineProperties(this, {
+        remoteParty: {
+            value: data.remoteParty ? data.remoteParty : null,
+            writable: false,
+            enumerable: true
+        },
+        personId: {
+            value: data.personId ? Converter.toString(data.personId) : null,
+            writable: false,
+            enumerable: true
+        }
+    });
+};
 
 function CallHistoryEntry(data) {
 
-}
+    function directionSetter(val) {
+        direction = Converter.toString(val, false);
+    }
+
+    function createRemoteParties(parties) {
+        var parties_array = [];
+        parties.forEach(function (data) {
+            parties_array.push(new RemoteParty(data));
+        });
+        return parties_array;
+    }
+
+    var direction;
+    if (data) {
+        directionSetter(data.direction);
+    }
+
+    Object.defineProperties(this, {
+        uid: {value: Converter.toString(data.uid), writable: false, enumerable: true},
+        type: {value: data.type, writable: false, enumerable: true},
+        features : {
+            value: data.features ? data.features : null,
+            writable: false,
+            enumerable: true
+        },
+        remoteParties : {
+            value : createRemoteParties(data.remoteParties),
+            writable: false,
+            enumerable: true
+        },
+        startTime: {value: new Date(Number(data.startTime) * 1000),
+            writable: false,
+            enumerable: true
+        },
+        duration: {value: data.duration, writable: false, enumerable: true},
+        direction: {
+            enumerable: true,
+            set : directionSetter,
+            get : function() { return direction; }
+        },
+        callingParty: {
+            value: data.callingParty ? data.callingParty : null,
+            writable: false,
+            enumerable: true
+        },
+    });
+};
 
 // Exports
-var CallHistoryObject = new CallHistory();
-
-exports.find = CallHistoryObject.find;
-exports.remove = CallHistoryObject.remove;
-exports.removeBatch = CallHistoryObject.removeBatch;
-exports.removeAll = CallHistoryObject.removeAll;
-exports.addChangeListener = CallHistoryObject.addChangeListener;
-exports.removeChangeListener = CallHistoryObject.removeChangeListener;
+exports = new CallHistory();
index 24855939832acbfad3cbd9a908608924f407492a..848687745066c3d3bdf577ecdb0cd32c9a0d3fef 100644 (file)
@@ -20,5 +20,5 @@ CallHistoryExtension::CallHistoryExtension() {
 CallHistoryExtension::~CallHistoryExtension() {}
 
 common::Instance* CallHistoryExtension::CreateInstance() {
-    return new extension::callhistory::CallHistoryInstance;
+    return &extension::callhistory::CallHistoryInstance::getInstance();
 }
index 645435aed3e7c349389bd469cd70bfaad17b1428..40ac741cd29e8b38207471ea83910ad014a8230c 100644 (file)
@@ -19,19 +19,24 @@ const std::string kPrivilegeCallHistoryWrite = "http://tizen.org/privilege/callh
 
 using namespace common;
 
+CallHistoryInstance& CallHistoryInstance::getInstance() {
+    static CallHistoryInstance instance;
+    return instance;
+}
+
 CallHistoryInstance::CallHistoryInstance() {
     using namespace std::placeholders;
 #define REGISTER_SYNC(c,x) \
         RegisterSyncHandler(c, std::bind(&CallHistoryInstance::x, this, _1, _2));
-    REGISTER_SYNC("remove", Remove);
-    REGISTER_SYNC("addChangeListener", AddChangeListener);
-    REGISTER_SYNC("removeChangeListener", RemoveChangeListener);
+    REGISTER_SYNC("CallHistory_remove", Remove);
+    REGISTER_SYNC("CallHistory_addChangeListener", AddChangeListener);
+    REGISTER_SYNC("CallHistory_removeChangeListener", RemoveChangeListener);
 #undef REGISTER_SYNC
 #define REGISTER_ASYNC(c,x) \
         RegisterHandler(c, std::bind(&CallHistoryInstance::x, this, _1, _2));
-    REGISTER_ASYNC("find", Find);
-    REGISTER_ASYNC("removeBatch", RemoveBatch);
-    REGISTER_ASYNC("removeAll", RemoveAll);
+    REGISTER_ASYNC("CallHistory_find", Find);
+    REGISTER_ASYNC("CallHistory_removeBatch", RemoveBatch);
+    REGISTER_ASYNC("CallHistory_removeAll", RemoveAll);
 #undef REGISTER_ASYNC
 }
 
@@ -55,11 +60,24 @@ void CallHistoryInstance::RemoveAll(const picojson::value& args, picojson::objec
 }
 
 void CallHistoryInstance::AddChangeListener(const picojson::value& args, picojson::object& out) {
-
+    LoggerD("Entered");
+    CallHistory::getInstance()->startCallHistoryChangeListener();
+    ReportSuccess(out);
 }
 
 void CallHistoryInstance::RemoveChangeListener(const picojson::value& args, picojson::object& out) {
+    LoggerD("Entered");
+    CallHistory::getInstance()->stopCallHistoryChangeListener();
+    ReportSuccess(out);
+}
+
+void CallHistoryInstance::CallHistoryChange(picojson::object& data) {
+    LoggerD("Entered");
+    picojson::value event = picojson::value(data);
+    picojson::object& obj = event.get<picojson::object>();
+    obj["cmd"] = picojson::value("CallHistoryChangeCallback");
 
+    PostMessage(event.serialize().c_str());
 }
 
 } // namespace callhistory
index 1718e7816813d4a0d4d6e6406def6a66e118fd71..eb4fade3a6ec2797beaf97a3ed5b6dd1ea7b1b69 100644 (file)
@@ -13,10 +13,13 @@ namespace callhistory {
 
 class CallHistoryInstance : public common::ParsedInstance {
 public:
+    static CallHistoryInstance& getInstance();
+
+    void CallHistoryChange(picojson::object& data);
+private:
     CallHistoryInstance();
     virtual ~CallHistoryInstance();
 
-private:
     void Find(const picojson::value& args, picojson::object& out);
     void Remove(const picojson::value& args, picojson::object& out);
     void RemoveBatch(const picojson::value& args, picojson::object& out);
diff --git a/src/callhistory/callhistory_types.h b/src/callhistory/callhistory_types.h
new file mode 100644 (file)
index 0000000..262bc21
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CALLHISTORY_CALLHISTORY_TYPES_H_
+#define CALLHISTORY_CALLHISTORY_TYPES_H_
+
+namespace extension {
+namespace callhistory {
+
+#define STR_CALLTYPE_TEL "TEL"
+#define STR_CALLTYPE_XMPP "XMPP"
+#define STR_CALLTYPE_SIP "SIP"
+
+#define STR_CALL "CALL"
+#define STR_CALL_VOICE "VOICECALL"
+#define STR_CALL_VIDEO "VIDEOCALL"
+#define STR_CALL_EMERGENCY "EMERGENCYCALL"
+
+#define STR_DIALED "DIALED"
+#define STR_RECEIVED "RECEIVED"
+#define STR_MISSED_NEW "MISSEDNEW"
+#define STR_MISSED "MISSED"
+#define STR_REJECTED "REJECTED"
+#define STR_BLOCKED "BLOCKED"
+
+#define STR_DATA "data"
+#define STR_ACTION "action"
+#define STR_ENTRY_ID "uid"
+#define STR_CALL_TYPE "type"
+#define STR_TAGS "features"
+#define STR_REMOTE_PARTIES "remoteParties"
+#define STR_START_TIME "startTime"
+#define STR_DURATION "duration"
+#define STR_DIRECTION "direction"
+#define STR_CALLING_PARTY "callingParty"
+
+#define STR_REMOTE_PARTY "remoteParty"
+#define STR_PERSON_ID "personId"
+
+} // namespace callhistory
+} // namespace extension
+
+#endif // CALLHISTORY_CALLHISTORY_TYPES_H_
index 899f67648e580fc0cf62fba9f2db976d5c4a106e..49ddb5f3645ced18730af24cd4592ccb37f11f10 100644 (file)
@@ -1,3 +1,210 @@
 // Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
+#include "callhistory_utils.h"
+#include "callhistory_types.h"
+#include "callhistory.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace callhistory {
+
+void CallHistoryUtils::parseRecordList(contacts_list_h *record_list, picojson::array& array)
+{
+    LoggerD("Entered");
+
+    int ret = CONTACTS_ERROR_NONE;
+    contacts_record_h record = NULL;
+    int total = 0;
+
+    ret = contacts_list_get_count(*record_list, &total);
+    if (CONTACTS_ERROR_NONE != ret) {
+        LoggerW("Failed to get contacts list: %d", ret);
+        return;
+    }
+
+    for (int i = 0; i < total; i++) {
+        ret = contacts_list_get_current_record_p(*record_list, &record);
+        if (NULL != record) {
+            array.push_back(picojson::value(picojson::object()));
+            picojson::object& obj = array.back().get<picojson::object>();
+            parseRecord(&record, obj);
+        } else {
+            ret = contacts_list_next(*record_list);
+            if (CONTACTS_ERROR_NONE != ret && CONTACTS_ERROR_NO_DATA != ret) {
+                LoggerW("Callhistory list parse error: %d", ret);
+                return;
+            }
+        }
+    }
+}
+
+void CallHistoryUtils::parseRecord(contacts_record_h *record, picojson::object& obj)
+{
+    LoggerD("Entered");
+
+    int ret = CONTACTS_ERROR_NONE;
+    int int_data;
+
+    ret = contacts_record_get_int(*record, _contacts_phone_log.id, &int_data);
+    if (CONTACTS_ERROR_NONE != ret) {
+        LoggerD("Failed to get contacts phone log id: %d", ret);
+    } else {
+        obj[STR_ENTRY_ID] = picojson::value(static_cast<double>(int_data));
+    }
+
+    ret = contacts_record_get_int(*record, _contacts_phone_log.log_type, &int_data);
+    if (CONTACTS_ERROR_NONE != ret) {
+        LoggerD("Failed to get contacts phone log type: %d", ret);
+    } else {
+        parseLogType(static_cast<contacts_phone_log_type_e>(int_data), obj);
+    }
+
+    ret = contacts_record_get_int(*record, _contacts_phone_log.log_time, &int_data);
+    if (CONTACTS_ERROR_NONE != ret) {
+        LoggerD("Failed to get contacts phone log time: %d", ret);
+    } else {
+        obj[STR_START_TIME] = picojson::value(static_cast<double>(int_data));
+    }
+
+    ret = contacts_record_get_int(*record, _contacts_phone_log.extra_data1, &int_data);
+    if (CONTACTS_ERROR_NONE != ret) {
+        LoggerD("Failed to get contacts phone log extra data: %d", ret);
+    } else {
+        obj[STR_DURATION] = picojson::value(static_cast<double>(int_data));
+    }
+
+    parseRemoteParties(record, obj);
+    parseCallingParty(record, obj);
+}
+
+void CallHistoryUtils::parseLogType(contacts_phone_log_type_e log_type, picojson::object& obj)
+{
+    LoggerD("Entered");
+
+    picojson::value val = picojson::value(picojson::array());
+    picojson::array& features = val.get<picojson::array>();
+
+    switch(log_type) {
+        case CONTACTS_PLOG_TYPE_VOICE_INCOMMING:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_RECEIVED);
+            features.push_back(picojson::value(STR_CALL_VOICE));
+            break;
+        case CONTACTS_PLOG_TYPE_VOICE_OUTGOING:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_DIALED);
+            features.push_back(picojson::value(STR_CALL_VOICE));
+            break;
+        case CONTACTS_PLOG_TYPE_VOICE_INCOMMING_SEEN:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_MISSED);
+            features.push_back(picojson::value(STR_CALL_VOICE));
+            break;
+        case CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_MISSED_NEW);
+            features.push_back(picojson::value(STR_CALL_VOICE));
+            break;
+        case CONTACTS_PLOG_TYPE_VOICE_REJECT:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_REJECTED);
+            features.push_back(picojson::value(STR_CALL_VOICE));
+            break;
+        case CONTACTS_PLOG_TYPE_VOICE_BLOCKED:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_BLOCKED);
+            features.push_back(picojson::value(STR_CALL_VOICE));
+            break;
+        case CONTACTS_PLOG_TYPE_VIDEO_INCOMMING:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_RECEIVED);
+            features.push_back(picojson::value(STR_CALL_VIDEO));
+            break;
+        case CONTACTS_PLOG_TYPE_VIDEO_OUTGOING:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_DIALED);
+            features.push_back(picojson::value(STR_CALL_VIDEO));
+            break;
+        case CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_MISSED);
+            features.push_back(picojson::value(STR_CALL_VIDEO));
+            break;
+        case CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_MISSED_NEW);
+            features.push_back(picojson::value(STR_CALL_VIDEO));
+            break;
+        case CONTACTS_PLOG_TYPE_VIDEO_REJECT:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_REJECTED);
+            features.push_back(picojson::value(STR_CALL_VIDEO));
+            break;
+        case CONTACTS_PLOG_TYPE_VIDEO_BLOCKED:
+            obj[STR_CALL_TYPE] = picojson::value(STR_CALLTYPE_TEL);
+            obj[STR_DIRECTION] = picojson::value(STR_BLOCKED);
+            features.push_back(picojson::value(STR_CALL_VIDEO));
+            break;
+        default:
+            LoggerW("Wrong phone log type: %d", log_type);
+            return;
+    }
+
+    if (features.size() > 0) {
+        obj.insert(std::make_pair(STR_TAGS, features));
+    }
+}
+
+void CallHistoryUtils::parseRemoteParties(contacts_record_h *record, picojson::object& obj)
+{
+    LoggerD("Entered");
+
+    int ret = CONTACTS_ERROR_NONE;
+    char * char_data = NULL;
+    int int_data;
+
+    picojson::array& remote_parties = obj.insert(std::make_pair(STR_REMOTE_PARTIES, picojson::value(
+                                      picojson::array()))).first->second.get<picojson::array>();
+    remote_parties.push_back(picojson::value(picojson::object()));
+    picojson::object& parties_obj = remote_parties.back().get<picojson::object>();
+
+    ret = contacts_record_get_int(*record, _contacts_phone_log.person_id, &int_data);
+    if (CONTACTS_ERROR_NONE != ret) {
+        LoggerD("Failed to get contacts phone log person id: %d", ret);
+    } else {
+        parties_obj[STR_PERSON_ID] = picojson::value(static_cast<double>(int_data));
+    }
+
+    ret = contacts_record_get_str_p(*record, _contacts_phone_log.address, &char_data);
+    if (CONTACTS_ERROR_NONE != ret) {
+        LoggerD("Failed to get contacts phone log address: %d", ret);
+    } else if (NULL != char_data) {
+        parties_obj[STR_REMOTE_PARTY] = picojson::value(char_data);
+    }
+}
+
+void CallHistoryUtils::parseCallingParty(contacts_record_h *record, picojson::object& obj)
+{
+    LoggerD("Entered");
+
+    int ret = CONTACTS_ERROR_NONE;
+    const std::vector<std::string>& phone_numbers = CallHistory::getInstance()->getPhoneNumbers();
+    int sim_count = phone_numbers.size();
+    int sim_index;
+
+    ret = contacts_record_get_int(*record, _contacts_phone_log.sim_slot_no, &sim_index);
+    if (CONTACTS_ERROR_NONE != ret) {
+        LoggerW("Failed to get sim slot no. %d", ret);
+    }
+
+    if (sim_index >= sim_count) {
+        LoggerE("sim slot no. [%d] is out of count %d", sim_index, sim_count);
+    } else if (sim_index > 0) {
+        obj[STR_CALLING_PARTY] = picojson::value(phone_numbers.at(sim_index));
+    }
+}
+
+} // namespace callhistory
+} // namespace extension
index 899f67648e580fc0cf62fba9f2db976d5c4a106e..0bfa01044cb20df8bb07bf176362926831b09045 100644 (file)
@@ -1,3 +1,28 @@
 // Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
+#ifndef CALLHISTORY_CALLHISTORY_UTILS_H_
+#define CALLHISTORY_CALLHISTORY_UTILS_H_
+
+#include <contacts.h>
+#include <contacts_internal.h>
+
+#include "common/picojson.h"
+
+namespace extension {
+namespace callhistory {
+
+class CallHistoryUtils {
+public:
+    static void parseRecordList(contacts_list_h *record_list, picojson::array& array);
+    static void parseRecord(contacts_record_h *record, picojson::object& obj);
+    static void parseLogType(contacts_phone_log_type_e log_type, picojson::object& obj);
+    static void parseRemoteParties(contacts_record_h *record, picojson::object& obj);
+    static void parseCallingParty(contacts_record_h *record, picojson::object& obj);
+};
+
+} // namespace callhistory
+} // namespace extension
+
+#endif // CALLHISTORY_CALLHISTORY_UTILS_H_