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