Release Tizen2.0 beta
[framework/location/gps-manager.git] / gps-manager / gps_manager.c
index 5e976f3..4dcb23a 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "server.h"
 #include "last_position.h"
+#include "debug_util.h"
 
 #define GEOCLUE_GPSMANAGER_DBUS_SERVICE        "org.freedesktop.Geoclue.Providers.GpsManager"
 #define GEOCLUE_GPSMANAGER_DBUS_PATH   "/org/freedesktop/Geoclue/Providers/GpsManager"
@@ -50,6 +51,7 @@
 typedef struct {
        GcProvider parent;
        GMainLoop *loop;
+       GMutex *mutex;
 
        GeoclueStatus status;
        pos_data_t position;
@@ -59,7 +61,8 @@ typedef struct {
        pos_data_t last_position;
        sv_data_t last_satellite;
 
-       GHashTable *connections;
+       gboolean is_running;
+       gint client_count;
 } GeoclueGpsManager;
 
 typedef struct {
@@ -82,19 +85,13 @@ G_DEFINE_TYPE_WITH_CODE(GeoclueGpsManager, geoclue_gpsmanager, GC_TYPE_PROVIDER,
                        G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_SATELLITE, init_satellite)
                        G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_GEOCLUE, init_geoclue));
 
-static void constructed(GObject * object)
+static GObject* constructor (GType type, guint n_props, GObjectConstructParam *props)
 {
-       GeoclueGpsManager *gps_manager = GEOCLUE_GPSMANAGER(object);
+       GObject *object;
 
-       gps_manager->connections = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+       object = ((GObjectClass *) geoclue_gpsmanager_parent_class)->constructor(type, n_props, props);
 
-       gps_manager->status = GEOCLUE_STATUS_UNAVAILABLE;
-
-       memset(&gps_manager->position, 0x00, sizeof(pos_data_t));
-       memset(&gps_manager->satellite, 0x00, sizeof(sv_data_t));
-       memset(&gps_manager->nmea, 0x00, sizeof(nmea_data_t));
-
-       ((GObjectClass *) geoclue_gpsmanager_parent_class)->constructed(object);
+       return object;
 }
 
 static void finalize(GObject * object)
@@ -105,9 +102,7 @@ static void finalize(GObject * object)
 static void dispose(GObject * object)
 {
        GeoclueGpsManager *gpsmanager = GEOCLUE_GPSMANAGER(object);
-
-       g_hash_table_destroy(gpsmanager->connections);
-
+       g_mutex_free(gpsmanager->mutex);
        ((GObjectClass *) geoclue_gpsmanager_parent_class)->dispose(object);
 }
 
@@ -131,33 +126,87 @@ static gboolean get_provider_info(GcIfaceGeoclue * geoclue, gchar ** name, gchar
        return TRUE;
 }
 
-static void print_option(gpointer key, gpointer value, gpointer data)
+static void start_tracking(GeoclueGpsManager * gpsmanager)
 {
-       g_print("   %s - %s\n", (char *)key, (char *)value);
+       LOG_GPS(DBG_LOW, "start_tracking");
+       gpsmanager->status = GEOCLUE_STATUS_ACQUIRING;
+       g_mutex_lock(gpsmanager->mutex);
+       if (request_start_session() == TRUE) {
+               gpsmanager->is_running = TRUE;
+       } else {
+               LOG_GPS(DBG_ERR, "Fail to request_start_session");
+       }
+       g_mutex_unlock(gpsmanager->mutex);
 }
 
-static gboolean set_options(GcIfaceGeoclue * gc, GHashTable * options, GError ** error)
+static void stop_tracking(GeoclueGpsManager * gpsmanager)
 {
-       g_print("Options received---\n");
-       g_hash_table_foreach(options, print_option, NULL);
-       return TRUE;
+       LOG_GPS(DBG_LOW, "stop_tracking");
+       g_mutex_lock(gpsmanager->mutex);
+       if (request_stop_session() == TRUE) {
+               gpsmanager->is_running = FALSE;
+       }
+       g_mutex_unlock(gpsmanager->mutex);
+       gpsmanager->status = GEOCLUE_STATUS_UNAVAILABLE;
 }
 
-static void shutdown(GcProvider * provider)
+static gboolean set_options(GcIfaceGeoclue * gc, GHashTable * options, GError ** error)
 {
-       /* No shutdown!! */
+       LOG_GPS(DBG_LOW, "set_options");
+
+       GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
+       gchar *value = NULL;
+
+       value = g_hash_table_lookup(options, "CMD");
+
+       if (value) {
+               if (!g_strcmp0(value, "START")) {
+                       g_mutex_lock(gpsmanager->mutex);
+                       gpsmanager->client_count++;
+                       g_mutex_unlock(gpsmanager->mutex);
+
+                       if (gpsmanager->is_running == TRUE) {
+                               LOG_GPS(DBG_LOW, "gps-manager is already running");
+                               return TRUE;
+                       }
+                       start_tracking(gpsmanager);
+               } else if (!g_strcmp0(value, "STOP")) {
+                       g_mutex_lock(gpsmanager->mutex);
+                       gpsmanager->client_count--;
+                       g_mutex_unlock(gpsmanager->mutex);
+
+                       if (gpsmanager->is_running == FALSE) {
+                               return TRUE;
+                       }
+                       if (gpsmanager->client_count <= 0 ) {
+                               stop_tracking(gpsmanager);
+                       }
+                }
+       }
+       return TRUE;
 }
 
-static void start_tracking(GeoclueGpsManager * gpsmanager)
+static gboolean remove_all_clients(GeoclueGpsManager * gpsmanager)
 {
-       gpsmanager->status = GEOCLUE_STATUS_ACQUIRING;
-       request_start_session();
+       if (gpsmanager->client_count <= 0) {
+               return FALSE;
+       }
+
+       gpsmanager->client_count = 0;
+       stop_tracking(gpsmanager);
+
+       return TRUE;
 }
 
-static void stop_tracking(GeoclueGpsManager * gpsmanager)
+static void shutdown(GcProvider * provider)
 {
-       request_stop_session();
-       gpsmanager->status = GEOCLUE_STATUS_UNAVAILABLE;
+       GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(provider));
+
+       if (gpsmanager->is_running) {
+               if (remove_all_clients(gpsmanager)) {
+                       LOG_GPS(DBG_ERR, "<<<< Abnormal shutdown >>>>");
+               }
+       }
 }
 
 static void update_position_cb(pos_data_t * pos, gps_error_t error, void *user_data)
@@ -171,18 +220,16 @@ static void update_position_cb(pos_data_t * pos, gps_error_t error, void *user_d
 
        gpsmanager->status = GEOCLUE_STATUS_AVAILABLE;
 
-       fields = (GEOCLUE_POSITION_FIELDS_LATITUDE | GEOCLUE_POSITION_FIELDS_LONGITUDE | GEOCLUE_POSITION_FIELDS_ALTITUDE);
-
        accuracy = geoclue_accuracy_new(GEOCLUE_ACCURACY_LEVEL_DETAILED, pos->hor_accuracy, pos->ver_accuracy);
 
-       gc_iface_position_emit_position_changed(GC_IFACE_POSITION(gpsmanager),
-                                               fields, pos->timestamp, pos->latitude, pos->longitude, pos->altitude, accuracy);
-
        fields = (GEOCLUE_VELOCITY_FIELDS_SPEED | GEOCLUE_VELOCITY_FIELDS_DIRECTION);
-
        gc_iface_velocity_emit_velocity_changed(GC_IFACE_VELOCITY(gpsmanager),
                                                fields, pos->timestamp, pos->speed, pos->bearing, 0.0);
 
+       fields = (GEOCLUE_POSITION_FIELDS_LATITUDE | GEOCLUE_POSITION_FIELDS_LONGITUDE | GEOCLUE_POSITION_FIELDS_ALTITUDE);
+       gc_iface_position_emit_position_changed(GC_IFACE_POSITION(gpsmanager),
+                                               fields, pos->timestamp, pos->latitude, pos->longitude, pos->altitude, accuracy);
+
        geoclue_accuracy_free(accuracy);
 
        gc_iface_geoclue_emit_status_changed(GC_IFACE_GEOCLUE(gpsmanager), GEOCLUE_STATUS_AVAILABLE);
@@ -238,100 +285,19 @@ static void update_nmea_cb(nmea_data_t * nmea, void *user_data)
        g_memmove(gpsmanager->nmea.data, nmea->data, nmea->len);
        gpsmanager->nmea.data[nmea->len] = '\0';
 
+       timestamp = gpsmanager->position.timestamp;
+
        gc_iface_nmea_emit_nmea_changed(GC_IFACE_NMEA(gpsmanager), timestamp, gpsmanager->nmea.data);
 
        g_free(gpsmanager->nmea.data);
 }
 
-static void add_reference(GcIfaceGeoclue * gc, DBusGMethodInvocation * context)
-{
-       GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
-       char *sender;
-       int *pcount;
-
-       sender = dbus_g_method_get_sender(context);
-       if (g_hash_table_size(gpsmanager->connections) == 0) {
-               start_tracking(gpsmanager);
-       }
-       pcount = g_hash_table_lookup(gpsmanager->connections, sender);
-       if (!pcount) {
-               pcount = g_malloc0(sizeof(int));
-               g_hash_table_insert(gpsmanager->connections, sender, pcount);
-       }
-       (*pcount)++;
-
-       g_debug("add_reference (%s) (%d)", sender, (*pcount));
-
-       dbus_g_method_return(context);
-}
-
-static gboolean remove_client(GeoclueGpsManager * gpsmanager, const char *client)
-{
-       int *pcount;
-
-       pcount = g_hash_table_lookup(gpsmanager->connections, client);
-       if (!pcount) {
-               return FALSE;
-       }
-       (*pcount)--;
-       if (*pcount == 0) {
-               g_hash_table_remove(gpsmanager->connections, client);
-       }
-       if (g_hash_table_size(gpsmanager->connections) == 0) {
-               g_debug("There is no connections!");
-               stop_tracking(gpsmanager);
-       }
-       return TRUE;
-}
-
-static gboolean remove_all_clients(GeoclueGpsManager * gpsmanager, const char *client)
-{
-       int *pcount;
-
-       pcount = g_hash_table_lookup(gpsmanager->connections, client);
-       if (!pcount) {
-               return FALSE;
-       }
-       g_hash_table_remove(gpsmanager->connections, client);
-       if (g_hash_table_size(gpsmanager->connections) == 0) {
-               g_debug("There is no connections!");
-               stop_tracking(gpsmanager);
-       }
-       return TRUE;
-}
-
-static void remove_reference(GcIfaceGeoclue * gc, DBusGMethodInvocation * context)
-{
-       GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
-       char *sender;
-
-       sender = dbus_g_method_get_sender(context);
-       if (!remove_client(gpsmanager, sender)) {
-               g_warning("Unreffed by client taht has not been referenced");
-       }
-
-       g_free(sender);
-
-       dbus_g_method_return(context);
-}
-
-static void name_owner_changed(DBusGProxy * proxy, const char *name, const char *prev_owner, const char *new_owner, void *gc)
-{
-       GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
-       g_debug("name_owner_changed, name:%s, prev_owner:%s, new_owner:%s", name, prev_owner, new_owner);
-       if (strcmp(new_owner, "") == 0 && strcmp(name, prev_owner) == 0) {
-               if (remove_all_clients(gpsmanager, prev_owner)) {
-                       g_warning("Impolite client %s disconnected without unreferencing\n", prev_owner);
-               }
-       }
-}
-
 static void geoclue_gpsmanager_class_init(GeoclueGpsManagerClass * klass)
 {
        GObjectClass *o_class = (GObjectClass *) klass;
        GcProviderClass *p_class = (GcProviderClass *) klass;
 
-       o_class->constructed = constructed;
+       o_class->constructor = constructor;
        o_class->finalize = finalize;
        o_class->dispose = dispose;
        p_class->get_status = get_status;
@@ -341,34 +307,22 @@ static void geoclue_gpsmanager_class_init(GeoclueGpsManagerClass * klass)
 
 static void geoclue_gpsmanager_init(GeoclueGpsManager * gpsmanager)
 {
-       GError *error = NULL;
-       DBusGProxy *driver;
-       guint request_ret;
-       GcProvider *provider;
-       g_debug("geoclue_gpsmanager_init");
-
-       g_return_if_fail(GC_IS_PROVIDER(gpsmanager));
-       provider = GC_PROVIDER(gpsmanager);
-       g_return_if_fail(provider->connection != NULL);
-
-       driver = dbus_g_proxy_new_for_name(provider->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
-
-       if (!org_freedesktop_DBus_request_name(driver, GEOCLUE_GPSMANAGER_DBUS_SERVICE, 0, &request_ret, &error)) {
-               g_warning("%s was unable to register service %s: %s",
-                         G_OBJECT_TYPE_NAME(provider), GEOCLUE_GPSMANAGER_DBUS_SERVICE, error->message);
-               g_error_free(error);
-               return;
-       }
+       LOG_GPS(DBG_LOW, "geoclue_gpsmanager_init");
 
-       dbus_g_proxy_add_signal(driver, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
-
-       dbus_g_proxy_connect_signal(driver, "NameOwnerChanged", G_CALLBACK(name_owner_changed), provider, NULL);
-
-       dbus_g_connection_register_g_object(provider->connection, GEOCLUE_GPSMANAGER_DBUS_PATH, G_OBJECT(provider));
+       gpsmanager->status = GEOCLUE_STATUS_UNAVAILABLE;
+       gpsmanager->mutex = g_mutex_new();
 
+       memset(&gpsmanager->position, 0x00, sizeof(pos_data_t));
+       memset(&gpsmanager->satellite, 0x00, sizeof(sv_data_t));
+       memset(&gpsmanager->nmea, 0x00, sizeof(nmea_data_t));
        memset(&gpsmanager->last_position, 0x00, sizeof(pos_data_t));
        memset(&gpsmanager->last_satellite, 0x00, sizeof(sv_data_t));
 
+       gpsmanager->is_running = FALSE;
+       gpsmanager->client_count = 0;
+
+       gc_provider_set_details(GC_PROVIDER(gpsmanager), GEOCLUE_GPSMANAGER_DBUS_SERVICE, GEOCLUE_GPSMANAGER_DBUS_PATH, "gps-manager", "GPS Manager");
+
        gps_manager_get_last_position(&gpsmanager->last_position);
 }
 
@@ -697,8 +651,6 @@ static void init_satellite(GcIfaceSatelliteClass * iface)
 static void init_geoclue(GcIfaceGeoclueClass * iface)
 {
        iface->get_provider_info = get_provider_info;
-       iface->add_reference = add_reference;
-       iface->remove_reference = remove_reference;
 }
 
 int main(int argc, char **argv)
@@ -709,9 +661,12 @@ int main(int argc, char **argv)
        cb.sv_cb = update_satellite_cb;
        cb.nmea_cb = update_nmea_cb;
 
+#if !GLIB_CHECK_VERSION (2, 31, 0)
        if (!g_thread_supported()) {
                g_thread_init(NULL);
        }
+#endif
+
        dbus_g_thread_init();
        g_type_init();