Geofence event agent implemented 10/146410/3
authorSomin Kim <somin926.kim@samsung.com>
Mon, 28 Aug 2017 10:33:00 +0000 (19:33 +0900)
committerSomin Kim <somin926.kim@samsung.com>
Tue, 29 Aug 2017 11:47:18 +0000 (20:47 +0900)
Change-Id: I8917b5a2cef61b144cf91f26684a2564ceb1ed47
Signed-off-by: Somin Kim <somin926.kim@samsung.com>
packaging/context-job-scheduler.spec
src/agent/CMakeLists.txt
src/agent/GeofenceAgent.cpp
src/agent/GeofenceAgent.h

index e4bec96d557bad3a9074fb72ff8eae7622f903c6..630b26d04b5d363c9218d50fb013cbfc78db88c5 100644 (file)
@@ -23,6 +23,7 @@ BuildRequires: pkgconfig(capi-network-wifi-manager)
 BuildRequires: pkgconfig(aul)
 BuildRequires: pkgconfig(notification)
 BuildRequires: pkgconfig(contacts-service2)
+BuildRequires: pkgconfig(capi-geofence-manager)
 
 BuildRequires: pkgconfig(context-common-server)
 BuildRequires: pkgconfig(context-common-client)
index 2ff8283b208909abc0037a9c414ca3e19e5058c3..815ba8f493aa9a76faaa2fbab2ff4cb5f5fd3c59 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 contacts-service2")
+SET(DEPS "${DEPS} capi-system-info contacts-service2 capi-geofence-manager")
 
 FILE(GLOB_RECURSE SRCS *.cpp)
 MESSAGE("Sources: ${SRCS}")
index b40904676dbc26c17c7555fb9efd3e8d01e25692..b79be6019cb62c392cac34dc8509926a9683e6d3 100644 (file)
 #include "AgentTypes.h"
 #include "GeofenceAgent.h"
 
+#define UNCERTAIN "Uncertain"
+
 using namespace ctx;
 
 GeofenceAgent::GeofenceAgent(IAgentUtil* agentUtil) :
        __idle(true),
-       __agentUtil(agentUtil)
+       __agentUtil(agentUtil),
+       __geoHandle(NULL)
 {
        _D("Created");
 }
@@ -32,6 +35,9 @@ GeofenceAgent::GeofenceAgent(IAgentUtil* agentUtil) :
 GeofenceAgent::~GeofenceAgent()
 {
        _D("Destroyed");
+       if (__geoHandle) {
+               __stopMonitor();
+       }
 }
 
 uint16_t GeofenceAgent::getId()
@@ -46,15 +52,54 @@ bool GeofenceAgent::doAction(uint8_t length, const void* command)
 
        __idle = (cmd == GEOFENCE_CMD_STOP);
 
-       //TODO
        // Regarding the given command, start or stop monitoring Home/Work geofencing events.
        // If an event is detected, send a signal to the GeofenceEvent publisher.
        // This may require to assign an app id to this user session daemon,
        // as the Geofence API requires the package id to distinguish a client.
+       if (cmd == GEOFENCE_CMD_START) {
+               __startMonitor();
+       } else if (cmd == GEOFENCE_CMD_STOP) {
+               __stopMonitor();
+       } else {
+               return false;
+       }
 
        return true;
 }
 
+bool GeofenceAgent::__startMonitor()
+{
+       IF_FAIL_RETURN_TAG(__geoHandle == NULL, false, _E, "Geofence monitoring already started");
+
+       geofence_manager_create(&__geoHandle);
+       IF_FAIL_RETURN_TAG(__geoHandle, false, _E, "Geofence initialization failed");
+
+       int error = geofence_manager_set_geofence_state_changed_cb(__geoHandle, __fenceStateCb, this);
+       IF_FAIL_CATCH_TAG(error == GEOFENCE_MANAGER_ERROR_NONE, _E, "Setting state callback failed");
+
+       error = geofence_manager_set_geofence_event_cb(__geoHandle, __fenceEventCb, this);
+       IF_FAIL_CATCH_TAG(error == GEOFENCE_MANAGER_ERROR_NONE, _E, "Setting event callback failed");
+
+       error = geofence_manager_foreach_geofence_list(__geoHandle, __fenceListCb, this);
+       IF_FAIL_CATCH_TAG(error == GEOFENCE_MANAGER_ERROR_NONE, _E, "Getting fence list failed");
+
+       return true;
+
+CATCH:
+       __stopMonitor();
+       return false;
+}
+
+void GeofenceAgent::__stopMonitor()
+{
+       if (__geoHandle) {
+               geofence_manager_destroy(__geoHandle);
+               __geoHandle = NULL;
+       }
+
+       __placeInfoMap.clear();
+}
+
 bool GeofenceAgent::isIdle()
 {
        return __idle;
@@ -71,3 +116,143 @@ void GeofenceAgent::__publish(const char* event, int placeId)
                        GEOFENCE_SIGNAL, g_variant_new("(si)", event, placeId), &gerr);
        HANDLE_GERROR(gerr);
 }
+
+void GeofenceAgent::__fenceStateCb(int geofenceId, geofence_state_e state, void* userData)
+{
+       GeofenceAgent *handle = reinterpret_cast<GeofenceAgent*>(userData);
+
+       int placeId = handle->__updateState(geofenceId, state);
+       IF_FAIL_VOID_TAG(placeId > 0, _E, "Cannot find place id for geofence Id %d", geofenceId);
+
+       handle->__emitStateChange(placeId);
+}
+
+bool GeofenceAgent::__fenceListCb(int geofenceId, geofence_h fence, int fenceIndex, int fenceCount, void* userData)
+{
+       IF_FAIL_RETURN_TAG(fenceCount > 0, false, _I, "No fence");
+
+       int placeId = -1;
+       geofence_get_place_id(fence, &placeId);
+       geofence_destroy(fence);
+       _D("FenceID: %d, Index: %d, Count: %d, PlaceID: %d", geofenceId, fenceIndex, fenceCount, placeId);
+
+       GeofenceAgent *handle = reinterpret_cast<GeofenceAgent*>(userData);
+       handle->__startFence(placeId, geofenceId);
+
+       return true;
+}
+
+void GeofenceAgent::__fenceEventCb(int placeId, int geofenceId, geofence_manager_error_e error, geofence_manage_e manage, void* userData)
+{
+       IF_FAIL_VOID_TAG(error == GEOFENCE_MANAGER_ERROR_NONE, _W, "Geofence error: %d", error);
+
+       GeofenceAgent *handle = reinterpret_cast<GeofenceAgent*>(userData);
+       handle->__updateFence(placeId, geofenceId, manage);
+}
+
+bool GeofenceAgent::__startFence(int placeId, int geofenceId)
+{
+       int error = geofence_manager_start(__geoHandle, geofenceId);
+       IF_FAIL_RETURN_TAG(error == GEOFENCE_MANAGER_ERROR_NONE, true, _W, "Starting failed");
+
+       geofence_status_h status;
+       error = geofence_status_create(geofenceId, &status);
+       IF_FAIL_RETURN_TAG(error == GEOFENCE_MANAGER_ERROR_NONE, true, _W, "Getting status failed");
+
+       geofence_state_e state = GEOFENCE_STATE_UNCERTAIN;
+       error = geofence_status_get_state(status, &state);
+
+       geofence_status_destroy(status);
+
+       __placeInfoMap[placeId].fences[geofenceId] = state;
+
+       return true;
+}
+
+void GeofenceAgent::__removeFence(int placeId, int geofenceId)
+{
+       geofence_manager_stop(__geoHandle, geofenceId);
+       __placeInfoMap[placeId].fences.erase(geofenceId);
+}
+
+void GeofenceAgent::__updateFence(int placeId, int geofenceId, geofence_manage_e manage)
+{
+       switch (manage) {
+       case GEOFENCE_MANAGE_PLACE_REMOVED:
+               _W("[Place-%d] Removed", placeId);
+               __placeInfoMap.erase(placeId);
+               break;
+       case GEOFENCE_MANAGE_FENCE_ADDED:
+               _I("[Place %d] Fence-%d added", placeId, geofenceId);
+               __startFence(placeId, geofenceId);
+               __emitStateChange(placeId);
+               break;
+       case GEOFENCE_MANAGE_FENCE_REMOVED:
+               _I("[Place-%d] Fence-%d removed", placeId, geofenceId);
+               __removeFence(placeId, geofenceId);
+               __emitStateChange(placeId);
+               break;
+       case GEOFENCE_MANAGE_FENCE_STARTED:
+               _D("[Place-%d] Fence-%d started", placeId, geofenceId);
+               break;
+       case GEOFENCE_MANAGE_FENCE_STOPPED:
+               _D("[Place-%d] Fence-%d stopped", placeId, geofenceId);
+               //TODO: Do we need to restart this?
+               break;
+       default:
+               _D("[Place-%d] Ignoring the manage event %d", placeId, manage);
+               break;
+       }
+}
+
+int GeofenceAgent::__updateState(int geofenceId, geofence_state_e state)
+{
+       // Return place id of updated fence id
+       for (auto placeIt = __placeInfoMap.begin(); placeIt != __placeInfoMap.end(); ++placeIt)
+       {
+               auto fenceIt = placeIt->second.fences.find(geofenceId);
+               if (fenceIt != placeIt->second.fences.end()) {
+                       __placeInfoMap[placeIt->first].fences[geofenceId] = state;
+                       return placeIt->first;
+               }
+       }
+       return -1;
+}
+
+void GeofenceAgent::__emitStateChange(int placeId)
+{
+       geofence_state_e currentState = GEOFENCE_STATE_UNCERTAIN;
+       int outCount = 0;
+
+       for (auto fenceIt = __placeInfoMap[placeId].fences.begin(); fenceIt != __placeInfoMap[placeId].fences.end(); ++fenceIt) {
+               if (fenceIt->second == GEOFENCE_STATE_IN) {
+                       currentState = GEOFENCE_STATE_IN;
+                       break;
+               } else if (fenceIt->second == GEOFENCE_STATE_OUT) {
+                       ++outCount;
+               }
+       }
+
+       if (currentState != GEOFENCE_STATE_IN && outCount > 0) {
+               currentState = GEOFENCE_STATE_OUT;
+       }
+
+       if (currentState == __placeInfoMap[placeId].prevState) {
+               return;
+       }
+
+       __placeInfoMap[placeId].prevState = currentState;
+       __publish(__getStateString(currentState), placeId);
+}
+
+const char* GeofenceAgent::__getStateString(geofence_state_e state)
+{
+       switch (state) {
+       case GEOFENCE_STATE_IN:
+               return VALUE(IN);
+       case GEOFENCE_STATE_OUT:
+               return VALUE(OUT);
+       default:
+               return UNCERTAIN;
+       }
+}
index 20963981c96e68e974962a9b70b98dfaf5653aae..16360366fd1485578e65c826f4be017ebc13f267 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef __CONTEXT_JOB_SCHEDULER_GEOFENCE_AGENT_H__
 #define __CONTEXT_JOB_SCHEDULER_GEOFENCE_AGENT_H__
 
+#include <map>
+#include <geofence_manager.h>
 #include <IAgentPlugin.h>
 
 namespace ctx {
@@ -31,11 +33,41 @@ namespace ctx {
                bool isIdle();
 
        private:
-               void __publish(const char* event, int placeId);
+               typedef std::map<int, geofence_state_e> FenceStateMap;  // fence id, fence state
+
+               struct PlaceInfo {
+                       geofence_state_e prevState;
+                       FenceStateMap fences;
+                       PlaceInfo() :
+                               prevState(GEOFENCE_STATE_UNCERTAIN)
+                       {
+                       }
+               };
+
+               typedef std::map<int, PlaceInfo> PlaceInfoMap;                  // place id, PlaceInfo(prevState, FenceStateMap)
 
                bool __idle;
                IAgentUtil* __agentUtil;
+
+               geofence_manager_h __geoHandle;
+               PlaceInfoMap __placeInfoMap;
+
+               bool __startMonitor();
+               void __stopMonitor();
+               void __publish(const char* event, int placeId);
+               bool __startFence(int placeId, int geofenceId);
+               void __removeFence(int placeId, int geofenceId);
+               void __updateFence(int placeId, int geofenceId, geofence_manage_e manage);
+               int __updateState(int geofenceId, geofence_state_e state);
+               void __emitStateChange(int placeId);
+               static const char* __getStateString(geofence_state_e state);
+
+               static bool __fenceListCb(int geofenceId, geofence_h fence, int fenceIndex, int fenceCount, void* userData);
+               static void __fenceStateCb(int geofenceId, geofence_state_e state, void* userData);
+               static void __fenceEventCb(int placeId, int geofenceId, geofence_manager_error_e error, geofence_manage_e manage, void* userData);
+
        };
+
 }
 
 #endif