* @brief URI of the Contacts DB change event
* @details It can be used as a trigger. Available attribute and its values are:
* - "Event" ∈ {"Changed"}
+ * - "Type" ∈ {"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"
+
/**
* @}
*/
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)
# 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}")
* 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");
}
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()
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);
+
};
}
--- /dev/null
+/*
+ * 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();
+}