[ACR-476] Added mock location APIs
[platform/core/api/location-manager.git] / src / location_bounds.c
1 /*
2  * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd All Rights Reserved
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 <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <system_info.h>
21 #include "location_bounds.h"
22 #include "location_internal.h"
23
24
25 static void __free_position_list(gpointer data)
26 {
27         if (data == NULL)
28                 return;
29
30         LocationPosition *position = (LocationPosition *) data;
31         location_position_free(position);
32 }
33
34 static location_bounds_type_e __convert_bounds_type(LocationBoundaryType type)
35 {
36         location_bounds_type_e ret;
37         switch (type) {
38                 case LOCATION_BOUNDARY_CIRCLE:
39                         ret = LOCATION_BOUNDS_CIRCLE;
40                         break;
41                 case LOCATION_BOUNDARY_POLYGON:
42                         ret = LOCATION_BOUNDS_POLYGON;
43                         break;
44                 case LOCATION_BOUNDARY_NONE:
45                 case LOCATION_BOUNDARY_RECT:
46                 default:
47                         ret = LOCATION_BOUNDS_RECT;
48                         break;
49         }
50         return ret;
51 }
52
53 EXPORT_API int location_bounds_create_rect(location_coords_s top_left, location_coords_s bottom_right, location_bounds_h *bounds)
54 {
55         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
56         LOCATIONS_NULL_ARG_CHECK(bounds);
57         LOCATIONS_CHECK_CONDITION(top_left.latitude >= -90 && top_left.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
58         LOCATIONS_CHECK_CONDITION(top_left.longitude >= -180 && top_left.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
59         LOCATIONS_CHECK_CONDITION(bottom_right.latitude >= -90 && bottom_right.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
60         LOCATIONS_CHECK_CONDITION(bottom_right.longitude >= -180 && bottom_right.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
61
62         if ((bottom_right.longitude - top_left.longitude) < 180 && (bottom_right.longitude - top_left.longitude) > -180) {
63                 if (bottom_right.longitude <= top_left.longitude || bottom_right.latitude >= top_left.latitude) {
64                         return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
65                 }
66         } else {
67                 if (bottom_right.latitude >= top_left.latitude) {
68                         return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
69                 }
70         }
71
72         LocationPosition *lt = location_position_new(0, top_left.latitude, top_left.longitude, 0, LOCATION_STATUS_2D_FIX);
73         if (lt == NULL) {
74                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
75                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
76         }
77
78         LocationPosition *rb = location_position_new(0, bottom_right.latitude, bottom_right.longitude, 0, LOCATION_STATUS_2D_FIX);
79         if (rb == NULL) {
80                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
81                 location_position_free(lt);
82                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
83         }
84
85         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
86         if (handle == NULL) {
87                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
88                 location_position_free(rb);
89                 location_position_free(lt);
90                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
91         }
92         memset(handle, 0, sizeof(location_bounds_s));
93
94         handle->is_added = FALSE;
95         handle->boundary = location_boundary_new_for_rect(lt, rb);
96         location_position_free(rb);
97         location_position_free(lt);
98         if (handle->boundary == NULL) {
99                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_rect", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
100                 free(handle);
101                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
102         }
103
104         *bounds = (location_bounds_h) handle;
105         return LOCATION_BOUNDS_ERROR_NONE;
106 }
107
108 EXPORT_API int location_bounds_create_circle(location_coords_s center, double radius, location_bounds_h *bounds)
109 {
110         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
111         LOCATIONS_NULL_ARG_CHECK(bounds);
112         LOCATIONS_CHECK_CONDITION(radius > 0, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
113         LOCATIONS_CHECK_CONDITION(center.latitude >= -90 && center.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
114         LOCATIONS_CHECK_CONDITION(center.longitude >= -180 && center.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
115
116         LocationPosition *ct = location_position_new(0, center.latitude, center.longitude, 0, LOCATION_STATUS_2D_FIX);
117         if (ct == NULL) {
118                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
119                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
120         }
121
122         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
123         if (handle == NULL) {
124                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
125                 location_position_free(ct);
126                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
127         }
128         memset(handle, 0, sizeof(location_bounds_s));
129
130         handle->is_added = FALSE;
131         handle->boundary = location_boundary_new_for_circle(ct, radius);
132         location_position_free(ct);
133         if (handle->boundary == NULL) {
134                 free(handle);
135                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_circle", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
136                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
137         }
138
139         *bounds = (location_bounds_h) handle;
140         return LOCATION_BOUNDS_ERROR_NONE;
141 }
142
143 EXPORT_API int location_bounds_create_polygon(location_coords_s *coords_list, int length, location_bounds_h *bounds)
144 {
145         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
146         LOCATIONS_NULL_ARG_CHECK(coords_list);
147         LOCATIONS_NULL_ARG_CHECK(bounds);
148         LOCATIONS_CHECK_CONDITION(length >= 3, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
149
150         int i;
151         GList *position_list = NULL;
152         LocationPosition *position = NULL;
153         bool isValid;
154
155         for (i = 0; i < length; i++) {
156                 if (coords_list[i].latitude < -90 || coords_list[i].latitude > 90 || coords_list[i].longitude < -180 || coords_list[i].longitude > 180) {
157                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INVALID_PARAMETER(0x%08x)", LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
158                         isValid = FALSE;
159                         break;
160                 }
161                 position = location_position_new(0, coords_list[i].latitude, coords_list[i].longitude, 0.0, LOCATION_STATUS_2D_FIX);
162                 position_list = g_list_append(position_list, position);
163                 /* We should not remove position.
164                 location_position_free(position);
165                 */
166                 isValid = TRUE;
167         }
168
169         if (!isValid) {
170                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
171                 return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
172         }
173
174         if (position_list == NULL) {
175                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
176                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
177                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
178         }
179
180         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
181         if (handle == NULL) {
182                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
183                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
184         }
185         memset(handle, 0, sizeof(location_bounds_s));
186
187         handle->is_added = FALSE;
188         handle->boundary = location_boundary_new_for_polygon(position_list);
189         if (handle->boundary == NULL) {
190                 free(handle);
191                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_polygon", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
192                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
193         }
194
195         *bounds = (location_bounds_h) handle;
196         return LOCATION_BOUNDS_ERROR_NONE;
197 }
198
199 EXPORT_API bool location_bounds_contains_coordinates(location_bounds_h bounds, location_coords_s coords)
200 {
201         if (__is_location_supported() == LOCATIONS_ERROR_NOT_SUPPORTED) {
202                 set_last_result(LOCATIONS_ERROR_NOT_SUPPORTED);
203                 return FALSE;
204         }
205
206         if (!bounds) {
207                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
208                 return FALSE;
209         }
210
211         if (coords.latitude < -90 || coords.latitude > 90 || coords.longitude < -180 || coords.longitude > 180) {
212                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
213                 return FALSE;
214         }
215
216         LocationPosition *pos = location_position_new(0, coords.latitude, coords.longitude, 0, LOCATION_STATUS_2D_FIX);
217         if (pos == NULL) {
218                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
219                 set_last_result(LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
220                 return FALSE;
221         }
222         location_bounds_s *handle = (location_bounds_s *) bounds;
223         gboolean is_inside = location_boundary_if_inside(handle->boundary, pos);
224         location_position_free(pos);
225         bool result = is_inside ? TRUE : FALSE;
226
227         set_last_result(LOCATION_BOUNDS_ERROR_NONE);
228         return result;
229 }
230
231 EXPORT_API int location_bounds_get_type(location_bounds_h bounds, location_bounds_type_e *type)
232 {
233         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
234         LOCATIONS_NULL_ARG_CHECK(bounds);
235         LOCATIONS_NULL_ARG_CHECK(type);
236
237         location_bounds_s *handle = (location_bounds_s *) bounds;
238         *type = __convert_bounds_type(handle->boundary->type);
239         return LOCATION_BOUNDS_ERROR_NONE;
240 }
241
242 EXPORT_API int location_bounds_get_rect_coords(location_bounds_h bounds, location_coords_s *top_left, location_coords_s *bottom_right)
243 {
244         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
245         LOCATIONS_NULL_ARG_CHECK(bounds);
246         LOCATIONS_NULL_ARG_CHECK(top_left);
247         LOCATIONS_NULL_ARG_CHECK(bottom_right);
248
249         location_bounds_s *handle = (location_bounds_s *) bounds;
250         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_RECT) {
251                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
252                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
253         }
254
255         top_left->latitude = handle->boundary->rect.left_top->latitude;
256         top_left->longitude = handle->boundary->rect.left_top->longitude;
257         bottom_right->latitude = handle->boundary->rect.right_bottom->latitude;
258         bottom_right->longitude = handle->boundary->rect.right_bottom->longitude;
259         return LOCATION_BOUNDS_ERROR_NONE;
260 }
261
262 EXPORT_API int location_bounds_get_circle_coords(location_bounds_h bounds, location_coords_s *center, double *radius)
263 {
264         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
265         LOCATIONS_NULL_ARG_CHECK(bounds);
266         LOCATIONS_NULL_ARG_CHECK(center);
267         LOCATIONS_NULL_ARG_CHECK(radius);
268
269         location_bounds_s *handle = (location_bounds_s *) bounds;
270         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_CIRCLE) {
271                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
272                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
273         }
274
275         center->latitude = handle->boundary->circle.center->latitude;
276         center->longitude = handle->boundary->circle.center->longitude;
277         *radius = handle->boundary->circle.radius;
278         return LOCATION_BOUNDS_ERROR_NONE;
279 }
280
281 EXPORT_API int location_bounds_foreach_polygon_coords(location_bounds_h bounds, polygon_coords_cb callback, void *user_data)
282 {
283         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
284         LOCATIONS_NULL_ARG_CHECK(bounds);
285         LOCATIONS_NULL_ARG_CHECK(callback);
286
287         location_bounds_s *handle = (location_bounds_s *) bounds;
288         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_POLYGON) {
289                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
290                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
291         }
292
293         GList *list = handle->boundary->polygon.position_list;
294         while (list) {
295                 LocationPosition *pos = list->data;
296                 location_coords_s coords;
297                 coords.latitude = pos->latitude;
298                 coords.longitude = pos->longitude;
299
300                 if (callback(coords, user_data) != TRUE) {
301                         LOCATIONS_LOGI("User quit the loop ");
302                         break;
303                 }
304                 list = g_list_next(list);
305         }
306         return LOCATION_BOUNDS_ERROR_NONE;
307 }
308
309 EXPORT_API int location_bounds_destroy(location_bounds_h bounds)
310 {
311         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
312         LOCATIONS_NULL_ARG_CHECK(bounds);
313
314         location_bounds_s *handle = (location_bounds_s *) bounds;
315         if (handle->is_added) {
316                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_IS_ADDED(0x%08x)", LOCATION_BOUNDS_ERROR_IS_ADDED);
317                 return LOCATION_BOUNDS_ERROR_IS_ADDED;
318         }
319         location_boundary_free(handle->boundary);
320         handle->user_cb = NULL;
321         handle->user_data = NULL;
322         free(handle);
323         LOCATIONS_LOGE("");
324         return LOCATION_BOUNDS_ERROR_NONE;
325 }
326
327 EXPORT_API int location_bounds_set_state_changed_cb(location_bounds_h bounds, location_bounds_state_changed_cb callback, void *user_data)
328 {
329         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
330         LOCATIONS_NULL_ARG_CHECK(bounds);
331         LOCATIONS_NULL_ARG_CHECK(callback);
332
333         location_bounds_s *handle = (location_bounds_s *) bounds;
334         handle->user_cb = callback;
335         handle->user_data = user_data;
336         return LOCATION_BOUNDS_ERROR_NONE;
337 }
338
339 EXPORT_API int location_bounds_unset_state_changed_cb(location_bounds_h bounds)
340 {
341         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
342         LOCATIONS_NULL_ARG_CHECK(bounds);
343
344         location_bounds_s *handle = (location_bounds_s *) bounds;
345         handle->user_cb = NULL;
346         handle->user_data = NULL;
347         return LOCATION_BOUNDS_ERROR_NONE;
348 }