tizen 2.4 release
[framework/context/place-context-provider.git] / src / geofence / myplace_handle.cpp
1 /*
2  * Copyright (c) 2015 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 bool ctx::myplace_handle::start_monitor(int place_id)
36 {
37         _D("Starts to monitor Place-%d", place_id);
38
39         IF_FAIL_RETURN(place_id >= 0, false);
40         IF_FAIL_RETURN_TAG(geo_handle == NULL, false, _E, "Re-starting MyPlace monitor");
41
42         geofence_manager_create(&geo_handle);
43         IF_FAIL_RETURN_TAG(geo_handle, false, _E, "Geofence initialization failed");
44
45         int ret;
46
47         ret = geofence_manager_set_geofence_state_changed_cb(geo_handle, fence_state_cb, this);
48         IF_FAIL_CATCH_TAG(ret == GEOFENCE_MANAGER_ERROR_NONE, _E, "Setting state callback failed");
49
50         ret = geofence_manager_set_geofence_event_cb(geo_handle, fence_event_cb, this);
51         IF_FAIL_CATCH_TAG(ret == GEOFENCE_MANAGER_ERROR_NONE, _E, "Setting event callback failed");
52
53         ret = geofence_manager_foreach_place_geofence_list(geo_handle, place_id, fence_list_cb, this);
54         IF_FAIL_CATCH_TAG(ret == GEOFENCE_MANAGER_ERROR_NONE, _E, "Getting fence list failed");
55
56         _place_id = place_id;
57         return true;
58
59 CATCH:
60         stop_monitor();
61         return false;
62 }
63
64 int ctx::myplace_handle::get_place_id()
65 {
66         return _place_id;
67 }
68
69 void ctx::myplace_handle::stop_monitor()
70 {
71         _D("Stops monitoring Place-%d", _place_id);
72
73         //TODO: Do we need to stop all geofences explicitly?
74         if (geo_handle) {
75                 geofence_manager_destroy(geo_handle);
76                 geo_handle = NULL;
77         }
78
79         geo_state_map.clear();
80         _place_id = -1;
81         prev_state = GEOFENCE_STATE_UNCERTAIN;
82 }
83
84 bool ctx::myplace_handle::start_fence(int fence_id)
85 {
86         int ret;
87
88         ret = geofence_manager_start(geo_handle, fence_id);
89         IF_FAIL_RETURN_TAG(ret == GEOFENCE_MANAGER_ERROR_NONE, true, _W, "Starting failed");
90
91         geofence_status_h status;
92         ret = geofence_status_create(fence_id, &status);
93         IF_FAIL_RETURN_TAG(ret == GEOFENCE_MANAGER_ERROR_NONE, true, _W, "Getting status failed");
94
95         geofence_state_e state = GEOFENCE_STATE_UNCERTAIN;
96         geofence_status_get_state(status, &state);
97         geofence_status_destroy(status);
98
99         geo_state_map[fence_id] = state;
100
101         return true;
102 }
103
104 void ctx::myplace_handle::remove_fence(int fence_id)
105 {
106         geofence_manager_stop(geo_handle, fence_id);
107         geo_state_map.erase(fence_id);
108 }
109
110 void ctx::myplace_handle::update_fence(int fence_id, geofence_manage_e manage)
111 {
112         switch (manage) {
113                 case GEOFENCE_MANAGE_PLACE_REMOVED:
114                         _W("[Place-%d] Removed", _place_id);
115                         stop_monitor();
116                         break;
117                 case GEOFENCE_MANAGE_FENCE_ADDED:
118                         _I("[Place %d] Fence-%d added", _place_id, fence_id);
119                         start_fence(fence_id);
120                         emit_state_change();
121                         break;
122                 case GEOFENCE_MANAGE_FENCE_REMOVED:
123                         _I("[Place-%d] Fence-%d removed", _place_id, fence_id);
124                         remove_fence(fence_id);
125                         emit_state_change();
126                         break;
127                 case GEOFENCE_MANAGE_FENCE_STARTED:
128                         _D("[Place-%d] Fence-%d started", _place_id, fence_id);
129                         break;
130                 case GEOFENCE_MANAGE_FENCE_STOPPED:
131                         _D("[Place-%d] Fence-%d stopped", _place_id, fence_id);
132                         //TODO: Do we need to restart this?
133                         break;
134                 default:
135                         _D("[Place-%d] Ignoring the manage event %d", _place_id, manage);
136                         break;
137         }
138 }
139
140 void ctx::myplace_handle::update_state(int fence_id, geofence_state_e state)
141 {
142         geo_state_map[fence_id] = state;
143 }
144
145 static const char* get_state_string(geofence_state_e state)
146 {
147         switch (state) {
148                 case GEOFENCE_STATE_IN:
149                         return MYPLACE_EVENT_IN;
150                 case GEOFENCE_STATE_OUT:
151                         return MYPLACE_EVENT_OUT;
152                 case GEOFENCE_STATE_UNCERTAIN:
153                         return MYPLACE_EVENT_UNCERTAIN;
154                 default:
155                         return MYPLACE_EVENT_UNCERTAIN;
156         }
157 }
158
159 void ctx::myplace_handle::emit_state_change()
160 {
161         geofence_state_e current_state = GEOFENCE_STATE_UNCERTAIN;
162         int out_count = 0;
163
164         for (geo_state_map_t::iterator it = geo_state_map.begin(); it != geo_state_map.end(); ++it) {
165                 if (it->second == GEOFENCE_STATE_IN) {
166                         current_state = GEOFENCE_STATE_IN;
167                         break;
168                 } else if (it->second == GEOFENCE_STATE_OUT) {
169                         ++ out_count;
170                 }
171         }
172
173         if (current_state != GEOFENCE_STATE_IN && out_count > 0) {
174                 current_state = GEOFENCE_STATE_OUT;
175         }
176
177         if (current_state == prev_state) {
178                 return;
179         }
180
181         prev_state = current_state;
182
183         json option;
184         option.set(NULL, PLACE_STATUS_DATA_MYPLACE_ID, _place_id);
185
186         json data;
187         data.set(NULL, PLACE_STATUS_DATA_MYPLACE_ID, _place_id);
188         data.set(NULL, PLACE_STATUS_DATA_MYPLACE_EVENT, get_state_string(current_state));
189
190         context_manager::publish(PLACE_SUBJ_GEOFENCE, option, ERR_NONE, data);
191 }
192
193 bool ctx::myplace_handle::fence_list_cb(int geofence_id, geofence_h fence, int fence_index, int fence_cnt, void* user_data)
194 {
195         _D("FenceID: %d, Index: %d, Count: %d", geofence_id, fence_index, fence_cnt);
196         IF_FAIL_RETURN(fence_cnt > 0, false);
197
198         myplace_handle *handle = reinterpret_cast<myplace_handle*>(user_data);
199         return handle->start_fence(geofence_id);
200 }
201
202 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)
203 {
204         IF_FAIL_VOID_TAG(error == GEOFENCE_MANAGER_ERROR_NONE, _W, "Geofence error: %d", error);
205
206         myplace_handle *handle = reinterpret_cast<myplace_handle*>(user_data);
207
208         IF_FAIL_VOID_TAG(place_id == handle->get_place_id(), _W, "Mismatched Place ID");
209
210         handle->update_fence(geofence_id, manage);
211 }
212
213 void ctx::myplace_handle::fence_state_cb(int geofence_id, geofence_state_e state, void* user_data)
214 {
215         myplace_handle *handle = reinterpret_cast<myplace_handle*>(user_data);
216         handle->update_state(geofence_id, state);
217         handle->emit_state_change();
218 }