2 * location-geoclue-nominatim
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Youngae Kang <youngae.kang@samsung.com>, Yunhan Kim <yhan.kim@samsung.com>,
7 * Genie Kim <daejins.kim@samsung.com>, Minjune Kim <sena06.kim@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
24 #include <location-module.h>
26 #include <geoclue/geoclue-geocode.h>
27 #include <geoclue/geoclue-reverse-geocode.h>
28 #include <geoclue/geoclue-provider.h>
37 GeoclueGeocode* geocoder;
38 GeoclueReverseGeocode* rev_geocoder;
42 LocationPositionCB pos_cb;
43 LocationAddressCB addr_cb;
48 get_geoclue_addr_from_location_addr (const LocationAddress *address)
50 if (!address) return NULL;
52 GHashTable *geoclue_addr = geoclue_address_details_new();
53 if (address->street) {
54 if (address->building_number) {
55 char *street_addr = g_strdup_printf ("%s %s", address->building_number, address->street);
56 geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_STREET, street_addr);
58 } else geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_STREET, address->street);
60 if (address->district) geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_AREA, address->district);
61 if (address->city) geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_LOCALITY, address->city);
62 if (address->state) geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_REGION, address->state);
63 if (address->country_code) geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_COUNTRY, address->country_code);
64 if (address->postal_code) geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_POSTALCODE, address->postal_code);
69 static LocationAddress*
70 get_location_addr_from_geoclue_addr (GHashTable *geoclue_addr)
72 if (!geoclue_addr) return NULL;
74 LocationAddress *addr = NULL;
76 gchar *country, *region, *locality, *postalcode, *area, *street;
78 country = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_COUNTRY);
79 region = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_REGION);
80 locality = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_LOCALITY);
81 area = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_AREA);
82 postalcode = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_POSTALCODE);
83 street = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_STREET);
85 addr = location_address_new (NULL, street, area, locality, region, country, postalcode);
89 static LocationAccuracy *
90 get_location_acc_from_geoclue_acc (GeoclueAccuracy *acc)
92 if (!acc) return NULL;
94 LocationAccuracy *accuracy = NULL;
95 GeoclueAccuracyLevel level;
98 geoclue_accuracy_get_details (acc, &level, &horiz_acc, &vert_acc);
100 if (level == GEOCLUE_ACCURACY_LEVEL_DETAILED) accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, horiz_acc, vert_acc);
101 else if (level == GEOCLUE_ACCURACY_LEVEL_STREET) accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_STREET, horiz_acc, vert_acc);
102 else if (level == GEOCLUE_ACCURACY_LEVEL_POSTALCODE) accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_POSTALCODE, horiz_acc, vert_acc);
103 else if (level == GEOCLUE_ACCURACY_LEVEL_LOCALITY) accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_LOCALITY, horiz_acc, vert_acc);
104 else if (level == GEOCLUE_ACCURACY_LEVEL_REGION) accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_REGION, horiz_acc, vert_acc);
105 else if (level == GEOCLUE_ACCURACY_LEVEL_COUNTRY) accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_COUNTRY, horiz_acc, vert_acc);
106 else accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
112 _unref_geoclue(NominatimHandle* handle)
114 if (handle->geocoder) {
115 g_object_unref (handle->geocoder);
116 handle->geocoder = NULL;
118 if (handle->rev_geocoder) {
119 g_object_unref (handle->rev_geocoder);
120 handle->rev_geocoder = NULL;
125 _ref_geoclue(NominatimHandle* handle)
127 gchar *service, *path;
128 service = g_strdup_printf ("org.freedesktop.Geoclue.Providers.Nominatim");
129 path = g_strdup_printf ("/org/freedesktop/Geoclue/Providers/Nominatim");
131 if (!handle->geocoder) handle->geocoder = geoclue_geocode_new (service, path);
132 if (!handle->rev_geocoder) handle->rev_geocoder = geoclue_reverse_geocode_new (service, path);
134 if(!handle->geocoder || !handle->rev_geocoder){
135 MOD_LOGW ("Error while creating Geoclue object.");
136 _unref_geoclue(handle);
143 address_cb (GeoclueReverseGeocode *revgeocode,
145 GeoclueAccuracy *accuracy,
149 NominatimData* data = (NominatimData*)userdata;
150 g_return_if_fail(data->addr_cb);
152 LocationAddress *addr = NULL;
153 LocationAccuracy *acc = NULL;
154 LocationError err = LOCATION_ERROR_NONE;
157 MOD_LOGW ("Error getting reverse geocode: %s", error->message);
158 err = LOCATION_ERROR_NOT_AVAILABLE;
160 if (accuracy) acc = get_location_acc_from_geoclue_acc (accuracy);
161 else acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
163 if (details) addr = get_location_addr_from_geoclue_addr (details);
166 data->addr_cb (err, addr, acc, data->userdata);
167 if (addr) location_address_free (addr);
168 if (acc) location_accuracy_free (acc);
172 static void _free_pos_list_item(gpointer data)
174 g_return_if_fail(data);
176 LocationPosition *position = (LocationPosition *)data;
177 location_position_free(position);
180 static void _free_acc_list_item(gpointer data)
182 g_return_if_fail(data);
184 LocationAccuracy *accuracy = (LocationAccuracy *)data;
185 location_accuracy_free(accuracy);
188 static void position_cb (GeoclueGeocode *geocode,
189 GeocluePositionFields fields,
193 GeoclueAccuracy *accuracy,
197 NominatimData* data = (NominatimData*)userdata;
198 GList *pos_list = NULL;
199 GList *acc_list = NULL;
201 g_return_if_fail(data->pos_cb);
203 LocationPosition *pos = NULL;
204 LocationAccuracy *acc = NULL;
205 LocationError err = LOCATION_ERROR_NONE;
208 MOD_LOGW ("Error getting geocode: %s", error->message);
209 err = LOCATION_ERROR_NOT_AVAILABLE;
211 if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE &&
212 fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
213 if(fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) pos = location_position_new (0, latitude, longitude, altitude, LOCATION_STATUS_3D_FIX);
214 else pos = location_position_new (0, latitude, longitude, 0, LOCATION_STATUS_2D_FIX);
216 pos_list = g_list_append(pos_list, pos);
218 err = LOCATION_ERROR_NOT_FOUND;
222 acc = get_location_acc_from_geoclue_acc (accuracy);
223 acc_list = g_list_append(acc_list, acc);
226 data->pos_cb (err, pos_list, acc_list, data->userdata);
228 if (pos_list) g_list_free_full(pos_list, _free_pos_list_item);
229 if (acc_list) g_list_free_full(pos_list, _free_acc_list_item);
236 get_geocode (gpointer handle,
237 const LocationAddress *addr,
241 NominatimHandle *nominatim = (NominatimHandle *)handle;
242 g_return_val_if_fail(nominatim, LOCATION_ERROR_NOT_AVAILABLE);
243 g_return_val_if_fail(addr, LOCATION_ERROR_PARAMETER);
244 g_return_val_if_fail(pos_list, LOCATION_ERROR_PARAMETER);
245 g_return_val_if_fail(acc_list, LOCATION_ERROR_PARAMETER);
247 double lat, lon, alt;
248 GeoclueAccuracy *geoclue_acc = NULL;
249 GError *error = NULL;
250 LocationPosition *pos = NULL;
251 LocationAccuracy *acc = NULL;
252 LocationError err = LOCATION_ERROR_NONE;
254 GHashTable* geoclue_addr = get_geoclue_addr_from_location_addr (addr);
255 GeocluePositionFields fields = geoclue_geocode_address_to_position (nominatim->geocoder, geoclue_addr,
257 &geoclue_acc, &error);
258 g_hash_table_destroy (geoclue_addr);
261 MOD_LOGW ("Error getting geocode: %s", error->message);
262 g_error_free (error);
263 return LOCATION_ERROR_NOT_AVAILABLE;
266 if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE &&
267 fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
268 if(fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) pos = location_position_new (0, lat, lon, alt, LOCATION_STATUS_3D_FIX);
269 else pos = location_position_new (0, lat, lon, 0, LOCATION_STATUS_2D_FIX);
271 *pos_list = g_list_append(*pos_list, pos);
274 err = LOCATION_ERROR_NOT_FOUND;
278 acc = get_location_acc_from_geoclue_acc (geoclue_acc);
279 geoclue_accuracy_free (geoclue_acc);
281 *acc_list = g_list_append(*acc_list, acc);
284 if (pos) location_position_free (pos);
285 if (acc) location_accuracy_free (acc);
292 get_geocode_async (gpointer handle,
293 const LocationAddress * addr,
294 LocationPositionCB callback,
297 NominatimHandle *nominatim = (NominatimHandle *)handle;
298 g_return_val_if_fail(nominatim, LOCATION_ERROR_NOT_AVAILABLE);
299 g_return_val_if_fail(addr, LOCATION_ERROR_PARAMETER);
300 g_return_val_if_fail(callback, LOCATION_ERROR_PARAMETER);
302 GHashTable* geoclue_addr = get_geoclue_addr_from_location_addr (addr);
303 NominatimData *data = g_new0 (NominatimData, 1);
304 data->pos_cb = callback;
305 data->userdata = userdata;
306 geoclue_geocode_address_to_position_async (nominatim->geocoder, geoclue_addr, position_cb, data);
307 g_hash_table_destroy (geoclue_addr);
309 return LOCATION_ERROR_NONE;
313 get_geocode_freetext(gpointer handle,
314 const const gchar* addr,
318 NominatimHandle *nominatim = (NominatimHandle *)handle;
319 g_return_val_if_fail(nominatim, LOCATION_ERROR_NOT_AVAILABLE);
320 g_return_val_if_fail(addr, LOCATION_ERROR_PARAMETER);
321 g_return_val_if_fail(pos_list, LOCATION_ERROR_PARAMETER);
322 g_return_val_if_fail(acc_list, LOCATION_ERROR_PARAMETER);
324 double lat, lon, alt;
325 GeoclueAccuracy *geoclue_acc = NULL;
326 GError *error = NULL;
327 LocationPosition *pos = NULL;
328 LocationAccuracy *acc = NULL;
329 LocationError err = LOCATION_ERROR_NONE;
331 GeocluePositionFields fields = geoclue_geocode_freeform_address_to_position (nominatim->geocoder, addr,
333 &geoclue_acc, &error);
335 MOD_LOGW ("Error getting geocode: %s", error->message);
336 g_error_free (error);
337 return LOCATION_ERROR_NOT_AVAILABLE;
340 if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE &&
341 fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
342 if(fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) pos = location_position_new (0, lat, lon, alt, LOCATION_STATUS_3D_FIX);
343 else pos = location_position_new (0, lat, lon, 0, LOCATION_STATUS_2D_FIX);
344 *pos_list = g_list_append(*pos_list, pos);
347 err = LOCATION_ERROR_NOT_FOUND;
351 acc = get_location_acc_from_geoclue_acc (geoclue_acc);
352 geoclue_accuracy_free (geoclue_acc);
353 *acc_list = g_list_append(*acc_list, acc);
356 if (pos) location_position_free (pos);
357 if (acc) location_accuracy_free (acc);
363 get_geocode_freetext_async (gpointer handle,
365 LocationPositionCB callback,
368 NominatimHandle *nominatim = (NominatimHandle *)handle;
369 g_return_val_if_fail(nominatim, LOCATION_ERROR_NOT_AVAILABLE);
370 g_return_val_if_fail(addr, LOCATION_ERROR_PARAMETER);
371 g_return_val_if_fail(callback, LOCATION_ERROR_PARAMETER);
373 NominatimData *data = g_new0 (NominatimData, 1);
374 data->pos_cb = callback;
375 data->userdata = userdata;
376 geoclue_geocode_freeform_address_to_position_async (nominatim->geocoder, addr, position_cb, data);
378 return LOCATION_ERROR_NONE;
382 get_reverse_geocode(gpointer handle,
383 const LocationPosition *pos,
384 LocationAddress **addr,
385 LocationAccuracy **acc)
387 NominatimHandle *nominatim = (NominatimHandle *)handle;
388 g_return_val_if_fail(nominatim, LOCATION_ERROR_NOT_AVAILABLE);
389 g_return_val_if_fail(pos, LOCATION_ERROR_PARAMETER);
390 g_return_val_if_fail(addr, LOCATION_ERROR_PARAMETER);
391 g_return_val_if_fail(acc, LOCATION_ERROR_PARAMETER);
393 GeoclueAccuracy *addr_acc = NULL;
394 GError *error = NULL;
395 GHashTable* geoclue_addr = NULL;
397 double lat = pos->latitude;
398 double lon = pos->longitude;
399 GeoclueAccuracy *pos_acc = geoclue_accuracy_new (GEOCLUE_ACCURACY_LEVEL_DETAILED, 0.0, 0.0);
401 gboolean success = geoclue_reverse_geocode_position_to_address (nominatim->rev_geocoder, lat, lon,
402 pos_acc, &geoclue_addr,
404 geoclue_accuracy_free (pos_acc);
406 if (!success || error) {
407 MOD_LOGW ("Error getting reverse geocode: %s", error->message);
408 g_error_free (error);
409 return LOCATION_ERROR_NOT_AVAILABLE;
413 *acc = get_location_acc_from_geoclue_acc (addr_acc);
414 geoclue_accuracy_free (addr_acc);
415 } else *acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
417 *addr = get_location_addr_from_geoclue_addr (geoclue_addr);
418 g_hash_table_destroy (geoclue_addr);
421 return LOCATION_ERROR_NONE;
425 get_reverse_geocode_async (gpointer handle,
426 const LocationPosition *pos,
427 LocationAddressCB callback,
430 NominatimHandle *nominatim = (NominatimHandle *)handle;
431 g_return_val_if_fail(nominatim, LOCATION_ERROR_NOT_AVAILABLE);
432 g_return_val_if_fail(pos, LOCATION_ERROR_PARAMETER);
433 g_return_val_if_fail(callback, LOCATION_ERROR_PARAMETER);
435 double lat = pos->latitude;
436 double lon = pos->longitude;
437 GeoclueAccuracy *pos_acc = geoclue_accuracy_new (GEOCLUE_ACCURACY_LEVEL_DETAILED, 0.0, 0.0);;
438 NominatimData *data = g_new0 (NominatimData, 1);
439 data->addr_cb = callback;
440 data->userdata = userdata;
441 geoclue_reverse_geocode_position_to_address_async (nominatim->rev_geocoder,
444 geoclue_accuracy_free (pos_acc);
446 return LOCATION_ERROR_NONE;
450 get_service_name (gpointer handle,
451 gchar **service_name)
453 NominatimHandle *nominatim = (NominatimHandle *)handle;
454 g_return_val_if_fail(nominatim, LOCATION_ERROR_NOT_AVAILABLE);
455 g_return_val_if_fail (service_name, LOCATION_ERROR_PARAMETER);
456 *service_name = g_strdup (nominatim->service_name);
457 return LOCATION_ERROR_NONE;
460 LOCATION_MODULE_API gpointer
461 init (LocModGeoOps* ops)
464 g_return_val_if_fail(ops, NULL);
465 NominatimHandle *handle = g_new0 (NominatimHandle, 1);
466 if (!_ref_geoclue(handle)) {
470 handle->service_name = g_strdup ("Nominatim");
471 ops->get_service_name = get_service_name;
472 ops->get_geocode = get_geocode;
473 ops->get_geocode_freetext = get_geocode_freetext;
474 ops->get_reverse_geocode = get_reverse_geocode;
475 ops->get_geocode_async = get_geocode_async;
476 ops->get_geocode_freetext_async = get_geocode_freetext_async;
477 ops->get_reverse_geocode_async = get_reverse_geocode_async;
478 return (gpointer)handle;
481 LOCATION_MODULE_API void
482 shutdown (gpointer handle)
484 MOD_LOGD("shutdown");
485 g_return_if_fail(handle);
486 NominatimHandle *nominatim = (NominatimHandle *)handle;
487 g_free (nominatim->service_name);
488 _unref_geoclue(nominatim);