2 * Copyright (C) 2008 Collabora Ltd.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Authors: Pierre-Luc Beaudoin <pierre-luc@pierlux.com>
26 #include <glib/gi18n.h>
28 #include <telepathy-glib/util.h>
31 #include <geoclue/geoclue-master.h>
34 #include <extensions/extensions.h>
36 #include "empathy-location-manager.h"
37 #include "empathy-conf.h"
39 #include "libempathy/empathy-enum-types.h"
40 #include "libempathy/empathy-location.h"
41 #include "libempathy/empathy-contact-factory.h"
42 #include "libempathy/empathy-utils.h"
44 #define DEBUG_FLAG EMPATHY_DEBUG_LOCATION
45 #include "libempathy/empathy-debug.h"
47 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyLocationManager)
54 GeoclueResourceFlags resources;
55 GeoclueMasterClient *gc_client;
56 GeocluePosition *gc_position;
57 GeoclueAddress *gc_address;
59 } EmpathyLocationManagerPriv;
61 static void location_manager_finalize (GObject *object);
62 static void location_manager_get_property (GObject *object, guint param_id,
63 GValue *value, GParamSpec *pspec);
64 static void location_manager_set_property (GObject *object, guint param_id,
65 const GValue *value, GParamSpec *pspec);
67 static void position_changed_cb (GeocluePosition *position,
68 GeocluePositionFields fields, int timestamp, double latitude,
69 double longitude, double altitude, GeoclueAccuracy *accuracy,
71 static void address_changed_cb (GeoclueAddress *address, int timestamp,
72 GHashTable *details, GeoclueAccuracy *accuracy, gpointer user_data);
73 static void setup_geoclue (EmpathyLocationManager *location_manager);
74 static void publish_cb (EmpathyConf *conf, const gchar *key,
76 static void update_resources (EmpathyLocationManager *location_manager);
77 static void resource_cb (EmpathyConf *conf, const gchar *key,
81 G_DEFINE_TYPE (EmpathyLocationManager, empathy_location_manager, G_TYPE_OBJECT);
89 empathy_location_manager_class_init (EmpathyLocationManagerClass *class)
91 GObjectClass *object_class;
93 object_class = G_OBJECT_CLASS (class);
95 object_class->finalize = location_manager_finalize;
96 object_class->get_property = location_manager_get_property;
97 object_class->set_property = location_manager_set_property;
99 g_type_class_add_private (object_class, sizeof (EmpathyLocationManagerPriv));
103 publish_location (EmpathyLocationManager *location_manager, McAccount *account)
105 EmpathyLocationManagerPriv *priv;
106 guint connection_status = -1;
107 gboolean can_publish;
108 EmpathyConf *conf = empathy_conf_get ();
109 EmpathyContactFactory *factory = empathy_contact_factory_new ();
110 priv = GET_PRIV (location_manager);
112 if (!empathy_conf_get_bool (conf, EMPATHY_PREFS_LOCATION_PUBLISH, &can_publish))
118 connection_status = mission_control_get_connection_status (priv->mc,
121 if (connection_status != TP_CONNECTION_STATUS_CONNECTED)
124 DEBUG ("Publishing location to account %s", mc_account_get_display_name (account));
126 empathy_contact_factory_set_location (factory, account, priv->location);
130 publish_location_to_all_accounts (EmpathyLocationManager *location_manager)
132 GList *accounts = NULL, *l;
134 accounts = mc_accounts_list_by_enabled (TRUE);
135 for (l = accounts; l; l = l->next)
137 publish_location (location_manager, l->data);
140 mc_accounts_list_free (accounts);
144 account_status_changed_cb (MissionControl *mc,
145 TpConnectionStatus status,
147 TpConnectionStatusReason reason,
148 const gchar *unique_name,
149 gpointer *location_manager)
151 DEBUG ("Account %s changed status to %d", unique_name, status);
152 McAccount *account = mc_account_lookup (unique_name);
153 if (account && status == TP_CONNECTION_STATUS_CONNECTED)
154 publish_location (EMPATHY_LOCATION_MANAGER (location_manager), account);
158 empathy_location_manager_init (EmpathyLocationManager *location_manager)
161 EmpathyLocationManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (location_manager,
162 EMPATHY_TYPE_LOCATION_MANAGER, EmpathyLocationManagerPriv);
164 location_manager->priv = priv;
165 priv->is_setup = FALSE;
166 priv->mc = empathy_mission_control_new ();
167 priv->location = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
168 (GDestroyNotify) tp_g_value_slice_free);
170 // Setup settings status callbacks
171 conf = empathy_conf_get ();
172 empathy_conf_notify_add (conf, EMPATHY_PREFS_LOCATION_PUBLISH, publish_cb,
174 empathy_conf_notify_add (conf, EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK,
175 resource_cb, location_manager);
176 empathy_conf_notify_add (conf, EMPATHY_PREFS_LOCATION_RESOURCE_CELL,
177 resource_cb, location_manager);
178 empathy_conf_notify_add (conf, EMPATHY_PREFS_LOCATION_RESOURCE_GPS,
179 resource_cb, location_manager);
181 publish_cb (conf, EMPATHY_PREFS_LOCATION_PUBLISH, location_manager);
182 resource_cb (conf, EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK, location_manager);
183 resource_cb (conf, EMPATHY_PREFS_LOCATION_RESOURCE_CELL, location_manager);
184 resource_cb (conf, EMPATHY_PREFS_LOCATION_RESOURCE_GPS, location_manager);
186 // Setup account status callbacks
187 priv->token = empathy_connect_to_account_status_changed (priv->mc,
188 G_CALLBACK (account_status_changed_cb), location_manager, NULL);
193 location_manager_finalize (GObject *object)
195 EmpathyLocationManagerPriv *priv;
197 priv = GET_PRIV (object);
199 DEBUG ("finalize: %p", object);
201 G_OBJECT_CLASS (empathy_location_manager_parent_class)->finalize (object);
206 location_manager_get_property (GObject *object,
211 EmpathyLocationManagerPriv *priv;
213 priv = GET_PRIV (object);
218 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
225 location_manager_set_property (GObject *object,
230 EmpathyLocationManagerPriv *priv;
232 priv = GET_PRIV (object);
237 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
243 EmpathyLocationManager *
244 empathy_location_manager_get_default (void)
246 static EmpathyLocationManager *singleton = NULL;
247 if (singleton == NULL)
248 singleton = g_object_new (EMPATHY_TYPE_LOCATION_MANAGER, NULL);
255 position_changed_cb (GeocluePosition *position,
256 GeocluePositionFields fields,
261 GeoclueAccuracy *accuracy,
264 GeoclueAccuracyLevel level;
266 geoclue_accuracy_get_details (accuracy, &level, NULL, NULL);
267 DEBUG ("New position (accuracy level %d)", level);
268 if (level == GEOCLUE_ACCURACY_LEVEL_NONE)
271 if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE &&
272 fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
273 DEBUG ("\t%f, %f", latitude, longitude);
275 publish_location_to_all_accounts (EMPATHY_LOCATION_MANAGER (user_data));
277 DEBUG ("- latitude and longitude not valid.");
283 address_changed_cb (GeoclueAddress *address,
286 GeoclueAccuracy *accuracy,
289 GeoclueAccuracyLevel level;
290 geoclue_accuracy_get_details (accuracy, &level, NULL, NULL);
291 DEBUG ("New address (accuracy level %d):\n", level);
293 publish_location_to_all_accounts (EMPATHY_LOCATION_MANAGER (user_data));
298 update_resources (EmpathyLocationManager *location_manager)
300 EmpathyLocationManagerPriv *priv;
302 priv = GET_PRIV (location_manager);
307 DEBUG ("Updating resources");
309 if (!geoclue_master_client_set_requirements (priv->gc_client,
310 GEOCLUE_ACCURACY_LEVEL_COUNTRY, 0, TRUE, priv->resources,
312 g_printerr ("set_requirements failed");
317 setup_geoclue (EmpathyLocationManager *location_manager)
319 EmpathyLocationManagerPriv *priv;
321 priv = GET_PRIV (location_manager);
323 GeoclueMaster *master;
324 GError *error = NULL;
326 DEBUG ("Setting up Geoclue");
327 master = geoclue_master_get_default ();
328 priv->gc_client = geoclue_master_create_client (master, NULL, NULL);
329 g_object_unref (master);
331 update_resources (location_manager);
333 /* Get updated when the position is changes */
334 priv->gc_position = geoclue_master_client_create_position (
335 priv->gc_client, &error);
336 if (priv->gc_position == NULL)
338 g_printerr ("Failed to create GeocluePosition: %s", error->message);
342 g_signal_connect (G_OBJECT (priv->gc_position), "position-changed",
343 G_CALLBACK (position_changed_cb), location_manager);
345 /* Get updated when the address changes */
346 priv->gc_address = geoclue_master_client_create_address (
347 priv->gc_client, &error);
348 if (priv->gc_address == NULL)
350 g_printerr ("Failed to create GeoclueAddress: %s", error->message);
354 g_signal_connect (G_OBJECT (priv->gc_address), "address-changed",
355 G_CALLBACK (address_changed_cb), location_manager);
357 priv->is_setup = TRUE;
361 publish_cb (EmpathyConf *conf,
365 EmpathyLocationManager *manager = EMPATHY_LOCATION_MANAGER (user_data);
366 EmpathyLocationManagerPriv *priv;
367 gboolean can_publish;
369 DEBUG ("Publish Conf changed");
370 priv = GET_PRIV (manager);
371 if (!empathy_conf_get_bool (conf, key, &can_publish))
374 if (can_publish && !priv->is_setup)
375 setup_geoclue (manager);
380 resource_cb (EmpathyConf *conf,
384 EmpathyLocationManager *manager = EMPATHY_LOCATION_MANAGER (user_data);
385 EmpathyLocationManagerPriv *priv;
386 GeoclueResourceFlags resource = 0;
387 gboolean resource_enabled;
389 priv = GET_PRIV (manager);
390 DEBUG ("A Resource Conf changed");
392 if (empathy_conf_get_bool (conf, key, &resource_enabled))
394 if (strcmp (key, EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK))
395 resource = GEOCLUE_RESOURCE_NETWORK;
396 if (strcmp (key, EMPATHY_PREFS_LOCATION_RESOURCE_CELL))
397 resource = GEOCLUE_RESOURCE_CELL;
398 if (strcmp (key, EMPATHY_PREFS_LOCATION_RESOURCE_GPS))
399 resource = GEOCLUE_RESOURCE_GPS;
401 if (resource_enabled)
402 priv->resources |= resource;
404 priv->resources &= resource;
406 update_resources (manager);