#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");
}
GeofenceAgent::~GeofenceAgent()
{
_D("Destroyed");
+ if (__geoHandle) {
+ __stopMonitor();
+ }
}
uint16_t GeofenceAgent::getId()
__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;
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;
+ }
+}
#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 {
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