*/
#include "config.h"
-
-#include <string.h>
-#include <time.h>
-
-#include <glib/gi18n-lib.h>
-
-#include <telepathy-glib/account-manager.h>
-#include <telepathy-glib/util.h>
-
-#include <geoclue/geoclue-master.h>
-
-#include <extensions/extensions.h>
-
#include "empathy-location-manager.h"
-#include "libempathy/empathy-enum-types.h"
-#include "libempathy/empathy-gsettings.h"
-#include "libempathy/empathy-location.h"
-#include "libempathy/empathy-utils.h"
-#include "libempathy/empathy-time.h"
+#include <tp-account-widgets/tpaw-time.h>
+
+#include "empathy-gsettings.h"
+#include "empathy-location.h"
+#include "empathy-geoclue-helper.h"
#define DEBUG_FLAG EMPATHY_DEBUG_LOCATION
-#include "libempathy/empathy-debug.h"
+#include "empathy-debug.h"
/* Seconds before updating the location */
#define TIMEOUT 10
static EmpathyLocationManager *location_manager = NULL;
+typedef enum
+{
+ GEOCLUE_NONE = 0,
+ GEOCLUE_STARTING,
+ GEOCLUE_STARTED,
+ GEOCLUE_FAILED,
+} GeoclueStatus;
+
struct _EmpathyLocationManagerPrivate {
- gboolean geoclue_is_setup;
+ GeoclueStatus geoclue_status;
/* Contains the location to be sent to accounts. Geoclue is used
* to populate it. This HashTable uses Telepathy's style (string,
* GValue). Keys are defined in empathy-location.h
GSettings *gsettings_loc;
- GeoclueResourceFlags resources;
- GeoclueMasterClient *gc_client;
- GeocluePosition *gc_position;
- GeoclueAddress *gc_address;
-
gboolean reduce_accuracy;
TpAccountManager *account_manager;
+ EmpathyGeoclueHelper *geoclue;
/* The idle id for publish_on_idle func */
guint timeout_id;
tp_clear_object (&self->priv->account_manager);
tp_clear_object (&self->priv->gsettings_loc);
- tp_clear_object (&self->priv->gc_client);
- tp_clear_object (&self->priv->gc_position);
- tp_clear_object (&self->priv->gc_address);
tp_clear_pointer (&self->priv->location, g_hash_table_unref);
if (dispose != NULL)
GList *accounts, *l;
GError *error = NULL;
- if (!tp_account_manager_prepare_finish (manager, result, &error))
+ if (!tp_proxy_prepare_finish (manager, result, &error))
{
DEBUG ("Failed to prepare account manager: %s", error->message);
g_error_free (error);
goto out;
}
- accounts = tp_account_manager_get_valid_accounts (manager);
+ accounts = tp_account_manager_dup_valid_accounts (manager);
for (l = accounts; l; l = l->next)
{
TpConnection *conn = tp_account_get_connection (TP_ACCOUNT (l->data));
if (conn != NULL)
publish_location (data->self, conn, data->force_publication);
}
- g_list_free (accounts);
+ g_list_free_full (accounts, g_object_unref);
out:
g_object_unref (data->self);
data->self = g_object_ref (self);
data->force_publication = force_publication;
- tp_account_manager_prepare_async (self->priv->account_manager, NULL,
+ tp_proxy_prepare_async (self->priv->account_manager, NULL,
publish_to_all_am_prepared_cb, data);
}
}
static void
-update_timestamp (EmpathyLocationManager *self)
+update_location (EmpathyLocationManager *self,
+ GClueLocation *proxy)
{
+ gdouble latitude, longitude, accuracy;
+ const gchar *desc;
gint64 timestamp;
- timestamp = empathy_time_get_current ();
- tp_asv_set_int64 (self->priv->location, EMPATHY_LOCATION_TIMESTAMP,
- timestamp);
-
- DEBUG ("\t - Timestamp: %" G_GINT64_FORMAT, timestamp);
-}
-
-static void
-address_changed_cb (GeoclueAddress *address,
- int timestamp,
- GHashTable *details,
- GeoclueAccuracy *accuracy,
- gpointer user_data)
-{
- EmpathyLocationManager *self = user_data;
- GeoclueAccuracyLevel level;
- GHashTableIter iter;
- gpointer key, value;
-
- geoclue_accuracy_get_details (accuracy, &level, NULL, NULL);
- DEBUG ("New address (accuracy level %d):", level);
- /* FIXME: Publish accuracy level also considering the position's */
-
- g_hash_table_remove (self->priv->location, EMPATHY_LOCATION_STREET);
- g_hash_table_remove (self->priv->location, EMPATHY_LOCATION_AREA);
- g_hash_table_remove (self->priv->location, EMPATHY_LOCATION_REGION);
- g_hash_table_remove (self->priv->location, EMPATHY_LOCATION_COUNTRY);
- g_hash_table_remove (self->priv->location, EMPATHY_LOCATION_COUNTRY_CODE);
- g_hash_table_remove (self->priv->location, EMPATHY_LOCATION_POSTAL_CODE);
-
- if (g_hash_table_size (details) == 0)
- {
- DEBUG ("\t - (Empty)");
- return;
- }
-
- g_hash_table_iter_init (&iter, details);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
- /* Discard street information if reduced accuracy is on */
- if (self->priv->reduce_accuracy &&
- !tp_strdiff (key, EMPATHY_LOCATION_STREET))
- continue;
-
- tp_asv_set_string (self->priv->location, key, value);
-
- DEBUG ("\t - %s: %s", (gchar *) key, (gchar *) value);
- }
-
- update_timestamp (self);
- if (self->priv->timeout_id == 0)
- self->priv->timeout_id = g_timeout_add_seconds (TIMEOUT, publish_on_idle,
- self);
-}
-
-static void
-initial_address_cb (GeoclueAddress *address,
- int timestamp,
- GHashTable *details,
- GeoclueAccuracy *accuracy,
- GError *error,
- gpointer self)
-{
- if (error)
- {
- DEBUG ("Error: %s", error->message);
- g_error_free (error);
- }
- else
- {
- address_changed_cb (address, timestamp, details, accuracy, self);
- }
-}
-
-static void
-position_changed_cb (GeocluePosition *position,
- GeocluePositionFields fields,
- int timestamp,
- double latitude,
- double longitude,
- double altitude,
- GeoclueAccuracy *accuracy,
- gpointer user_data)
-{
- EmpathyLocationManager *self = user_data;
- GeoclueAccuracyLevel level;
- gdouble mean, horizontal, vertical;
+ latitude = gclue_location_get_latitude (proxy);
+ longitude = gclue_location_get_longitude (proxy);
+ accuracy = gclue_location_get_accuracy (proxy);
+ desc = gclue_location_get_description (proxy);
- geoclue_accuracy_get_details (accuracy, &level, &horizontal, &vertical);
- DEBUG ("New position (accuracy level %d)", level);
- if (level == GEOCLUE_ACCURACY_LEVEL_NONE)
- return;
+ DEBUG ("Location updated: (%f %f) accuracy: %f (%s)",
+ latitude, longitude, accuracy, desc);
- if (fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)
+ if (self->priv->reduce_accuracy)
{
-
- if (self->priv->reduce_accuracy)
- /* Truncate at 1 decimal place */
- longitude = ((int) (longitude * 10)) / 10.0;
-
- tp_asv_set_double (self->priv->location, EMPATHY_LOCATION_LON, longitude);
-
- DEBUG ("\t - Longitude: %f", longitude);
+ /* Truncate at 1 decimal place */
+ latitude = ((int) (latitude * 10)) / 10.0;
+ longitude = ((int) (longitude * 10)) / 10.0;
}
else
{
- g_hash_table_remove (self->priv->location, EMPATHY_LOCATION_LON);
+ /* Include the description only if we are not asked to reduce the
+ * accuracy as it can contains a pretty specific description of the
+ * location. */
+ tp_asv_set_string (self->priv->location, EMPATHY_LOCATION_DESCRIPTION,
+ desc);
}
- if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE)
- {
- if (self->priv->reduce_accuracy)
- /* Truncate at 1 decimal place */
- latitude = ((int) (latitude * 10)) / 10.0;
-
- tp_asv_set_double (self->priv->location, EMPATHY_LOCATION_LAT, latitude);
+ tp_asv_set_double (self->priv->location, EMPATHY_LOCATION_LAT, latitude);
+ tp_asv_set_double (self->priv->location, EMPATHY_LOCATION_LON, longitude);
+ tp_asv_set_double (self->priv->location, EMPATHY_LOCATION_ACCURACY, accuracy);
- DEBUG ("\t - Latitude: %f", latitude);
- }
- else
- {
- g_hash_table_remove (self->priv->location, EMPATHY_LOCATION_LAT);
- }
-
- if (fields & GEOCLUE_POSITION_FIELDS_ALTITUDE)
- {
- tp_asv_set_double (self->priv->location, EMPATHY_LOCATION_ALT, altitude);
-
- DEBUG ("\t - Altitude: %f", altitude);
- }
- else
- {
- g_hash_table_remove (self->priv->location, EMPATHY_LOCATION_ALT);
- }
-
- if (level == GEOCLUE_ACCURACY_LEVEL_DETAILED)
- {
- mean = (horizontal + vertical) / 2.0;
- tp_asv_set_double (self->priv->location, EMPATHY_LOCATION_ACCURACY, mean);
-
- DEBUG ("\t - Accuracy: %f", mean);
- }
- else
- {
- g_hash_table_remove (self->priv->location, EMPATHY_LOCATION_ACCURACY);
- }
+ timestamp = tpaw_time_get_current ();
+ tp_asv_set_int64 (self->priv->location, EMPATHY_LOCATION_TIMESTAMP,
+ timestamp);
- update_timestamp (self);
if (self->priv->timeout_id == 0)
self->priv->timeout_id = g_timeout_add_seconds (TIMEOUT, publish_on_idle,
self);
}
static void
-initial_position_cb (GeocluePosition *position,
- GeocluePositionFields fields,
- int timestamp,
- double latitude,
- double longitude,
- double altitude,
- GeoclueAccuracy *accuracy,
- GError *error,
- gpointer self)
+location_changed_cb (EmpathyGeoclueHelper *geoclue,
+ GClueLocation *location,
+ EmpathyLocationManager *self)
{
- if (error)
- {
- DEBUG ("Error: %s", error->message);
- g_error_free (error);
- }
- else
- {
- position_changed_cb (position, fields, timestamp, latitude, longitude,
- altitude, accuracy, self);
- }
+ update_location (self, location);
}
-static gboolean
-set_requirements (EmpathyLocationManager *self)
+static void
+geoclue_new_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ EmpathyLocationManager *self = EMPATHY_LOCATION_MANAGER (user_data);
GError *error = NULL;
+ GClueLocation *location;
- if (!geoclue_master_client_set_requirements (self->priv->gc_client,
- GEOCLUE_ACCURACY_LEVEL_COUNTRY, 0, FALSE, self->priv->resources,
- &error))
+ self->priv->geoclue = empathy_geoclue_helper_new_started_finish (result,
+ &error);
+
+ if (self->priv->geoclue == NULL)
{
- DEBUG ("set_requirements failed: %s", error->message);
+ DEBUG ("Failed to create Geoclue client: %s", error->message);
g_error_free (error);
- return FALSE;
+ self->priv->geoclue_status = GEOCLUE_FAILED;
+ return;
}
- return TRUE;
-}
+ self->priv->geoclue_status = GEOCLUE_STARTED;
-static void
-update_resources (EmpathyLocationManager *self)
-{
- DEBUG ("Updating resources %d", self->priv->resources);
+ g_signal_connect_object (self->priv->geoclue, "location-changed",
+ G_CALLBACK (location_changed_cb), self, 0);
- if (!self->priv->geoclue_is_setup)
- return;
-
- /* As per Geoclue bug #15126, using NONE results in no address
- * being found as geoclue-manual report an empty address with
- * accuracy = NONE */
- if (!set_requirements (self))
- return;
-
- geoclue_address_get_address_async (self->priv->gc_address,
- initial_address_cb, self);
- geoclue_position_get_position_async (self->priv->gc_position,
- initial_position_cb, self);
+ location = empathy_geoclue_helper_get_location (self->priv->geoclue);
+ if (location != NULL)
+ update_location (self, location);
}
static void
setup_geoclue (EmpathyLocationManager *self)
{
- GeoclueMaster *master;
- GError *error = NULL;
-
- DEBUG ("Setting up Geoclue");
- master = geoclue_master_get_default ();
- self->priv->gc_client = geoclue_master_create_client (master, NULL, &error);
- g_object_unref (master);
-
- if (self->priv->gc_client == NULL)
- {
- DEBUG ("Failed to GeoclueMasterClient: %s", error->message);
- g_error_free (error);
- return;
- }
-
- if (!set_requirements (self))
- return;
-
- /* Get updated when the position is changes */
- self->priv->gc_position = geoclue_master_client_create_position (
- self->priv->gc_client, &error);
- if (self->priv->gc_position == NULL)
- {
- DEBUG ("Failed to create GeocluePosition: %s", error->message);
- g_error_free (error);
- return;
- }
-
- g_signal_connect (G_OBJECT (self->priv->gc_position), "position-changed",
- G_CALLBACK (position_changed_cb), self);
-
- /* Get updated when the address changes */
- self->priv->gc_address = geoclue_master_client_create_address (
- self->priv->gc_client, &error);
- if (self->priv->gc_address == NULL)
+ switch (self->priv->geoclue_status)
{
- DEBUG ("Failed to create GeoclueAddress: %s", error->message);
- g_error_free (error);
+ case GEOCLUE_NONE:
+ g_assert (self->priv->geoclue == NULL);
+ self->priv->geoclue_status = GEOCLUE_STARTING;
+ empathy_geoclue_helper_new_started_async (0, geoclue_new_cb, self);
+ break;
+ case GEOCLUE_STARTED:
+ case GEOCLUE_STARTING:
+ case GEOCLUE_FAILED:
return;
}
-
- g_signal_connect (G_OBJECT (self->priv->gc_address), "address-changed",
- G_CALLBACK (address_changed_cb), self);
-
- self->priv->geoclue_is_setup = TRUE;
}
static void
if (g_settings_get_boolean (gsettings_loc, key))
{
- if (!self->priv->geoclue_is_setup)
- setup_geoclue (self);
- /* if still not setup than the init failed */
- if (!self->priv->geoclue_is_setup)
- return;
-
- geoclue_address_get_address_async (self->priv->gc_address,
- initial_address_cb, self);
- geoclue_position_get_position_async (self->priv->gc_position,
- initial_position_cb, self);
+ setup_geoclue (self);
}
else
{
*/
g_hash_table_remove_all (self->priv->location);
publish_to_all_connections (self, TRUE);
- }
-
-}
-
-static void
-resource_cb (GSettings *gsettings_loc,
- const gchar *key,
- gpointer user_data)
-{
- EmpathyLocationManager *self = EMPATHY_LOCATION_MANAGER (user_data);
- GeoclueResourceFlags resource = 0;
- DEBUG ("%s changed", key);
-
- if (!tp_strdiff (key, EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK))
- resource = GEOCLUE_RESOURCE_NETWORK;
- if (!tp_strdiff (key, EMPATHY_PREFS_LOCATION_RESOURCE_CELL))
- resource = GEOCLUE_RESOURCE_CELL;
- if (!tp_strdiff (key, EMPATHY_PREFS_LOCATION_RESOURCE_GPS))
- resource = GEOCLUE_RESOURCE_GPS;
-
- if (g_settings_get_boolean (gsettings_loc, key))
- self->priv->resources |= resource;
- else
- self->priv->resources &= ~resource;
-
- if (self->priv->geoclue_is_setup)
- update_resources (self);
-}
-
-static void
-accuracy_cb (GSettings *gsettings_loc,
- const gchar *key,
- gpointer user_data)
-{
- EmpathyLocationManager *self = EMPATHY_LOCATION_MANAGER (user_data);
-
- DEBUG ("%s changed", key);
-
- self->priv->reduce_accuracy = g_settings_get_boolean (gsettings_loc, key);
-
- if (!self->priv->geoclue_is_setup)
- return;
-
- geoclue_address_get_address_async (self->priv->gc_address,
- initial_address_cb, self);
- geoclue_position_get_position_async (self->priv->gc_position,
- initial_position_cb, self);
+ g_clear_object (&self->priv->geoclue);
+ self->priv->geoclue_status = GEOCLUE_NONE;
+ }
}
static void
EmpathyLocationManager *self = user_data;
GError *error = NULL;
- if (!tp_account_manager_prepare_finish (account_manager, result, &error))
+ if (!tp_proxy_prepare_finish (account_manager, result, &error))
{
DEBUG ("Failed to prepare account manager: %s", error->message);
g_error_free (error);
return;
}
- accounts = tp_account_manager_get_valid_accounts (account_manager);
+ accounts = tp_account_manager_dup_valid_accounts (account_manager);
for (l = accounts; l != NULL; l = l->next)
{
TpAccount *account = TP_ACCOUNT (l->data);
tp_g_signal_connect_object (account, "status-changed",
G_CALLBACK (new_connection_cb), self, 0);
}
- g_list_free (accounts);
+ g_list_free_full (accounts, g_object_unref);
}
static void
EMPATHY_TYPE_LOCATION_MANAGER, EmpathyLocationManagerPrivate);
self->priv = priv;
- priv->geoclue_is_setup = FALSE;
priv->location = tp_asv_new (NULL, NULL);
priv->gsettings_loc = g_settings_new (EMPATHY_PREFS_LOCATION_SCHEMA);
/* Setup account status callbacks */
priv->account_manager = tp_account_manager_dup ();
- tp_account_manager_prepare_async (priv->account_manager, NULL,
+ tp_proxy_prepare_async (priv->account_manager, NULL,
account_manager_prepared_cb, self);
/* Setup settings status callbacks */
g_signal_connect (priv->gsettings_loc,
"changed::" EMPATHY_PREFS_LOCATION_PUBLISH,
G_CALLBACK (publish_cb), self);
- g_signal_connect (priv->gsettings_loc,
- "changed::" EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK,
- G_CALLBACK (resource_cb), self);
- g_signal_connect (priv->gsettings_loc,
- "changed::" EMPATHY_PREFS_LOCATION_RESOURCE_CELL,
- G_CALLBACK (resource_cb), self);
- g_signal_connect (priv->gsettings_loc,
- "changed::" EMPATHY_PREFS_LOCATION_RESOURCE_GPS,
- G_CALLBACK (resource_cb), self);
- g_signal_connect (priv->gsettings_loc,
- "changed::" EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY,
- G_CALLBACK (accuracy_cb), self);
-
- resource_cb (priv->gsettings_loc, EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK,
- self);
- resource_cb (priv->gsettings_loc, EMPATHY_PREFS_LOCATION_RESOURCE_CELL, self);
- resource_cb (priv->gsettings_loc, EMPATHY_PREFS_LOCATION_RESOURCE_GPS, self);
- accuracy_cb (priv->gsettings_loc, EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY,
- self);
+
publish_cb (priv->gsettings_loc, EMPATHY_PREFS_LOCATION_PUBLISH, self);
}