Contacts db agent implemented 24/146224/1
authorSomin Kim <somin926.kim@samsung.com>
Fri, 25 Aug 2017 09:56:30 +0000 (18:56 +0900)
committerSomin Kim <somin926.kim@samsung.com>
Fri, 25 Aug 2017 09:56:30 +0000 (18:56 +0900)
Change-Id: I5ea76ed5f1c4211fe5b24ebd82ac06cde302cc2b
Signed-off-by: Somin Kim <somin926.kim@samsung.com>
include/job_scheduler_types_internal.h
packaging/context-job-scheduler.spec
src/agent/CMakeLists.txt
src/agent/ContactsDbAgent.cpp
src/agent/ContactsDbAgent.h
src/server/publisher/ContactsDbEvent.cpp [new file with mode: 0644]

index ff419799c552420ae59833f9ae01186cd6247874..dc65f02473250323653d462d8e60452a2408bbde 100644 (file)
  * @brief      URI of the Contacts DB change event
  * @details    It can be used as a trigger. Available attribute and its values are:
  *                     - "Event" &isin; {"Changed"}
+ *                     - "Type" &isin; {"MyProfile", "Person"}
  */
 #define CTX_SCHED_URI_CONTACTS_DB      CTX_SCHED_URI_PREFIX "event/contacts_db"
 
 #define CTX_SCHED_ATTR_VALUE_FRI                       "Fri"
 #define CTX_SCHED_ATTR_VALUE_SAT                       "Sat"
 
+#define CTX_SCHED_ATTR_VALUE_MY_PROFILE                "MyProfile"
+#define CTX_SCHED_ATTR_VALUE_PERSON                    "Person"
+
 /**
  * @}
  */
index 1a4548e5188ba390c1a02eadbdb361f73daa5e6a..e4bec96d557bad3a9074fb72ff8eae7622f903c6 100644 (file)
@@ -22,6 +22,7 @@ BuildRequires: pkgconfig(capi-context-motion)
 BuildRequires: pkgconfig(capi-network-wifi-manager)
 BuildRequires: pkgconfig(aul)
 BuildRequires: pkgconfig(notification)
+BuildRequires: pkgconfig(contacts-service2)
 
 BuildRequires: pkgconfig(context-common-server)
 BuildRequires: pkgconfig(context-common-client)
index 18137888ea81c36e98a60944a5f7c0c876a8f71d..2ff8283b208909abc0037a9c414ca3e19e5058c3 100644 (file)
@@ -2,7 +2,7 @@ SET(target "${PROJECT_NAME}-agent")
 
 # Be sure that the agent so does not have dependency to context-common or job-scheduler itself.
 SET(DEPS "${DEPS} jsoncpp")
-SET(DEPS "${DEPS} capi-system-info")
+SET(DEPS "${DEPS} capi-system-info contacts-service2")
 
 FILE(GLOB_RECURSE SRCS *.cpp)
 MESSAGE("Sources: ${SRCS}")
index db8b4c3bd446f497e6d33d0553648b1bb02b7669..4e20e0015d5f761513eb664407cdb850dabc31ff 100644 (file)
  * limitations under the License.
  */
 
+#include <contacts.h>
 #include <ContextTypes.h>
+#include <JobSchedulerTypesPrivate.h>
+#include <job_scheduler_types_internal.h>
 #include "AgentTypes.h"
 #include "ContactsDbAgent.h"
 
+#define MY_PROFILE_VIEW _contacts_my_profile._uri
+#define PERSON_VIEW _contacts_person._uri
+#define TIME_INTERVAL 1
+
 using namespace ctx;
 
 ContactsDbAgent::ContactsDbAgent(IAgentUtil* agentUtil) :
        __idle(true),
-       __agentUtil(agentUtil)
+       __agentUtil(agentUtil),
+       __latestMyProfile(0),
+       __latestPerson(0)
 {
        _D("Created");
 }
@@ -42,13 +51,100 @@ bool ContactsDbAgent::doAction(uint8_t length, const void* command)
        char cmd = reinterpret_cast<const char*>(command)[0];
        _D("Command: %d", cmd);
 
-       __idle = (cmd == GEOFENCE_CMD_STOP);
-
-       //TODO
+       __idle = (cmd == CONTACTS_DB_CMD_STOP);
        // Regarding the given command, start or stop monitoring the DB changes.
        // If a change is detected, send a signal to the ContactsDbChanges publisher.
 
+       if (cmd == CONTACTS_DB_CMD_START) {
+               __startMonitor();
+       } else if (cmd == CONTACTS_DB_CMD_STOP) {
+               __stopMonitor();
+       } else {
+               return false;
+       }
+
+       return true;
+}
+
+bool ContactsDbAgent::__startMonitor()
+{
+       int error;
+
+       error = contacts_connect();
+       IF_FAIL_RETURN_TAG(error == CONTACTS_ERROR_NONE, false, _E, "Connecting contacts failed");
+
+       error = contacts_db_add_changed_cb(MY_PROFILE_VIEW, __changedCb, this);
+       IF_FAIL_CATCH_TAG(error == CONTACTS_ERROR_NONE, _E, "Setting my profile view changed callback failed");
+
+       error = contacts_db_add_changed_cb(PERSON_VIEW, __changedCb, this);
+       IF_FAIL_CATCH_TAG(error == CONTACTS_ERROR_NONE, _E, "Setting person view changed callback failed");
+
        return true;
+
+CATCH:
+       contacts_disconnect();
+       return false;
+
+}
+
+void ContactsDbAgent::__stopMonitor()
+{
+       contacts_db_remove_changed_cb(MY_PROFILE_VIEW, __changedCb, this);
+       contacts_db_remove_changed_cb(PERSON_VIEW, __changedCb, this);
+
+       contacts_disconnect();
+
+       __latestMyProfile = 0;
+       __latestPerson = 0;
+}
+
+void ContactsDbAgent::__handleEvent(const char* viewUri)
+{
+       if (!STR_EQ(viewUri, _contacts_my_profile._uri) && !STR_EQ(viewUri, _contacts_person._uri)) {
+               _W("Unknown view uri");
+               return;
+       }
+
+       IF_FAIL_VOID_TAG(!__isConsecutiveChange(viewUri), _D, "Ignore consecutive db change: %s", viewUri);
+
+       __publish(VALUE(CHANGED), (STR_EQ(viewUri, _contacts_my_profile._uri)? VALUE(MY_PROFILE) : VALUE(PERSON)));
+}
+
+void ContactsDbAgent::__publish(const char* event, const char* view)
+{
+       IF_FAIL_VOID_TAG(event && view, _E, "Invalid parameter");
+       _D("Publish <%s, %s>", event, view);
+
+       GError* gerr = NULL;
+       g_dbus_connection_emit_signal(__agentUtil->getDBusConnection(), CTX_DBUS_DEST,
+                       CTX_DBUS_PATH "/" CTX_JOB_SCHEDULER, CTX_DBUS_IFACE "." CTX_JOB_SCHEDULER,
+                       CONTACTS_DB_SIGNAL, g_variant_new("(ss)", event, view), &gerr);
+       HANDLE_GERROR(gerr);
+}
+
+void ContactsDbAgent::__changedCb(const char* viewUri, void* userData)
+{
+       ContactsDbAgent *instance = static_cast<ContactsDbAgent*>(userData);
+       instance->__handleEvent(viewUri);
+}
+
+bool ContactsDbAgent::__isConsecutiveChange(const char* viewUri)
+{
+       time_t now = time(NULL);
+       double diff = 0;
+
+       if (STR_EQ(viewUri, MY_PROFILE_VIEW)) {
+               diff = difftime(now, __latestMyProfile);
+               __latestMyProfile = now;
+       } else if (STR_EQ(viewUri, PERSON_VIEW)) {
+               diff = difftime(now, __latestPerson);
+               __latestPerson = now;
+       }
+
+       if (diff < TIME_INTERVAL)
+               return true;
+
+       return false;
 }
 
 bool ContactsDbAgent::isIdle()
index e44d4de7516b9957f8caa503b0a209c0b293d224..dca38827ba7596fbeae0f1cc62113b832a6a9889 100644 (file)
@@ -33,6 +33,17 @@ namespace ctx {
        private:
                bool __idle;
                IAgentUtil* __agentUtil;
+
+               time_t __latestMyProfile;
+               time_t __latestPerson;
+
+               bool __startMonitor();
+               void __stopMonitor();
+               void __handleEvent(const char* viewUri);
+               void __publish(const char* event, const char* viewUri);
+               bool __isConsecutiveChange(const char* viewUri);
+               static void __changedCb(const char* viewUri, void* userData);
+
        };
 }
 
diff --git a/src/server/publisher/ContactsDbEvent.cpp b/src/server/publisher/ContactsDbEvent.cpp
new file mode 100644 (file)
index 0000000..5819a06
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 <system_info.h>
+
+#include <ContextTypes.h>
+#include <AgentCommander.h>
+#include <DBusMonitor.h>
+#include <IDBusSignalListener.h>
+
+#include <JobSchedulerTypesPrivate.h>
+#include <job_scheduler_types_internal.h>
+#include "../../agent/AgentTypes.h"
+#include "../ContextPublisher.h"
+#include "../IContextObserver.h"
+
+using namespace ctx;
+
+namespace {
+       class ContactsDbEvent : public ContextPublisher, public IDBusSignalListener {
+       public:
+               ContactsDbEvent(uid_t uid);
+               ~ContactsDbEvent();
+
+               const char* getUri() const;
+               const char* getPrivilege() const;
+
+               bool isReadable() const;
+
+       protected:
+               void read();
+               void subscribe();
+               void unsubscribe();
+
+               void onSignal(const std::string& sender, const std::string& objPath,
+                               const std::string& interface, const std::string& signalName,
+                               GVariant* param);
+
+       private:
+               uid_t __uid;
+               unsigned int __signalId;
+               DBusMonitor __dbusMonitor;
+       };
+}
+
+REGISTER_PUBLISHER(URI(CONTACTS_DB), ContactsDbEvent)
+
+ContactsDbEvent::ContactsDbEvent(uid_t uid) :
+       __uid(uid),
+       __signalId(0)
+{
+       _D("Created");
+}
+
+ContactsDbEvent::~ContactsDbEvent()
+{
+       _D("Destroyed");
+}
+
+const char* ContactsDbEvent::getUri() const
+{
+       return URI(CONTACTS_DB);
+}
+
+const char* ContactsDbEvent::getPrivilege() const
+{
+       return "http://tizen.org/privilege/contact.read";
+}
+
+bool ContactsDbEvent::isReadable() const
+{
+       return false;
+}
+
+void ContactsDbEvent::read()
+{
+}
+
+void ContactsDbEvent::subscribe()
+{
+       const char cmd = CONTACTS_DB_CMD_START;
+
+       AgentCommander commander(__uid);
+       bool success = commander.send(CTX_AGENT_DOMAIN_JOB_SCHEDULER | AGENT_TYPE_CONTACTS_DB, sizeof(cmd), &cmd);
+       IF_FAIL_VOID_TAG(success, _E, "Sending command failed");
+
+       __signalId = __dbusMonitor.subscribe(NULL,
+                       CTX_DBUS_PATH "/" CTX_JOB_SCHEDULER,
+                       CTX_DBUS_IFACE "." CTX_JOB_SCHEDULER,
+                       CONTACTS_DB_SIGNAL, this);
+       _D("Subscription ID: %u", __signalId);
+}
+
+void ContactsDbEvent::unsubscribe()
+{
+       const char cmd = CONTACTS_DB_CMD_STOP;
+
+       __dbusMonitor.unsubscribe(__signalId);
+
+       AgentCommander commander(__uid);
+       bool success = commander.send(CTX_AGENT_DOMAIN_JOB_SCHEDULER | AGENT_TYPE_CONTACTS_DB, sizeof(cmd), &cmd);
+       IF_FAIL_VOID_TAG(success, _E, "Sending command failed");
+}
+
+void ContactsDbEvent::onSignal(const std::string& sender,
+               const std::string& objPath, const std::string& interface,
+               const std::string& signalName, GVariant* param)
+{
+       const char* event = NULL;
+       const char* type = NULL;
+
+       g_variant_get(param, "(&s&s)", &event, &type);
+       IF_FAIL_VOID_TAG(event && type, _E, "Invalid parameter");
+
+       _D("Event: %s, Type: %s", event, type);
+
+       __data[NAME(EVENT)] = event;
+       __data[NAME(TYPE)] = type;
+
+       notifyObservers();
+}