Migrate from 2.4 code repo
[platform/core/context/place-context-provider.git] / src / place_geofence / myplace_handle.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <types_internal.h>
18 #include <json.h>
19 #include <context_mgr.h>
20 #include "place_geofence_types.h"
21 #include "myplace_handle.h"
22
23 ctx::myplace_handle::myplace_handle()
24         : _place_id(-1)
25         , prev_state(GEOFENCE_STATE_UNCERTAIN)
26         , geo_handle(NULL)
27 {
28 }
29
30 ctx::myplace_handle::~myplace_handle()
31 {
32         stop_monitor();
33 }
34
35 void ctx::myplace_handle::add_zone(const char* zone)
36 {
37         _D("'%s' subscribes Place-%d", zone, _place_id);
38         _zone.insert(zone);
39 }
40
41 void ctx::myplace_handle::remove_zone(const char* zone)
42 {
43         _D("'%s' unsubscribes Place-%d", zone, _place_id);
44         _zone.erase(zone);
45 }
46
47 bool ctx::myplace_handle::zone_empty()
48 {
49         return _zone.empty();
50 }
51
52 bool ctx::myplace_handle::start_monitor(int place_id)
53 {
54         _D("Starts to monitor Place-%d", place_id);
55
56         IF_FAIL_RETURN(place_id >= 0, false);
57         IF_FAIL_RETURN_TAG(geo_handle == NULL, false, _E, "Re-starting MyPlace monitor");
58
59         geofence_manager_create(&geo_handle);
60         IF_FAIL_RETURN_TAG(geo_handle, false, _E, "Geofence initialization failed");
61
62         int ret;
63
64         ret = geofence_manager_set_geofence_state_changed_cb(geo_handle, fence_state_cb, this);
65         IF_FAIL_CATCH_TAG(ret == GEOFENCE_MANAGER_ERROR_NONE, _E, "Setting state callback failed");
66
67         ret = geofence_manager_set_geofence_event_cb(geo_handle, fence_event_cb, this);
68         IF_FAIL_CATCH_TAG(ret == GEOFENCE_MANAGER_ERROR_NONE, _E, "Setting event callback failed");
69
70         ret = geofence_manager_foreach_place_geofence_list(geo_handle, place_id, fence_list_cb, this);
71         IF_FAIL_CATCH_TAG(ret == GEOFENCE_MANAGER_ERROR_NONE, _E, "Getting fence list failed");
72
73         _place_id = place_id;
74         return true;
75
76 CATCH:
77         stop_monitor();
78         return false;
79 }
80
81 int ctx::myplace_handle::get_place_id()
82 {
83         return _place_id;
84 }
85
86 void ctx::myplace_handle::stop_monitor()
87 {
88         _D("Stops monitoring Place-%d", _place_id);
89
90         //TODO: Do we need to stop all geofences explicitly?
91         if (geo_handle) {
92                 geofence_manager_destroy(geo_handle);
93                 geo_handle = NULL;
94         }
95
96         geo_state_map.clear();
97         _place_id = -1;
98         prev_state = GEOFENCE_STATE_UNCERTAIN;
99 }
100
101 bool ctx::myplace_handle::start_fence(int fence_id)
102 {
103         int ret;
104
105         ret = geofence_manager_start(geo_handle, fence_id);
106         IF_FAIL_RETURN_TAG(ret == GEOFENCE_MANAGER_ERROR_NONE, true, _W, "Starting failed");
107
108         geofence_status_h status;
109         ret = geofence_status_create(fence_id, &status);
110         IF_FAIL_RETURN_TAG(ret == GEOFENCE_MANAGER_ERROR_NONE, true, _W, "Getting status failed");
111
112         geofence_state_e state = GEOFENCE_STATE_UNCERTAIN;
113         geofence_status_get_state(status, &state);
114         geofence_status_destroy(status);
115
116         geo_state_map[fence_id] = state;
117
118         return true;
119 }
120
121 void ctx::myplace_handle::remove_fence(int fence_id)
122 {
123         geofence_manager_stop(geo_handle, fence_id);
124         geo_state_map.erase(fence_id);
125 }
126
127 void ctx::myplace_handle::update_fence(int fence_id, geofence_manage_e manage)
128 {
129         switch (manage) {
130                 case GEOFENCE_MANAGE_PLACE_REMOVED:
131                         _W("[Place-%d] Removed", _place_id);
132                         stop_monitor();
133                         break;
134                 case GEOFENCE_MANAGE_FENCE_ADDED:
135                         _I("[Place %d] Fence-%d added", _place_id, fence_id);
136                         start_fence(fence_id);
137                         emit_state_change();
138                         break;
139                 case GEOFENCE_MANAGE_FENCE_REMOVED:
140                         _I("[Place-%d] Fence-%d removed", _place_id, fence_id);
141                         remove_fence(fence_id);
142                         emit_state_change();
143                         break;
144                 case GEOFENCE_MANAGE_FENCE_STARTED:
145                         _D("[Place-%d] Fence-%d started", _place_id, fence_id);
146                         break;
147                 case GEOFENCE_MANAGE_FENCE_STOPPED:
148                         _D("[Place-%d] Fence-%d stopped", _place_id, fence_id);
149                         //TODO: Do we need to restart this?
150                         break;
151                 default:
152                         _D("[Place-%d] Ignoring the manage event %d", _place_id, manage);
153                         break;
154         }
155 }
156
157 void ctx::myplace_handle::update_state(int fence_id, geofence_state_e state)
158 {
159         geo_state_map[fence_id] = state;
160 }
161
162 static const char* get_state_string(geofence_state_e state)
163 {
164         switch (state) {
165                 case GEOFENCE_STATE_IN:
166                         return MYPLACE_EVENT_IN;
167                 case GEOFENCE_STATE_OUT:
168                         return MYPLACE_EVENT_OUT;
169                 case GEOFENCE_STATE_UNCERTAIN:
170                         return MYPLACE_EVENT_UNCERTAIN;
171                 default:
172                         return MYPLACE_EVENT_UNCERTAIN;
173         }
174 }
175
176 void ctx::myplace_handle::emit_state_change()
177 {
178         geofence_state_e current_state = GEOFENCE_STATE_UNCERTAIN;
179         int out_count = 0;
180
181         for (geo_state_map_t::iterator it = geo_state_map.begin(); it != geo_state_map.end(); ++it) {
182                 if (it->second == GEOFENCE_STATE_IN) {
183                         current_state = GEOFENCE_STATE_IN;
184                         break;
185                 } else if (it->second == GEOFENCE_STATE_OUT) {
186                         ++ out_count;
187                 }
188         }
189
190         if (current_state != GEOFENCE_STATE_IN && out_count > 0) {
191                 current_state = GEOFENCE_STATE_OUT;
192         }
193
194         if (current_state == prev_state) {
195                 return;
196         }
197
198         prev_state = current_state;
199
200         json option;
201         option.set(NULL, PLACE_STATUS_DATA_MYPLACE_ID, _place_id);
202
203         json data;
204         data.set(NULL, PLACE_STATUS_DATA_MYPLACE_ID, _place_id);
205         data.set(NULL, PLACE_STATUS_DATA_MYPLACE_EVENT, get_state_string(current_state));
206
207         for (string_set_t::iterator it = _zone.begin(); it != _zone.end(); ++it) {
208                 context_manager::publish(PLACE_SUBJ_GEOFENCE, option, ERR_NONE, data, it->c_str());
209         }
210 }
211
212 bool ctx::myplace_handle::fence_list_cb(int geofence_id, geofence_h fence, int fence_index, int fence_cnt, void* user_data)
213 {
214         myplace_handle *handle = reinterpret_cast<myplace_handle*>(user_data);
215         return handle->start_fence(geofence_id);
216 }
217
218 void ctx::myplace_handle::fence_event_cb(int place_id, int geofence_id, geofence_manager_error_e error, geofence_manage_e manage, void* user_data)
219 {
220         IF_FAIL_VOID_TAG(error == GEOFENCE_MANAGER_ERROR_NONE, _W, "Geofence error: %d", error);
221
222         myplace_handle *handle = reinterpret_cast<myplace_handle*>(user_data);
223
224         IF_FAIL_VOID_TAG(place_id == handle->get_place_id(), _W, "Mismatched Place ID");
225
226         handle->update_fence(geofence_id, manage);
227 }
228
229 void ctx::myplace_handle::fence_state_cb(int geofence_id, geofence_state_e state, void* user_data)
230 {
231         myplace_handle *handle = reinterpret_cast<myplace_handle*>(user_data);
232         handle->update_state(geofence_id, state);
233         handle->emit_state_change();
234 }