--- /dev/null
+/*
+ * libslp-location
+ *
+ * Copyright (c) 2016-2017 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+#include <vconf-internal-location-keys.h>
+#include "module-internal.h"
+
+#include "location-fused.h"
+#include "location-setting.h"
+#include "location-marshal.h"
+#include "location-ielement.h"
+#include "location-signaling-util.h"
+#include "location-common-util.h"
+
+#include "location-log.h"
+
+
+static void location_ielement_interface_init(LocationIElementInterface *iface);
+
+typedef struct _LocationFusedPrivate {
+ LocationFusedMod *mod;
+ GMutex mutex;
+ gboolean is_started;
+ guint app_type;
+ gboolean set_noti;
+ gboolean enabled;
+ guint pos_updated_timestamp;
+ guint vel_updated_timestamp;
+ guint loc_updated_timestamp;
+ guint dist_updated_timestamp;
+ guint pos_interval;
+ guint vel_interval;
+ guint loc_interval;
+ guint optimized_interval;
+ guint min_interval;
+ gdouble min_distance;
+ LocationPosition *pos;
+ LocationVelocity *vel;
+ LocationAccuracy *acc;
+ GList *boundary_list;
+ LocationFusedMode fused_mode;
+} LocationFusedPrivate;
+
+enum {
+ PROP_0,
+ PROP_METHOD_TYPE,
+ PROP_IS_STARTED,
+ PROP_LAST_POSITION,
+ PROP_BOUNDARY,
+ PROP_REMOVAL_BOUNDARY,
+ PROP_POS_INTERVAL,
+ PROP_VEL_INTERVAL,
+ PROP_LOC_INTERVAL,
+ PROP_MIN_INTERVAL,
+ PROP_MIN_DISTANCE,
+ PROP_SERVICE_STATUS,
+ PROP_MAX
+};
+
+static guint32 signals[LAST_SIGNAL] = {0, };
+static GParamSpec *properties[PROP_MAX] = {NULL, };
+
+#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), LOCATION_TYPE_FUSED, LocationFusedPrivate))
+
+static void location_ielement_interface_init(LocationIElementInterface *iface);
+G_DEFINE_TYPE_WITH_CODE(LocationFused, location_fused, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(LOCATION_TYPE_IELEMENT, location_ielement_interface_init));
+
+static void fused_position_cb(gboolean enabled, LocationPosition *pos, LocationVelocity *vel, LocationAccuracy *acc, gpointer self);
+static void fused_status_cb(gboolean enabled, LocationStatus status, gpointer self);
+
+
+static void __reset_pos_data_from_priv(LocationFusedPrivate *priv)
+{
+ LOC_FUNC_LOG
+ g_return_if_fail(priv);
+
+ if (priv->pos) {
+ location_position_free(priv->pos);
+ priv->pos = NULL;
+ }
+
+ if (priv->vel) {
+ location_velocity_free(priv->vel);
+ priv->vel = NULL;
+ }
+
+ if (priv->acc) {
+ location_accuracy_free(priv->acc);
+ priv->acc = NULL;
+ }
+
+ priv->pos_updated_timestamp = 0;
+ priv->vel_updated_timestamp = 0;
+ priv->loc_updated_timestamp = 0;
+}
+
+static gboolean __get_started(gpointer self)
+{
+ LOC_FUNC_LOG
+ g_return_val_if_fail(self, FALSE);
+
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(priv, FALSE);
+
+ return priv->is_started;
+}
+
+static int __set_started(gpointer self, gboolean started)
+{
+ LOC_FUNC_LOG
+ g_return_val_if_fail(self, -1);
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(priv, -1);
+
+ if (priv->is_started != started) {
+ g_mutex_lock(&priv->mutex);
+ priv->is_started = started;
+ g_mutex_unlock(&priv->mutex);
+ }
+
+ return 0;
+}
+
+static void fused_status_cb(gboolean enabled, LocationStatus status, gpointer self)
+{
+ LOC_FUNC_LOG
+ g_return_if_fail(self);
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(priv);
+
+ enable_signaling((gpointer)self, signals, &(priv->enabled), status != LOCATION_STATUS_NO_FIX, status);
+}
+
+static void fused_position_cb(gboolean enabled, LocationPosition *pos, LocationVelocity *vel, LocationAccuracy *acc, gpointer self)
+{
+ LOC_FUNC_LOG
+ g_return_if_fail(self);
+ g_return_if_fail(pos);
+ g_return_if_fail(vel);
+ g_return_if_fail(acc);
+
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(priv);
+
+ if (priv->min_interval != LOCATION_UPDATE_INTERVAL_NONE) {
+ distance_based_position_signaling(self, signals, enabled, pos, vel, acc,
+ priv->min_interval, priv->min_distance, &(priv->enabled),
+ &(priv->dist_updated_timestamp), &(priv->pos), &(priv->vel), &(priv->acc));
+ }
+ location_signaling(self, signals, enabled, priv->boundary_list, pos, vel, acc,
+ priv->pos_interval, priv->vel_interval, priv->loc_interval, &(priv->enabled),
+ &(priv->pos_updated_timestamp), &(priv->vel_updated_timestamp),
+ &(priv->loc_updated_timestamp), &(priv->pos), &(priv->vel), &(priv->acc));
+}
+
+static void location_setting_changed_cb(keynode_t *key, gpointer self)
+{
+ LOC_FUNC_LOG
+ g_return_if_fail(self);
+ g_return_if_fail(key);
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(priv);
+ g_return_if_fail(priv->mod);
+ g_return_if_fail(priv->mod->handler);
+
+ int ret = LOCATION_ERROR_NONE;
+
+ if (0 == location_setting_get_key_val(key) && priv->mod->ops.stop && __get_started(self)) {
+ LOCATION_LOGD("location stopped by setting");
+ __set_started(self, FALSE);
+ ret = priv->mod->ops.stop(priv->mod->handler);
+ if (ret == LOCATION_ERROR_NONE)
+ __reset_pos_data_from_priv(priv);
+ else
+ LOCATION_LOGI("Fail to stop[%d]", ret);
+
+ } else if (1 == location_setting_get_key_val(key) && !__get_started(self)) {
+ LOCATION_LOGD("location resumed by setting");
+ __set_started(self, TRUE);
+
+ if (priv->fused_mode == LOCATION_FUSED_HIGH && priv->mod->ops.start_gps)
+ ret = priv->mod->ops.start_gps(priv->mod->handler, priv->optimized_interval, fused_status_cb, fused_position_cb, NULL, self);
+ else if (priv->fused_mode == LOCATION_FUSED_BALANCED && priv->mod->ops.start_wps)
+ ret = priv->mod->ops.start_wps(priv->mod->handler, priv->optimized_interval, fused_status_cb, fused_position_cb, NULL, self);
+
+ if (ret != LOCATION_ERROR_NONE) {
+ __set_started(self, FALSE);
+ LOCATION_LOGI("Fail to start[%d]", ret);
+ }
+ }
+}
+
+int location_fused_start(LocationFused *self)
+{
+ LOC_FUNC_LOG
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(priv, LOCATION_ERROR_NOT_AVAILABLE);
+ g_return_val_if_fail(priv->mod, LOCATION_ERROR_NOT_AVAILABLE);
+ g_return_val_if_fail(priv->mod->handler, LOCATION_ERROR_NOT_AVAILABLE);
+ g_return_val_if_fail(priv->mod->ops.start_gps, LOCATION_ERROR_NOT_AVAILABLE);
+ g_return_val_if_fail(priv->mod->ops.start_wps, LOCATION_ERROR_NOT_AVAILABLE);
+
+ LOC_COND_RET(__get_started(self) == TRUE, LOCATION_ERROR_NONE, _E, "Fused already started. Error[%s]", err_msg(LOCATION_ERROR_NONE));
+
+ int ret = LOCATION_ERROR_NONE;
+
+ if (priv->fused_mode == LOCATION_FUSED_HIGH) {
+ if (location_setting_get_int(VCONFKEY_LOCATION_ENABLED)) {
+ __set_started(self, TRUE);
+ ret = priv->mod->ops.start_gps(priv->mod->handler, priv->optimized_interval, fused_status_cb, fused_position_cb, NULL, self);
+
+ if (ret != LOCATION_ERROR_NONE) {
+ LOCATION_LOGE("Fail to start fused high. Error[%d]", ret);
+ __set_started(self, FALSE);
+ return ret;
+ }
+ } else {
+ LOCATION_LOGE("GPS Setting off");
+ ret = LOCATION_ERROR_SETTING_OFF;
+ }
+
+ } else if (priv->fused_mode == LOCATION_FUSED_BALANCED) {
+ if (location_setting_get_int(VCONFKEY_LOCATION_NETWORK_ENABLED)) {
+ __set_started(self, TRUE);
+ ret = priv->mod->ops.start_wps(priv->mod->handler, priv->optimized_interval, fused_status_cb, fused_position_cb, NULL, self);
+
+ if (ret != LOCATION_ERROR_NONE) {
+ LOCATION_LOGE("Fail to start fused balanced. Error[%d]", ret);
+ __set_started(self, FALSE);
+ return ret;
+ }
+ } else {
+ LOCATION_LOGE("WPS Setting off");
+ ret = LOCATION_ERROR_SETTING_OFF;
+ }
+ }
+
+ if (priv->app_type != CPPAPP && priv->set_noti == FALSE) {
+ if (priv->fused_mode == LOCATION_FUSED_HIGH)
+ location_setting_add_notify(VCONFKEY_LOCATION_ENABLED, location_setting_changed_cb, self);
+ else if (priv->fused_mode == LOCATION_FUSED_BALANCED)
+ location_setting_add_notify(VCONFKEY_LOCATION_NETWORK_ENABLED, location_setting_changed_cb, self);
+
+ priv->set_noti = TRUE;
+ }
+
+ LOCATION_LOGD("EXIT <<<");
+ return ret;
+}
+
+int location_fused_stop(LocationFused *self)
+{
+ LOC_FUNC_LOG
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(priv, LOCATION_ERROR_NOT_AVAILABLE);
+ g_return_val_if_fail(priv->mod, LOCATION_ERROR_NOT_AVAILABLE);
+ g_return_val_if_fail(priv->mod->handler, LOCATION_ERROR_NOT_AVAILABLE);
+ g_return_val_if_fail(priv->mod->ops.stop, LOCATION_ERROR_NOT_AVAILABLE);
+
+ int ret = LOCATION_ERROR_NONE;
+
+ if (__get_started(self) == TRUE) {
+ __set_started(self, FALSE);
+ ret = priv->mod->ops.stop(priv->mod->handler);
+ LOC_IF_FAIL_LOG(ret, _E, "Failed to stop [%s]", err_msg(ret));
+
+ g_signal_emit(self, signals[SERVICE_DISABLED], 0, LOCATION_STATUS_NO_FIX);
+ } else {
+ return LOCATION_ERROR_NONE;
+ }
+
+ if (priv->app_type != CPPAPP && priv->set_noti == TRUE) {
+ if (priv->fused_mode == LOCATION_FUSED_HIGH)
+ location_setting_ignore_notify(VCONFKEY_LOCATION_ENABLED, location_setting_changed_cb);
+ else if (priv->fused_mode == LOCATION_FUSED_BALANCED)
+ location_setting_ignore_notify(VCONFKEY_LOCATION_NETWORK_ENABLED, location_setting_changed_cb);
+
+ priv->set_noti = FALSE;
+ }
+
+ __reset_pos_data_from_priv(priv);
+
+ return ret;
+}
+
+void location_fused_dispose(GObject *gobject)
+{
+ LOC_FUNC_LOG
+ LocationFusedPrivate *priv = GET_PRIVATE(gobject);
+ g_return_if_fail(priv);
+ g_return_if_fail(priv->mod);
+ g_mutex_clear(&priv->mutex);
+
+ if (priv->app_type != CPPAPP && priv->set_noti == TRUE) {
+ if (priv->fused_mode == LOCATION_FUSED_HIGH)
+ location_setting_ignore_notify(VCONFKEY_LOCATION_ENABLED, location_setting_changed_cb);
+ else if (priv->fused_mode == LOCATION_FUSED_BALANCED)
+ location_setting_ignore_notify(VCONFKEY_LOCATION_NETWORK_ENABLED, location_setting_changed_cb);
+
+ priv->set_noti = FALSE;
+ }
+
+ G_OBJECT_CLASS(location_fused_parent_class)->dispose(gobject);
+}
+
+void location_fused_finalize(GObject *gobject)
+{
+ LOC_FUNC_LOG
+ LocationFusedPrivate *priv = GET_PRIVATE(gobject);
+ g_return_if_fail(priv);
+
+ module_free(priv->mod, "fused");
+ priv->mod = NULL;
+
+ if (priv->boundary_list) {
+ g_list_free_full(priv->boundary_list, free_boundary_list);
+ priv->boundary_list = NULL;
+ }
+
+ if (priv->pos) {
+ location_position_free(priv->pos);
+ priv->pos = NULL;
+ }
+
+ if (priv->vel) {
+ location_velocity_free(priv->vel);
+ priv->vel = NULL;
+ }
+
+ if (priv->acc) {
+ location_accuracy_free(priv->acc);
+ priv->acc = NULL;
+ }
+ G_OBJECT_CLASS(location_fused_parent_class)->finalize(gobject);
+}
+
+static guint get_valid_interval(guint interval, int max_interval, int min_interval)
+{
+ if (interval > max_interval)
+ return (guint)max_interval;
+ else if (interval < min_interval)
+ return (guint)min_interval;
+ else
+ return interval;
+}
+
+void location_fused_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ LOC_FUNC_LOG
+ LocationFusedPrivate *priv = GET_PRIVATE(object);
+ g_return_if_fail(priv);
+ g_return_if_fail(priv->mod);
+ g_return_if_fail(priv->mod->handler);
+
+ int ret = LOCATION_ERROR_NONE;
+
+ switch (property_id) {
+ case PROP_BOUNDARY: {
+ GList *source_list = (GList *)(g_value_get_pointer(value));
+ if (source_list) {
+ GList *boundary_list = (GList *)g_list_copy(source_list);
+ ret = set_prop_boundary(&priv->boundary_list, boundary_list);
+ LOC_IF_FAIL_LOG(ret, _E, "Set boundary. Error[%s]", err_msg(ret));
+ if (boundary_list) g_list_free(boundary_list);
+ }
+ break;
+ }
+ case PROP_REMOVAL_BOUNDARY: {
+ LocationBoundary *req_boundary = (LocationBoundary *) g_value_dup_boxed(value);
+ ret = set_prop_removal_boundary(&priv->boundary_list, req_boundary);
+ LOC_IF_FAIL_LOG(ret, _E, "Removal boundary. Error[%s]", err_msg(ret));
+ break;
+ }
+ case PROP_POS_INTERVAL: {
+ guint interval = g_value_get_uint(value);
+ LOCATION_LOGD("Set prop>> PROP_POS_INTERVAL: %u", interval);
+ if (interval == priv->pos_interval) break;
+
+ priv->pos_interval = get_valid_interval(interval, LOCATION_UPDATE_INTERVAL_MAX, LOCATION_UPDATE_INTERVAL_MIN);
+ priv->optimized_interval = priv->pos_interval;
+
+ if (__get_started(object) == TRUE) {
+ LOCATION_LOGD("[update_pos_interval]: update pos-interval while pos-tracking");
+ g_return_if_fail(priv->mod->ops.set_position_update_interval);
+ priv->mod->ops.set_position_update_interval(priv->mod->handler, priv->pos_interval);
+ }
+ break;
+ }
+ case PROP_VEL_INTERVAL: {
+ guint interval = g_value_get_uint(value);
+ LOCATION_LOGD("Set prop>> PROP_VEL_INTERVAL: %u", interval);
+ if (interval == priv->vel_interval) break;
+ priv->vel_interval = get_valid_interval(interval, LOCATION_UPDATE_INTERVAL_MAX, LOCATION_UPDATE_INTERVAL_MIN);
+ break;
+ }
+ case PROP_LOC_INTERVAL: {
+ guint interval = g_value_get_uint(value);
+ LOCATION_LOGD("Set prop>> PROP_LOC_INTERVAL: %u", interval);
+ if (interval == priv->loc_interval) break;
+
+ priv->loc_interval = get_valid_interval(interval, LOCATION_UPDATE_INTERVAL_MAX, LOCATION_UPDATE_INTERVAL_MIN);
+ priv->optimized_interval = priv->loc_interval;
+
+ if (__get_started(object) == TRUE) {
+ LOCATION_LOGD("[update_pos_interval]: update loc-interval while loc-tracking");
+ g_return_if_fail(priv->mod->ops.set_position_update_interval);
+ priv->mod->ops.set_position_update_interval(priv->mod->handler, priv->loc_interval);
+ }
+
+ break;
+ }
+ case PROP_MIN_INTERVAL: {
+ guint interval = g_value_get_uint(value);
+ LOCATION_LOGD("Set prop>> PROP_MIN_INTERVAL: %u", interval);
+ priv->min_interval = interval;
+ break;
+ }
+ case PROP_MIN_DISTANCE: {
+ gdouble distance = g_value_get_double(value);
+ LOCATION_LOGD("Set prop>> PROP_MIN_DISTANCE: %f", distance);
+ priv->min_distance = distance;
+ break;
+ }
+ case PROP_SERVICE_STATUS: {
+ gint enabled = g_value_get_int(value);
+ LOCATION_LOGD("Set prop>> PROP_SERVICE_STATUS: %u", enabled);
+ priv->enabled = enabled;
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+void location_fused_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ LOC_FUNC_LOG
+ LocationFusedPrivate *priv = GET_PRIVATE(object);
+ g_return_if_fail(priv);
+
+ switch (property_id) {
+ case PROP_METHOD_TYPE:
+ g_value_set_int(value, LOCATION_METHOD_FUSED);
+ break;
+ case PROP_IS_STARTED:
+ g_value_set_boolean(value, __get_started(object));
+ break;
+ case PROP_BOUNDARY:
+ g_value_set_pointer(value, g_list_first(priv->boundary_list));
+ break;
+ case PROP_POS_INTERVAL:
+ g_value_set_uint(value, priv->pos_interval);
+ break;
+ case PROP_VEL_INTERVAL:
+ g_value_set_uint(value, priv->vel_interval);
+ break;
+ case PROP_LOC_INTERVAL:
+ g_value_set_uint(value, priv->loc_interval);
+ break;
+ case PROP_MIN_INTERVAL:
+ g_value_set_uint(value, priv->min_interval);
+ break;
+ case PROP_MIN_DISTANCE:
+ g_value_set_double(value, priv->min_distance);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+
+}
+
+static int location_fused_get_position_ext(LocationFused *self, LocationPosition **position, LocationVelocity **velocity, LocationAccuracy **accuracy)
+{
+ LOC_FUNC_LOG
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(priv, LOCATION_ERROR_NOT_AVAILABLE);
+ setting_retval_if_fail(VCONFKEY_LOCATION_ENABLED);
+
+ LOC_COND_RET(__get_started(self) != TRUE, LOCATION_ERROR_NOT_AVAILABLE, _E, "Fused not started. Error[%s]", err_msg(LOCATION_ERROR_NOT_AVAILABLE));
+ int ret = LOCATION_ERROR_NONE;
+
+ if (position && priv->pos)
+ *position = location_position_copy(priv->pos);
+
+ if (velocity && priv->vel)
+ *velocity = location_velocity_copy(priv->vel);
+
+ if (accuracy) {
+ if (priv->acc)
+ *accuracy = location_accuracy_copy(priv->acc);
+ else
+ *accuracy = location_accuracy_new(LOCATION_ACCURACY_LEVEL_NONE, 0.0, 0.0);
+ }
+
+ if (position && (priv->pos == NULL))
+ ret = LOCATION_ERROR_NOT_AVAILABLE;
+
+ if (velocity && (priv->vel == NULL))
+ ret = LOCATION_ERROR_NOT_AVAILABLE;
+
+ return ret;
+}
+
+static int location_fused_get_position(LocationFused *self, LocationPosition **position, LocationAccuracy **accuracy)
+{
+ LOC_FUNC_LOG
+ return location_fused_get_position_ext(self, position, NULL, accuracy);
+}
+
+static int location_fused_get_velocity(LocationFused *self, LocationVelocity **velocity, LocationAccuracy **accuracy)
+{
+ LOC_FUNC_LOG
+ return location_fused_get_position_ext(self, NULL, velocity, accuracy);
+}
+
+static int location_fused_get_last_position_ext(LocationFused *self, LocationPosition **position, LocationVelocity **velocity, LocationAccuracy **accuracy)
+{
+ LOC_FUNC_LOG
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(priv, LOCATION_ERROR_NOT_AVAILABLE);
+ g_return_val_if_fail(priv->mod, LOCATION_ERROR_NOT_AVAILABLE);
+ g_return_val_if_fail(priv->mod->handler, LOCATION_ERROR_NOT_AVAILABLE);
+ setting_retval_if_fail(VCONFKEY_LOCATION_ENABLED);
+
+ if (__get_started(self) == TRUE) {
+ return location_fused_get_position_ext(self, position, velocity, accuracy);
+ } else {
+
+ int ret = LOCATION_ERROR_NONE;
+
+ LocModFusedOps ops = priv->mod->ops;
+ g_return_val_if_fail(ops.get_last_position, LOCATION_ERROR_NOT_AVAILABLE);
+ ret = ops.get_last_position(priv->mod->handler, position, velocity, accuracy);
+ return ret;
+ }
+}
+
+static int location_fused_get_last_position(LocationFused *self, LocationPosition **position, LocationAccuracy **accuracy)
+{
+ LOC_FUNC_LOG
+ return location_fused_get_last_position_ext(self, position, NULL, accuracy);
+}
+
+static int location_fused_get_last_velocity(LocationFused *self, LocationVelocity **velocity, LocationAccuracy **accuracy)
+{
+ LOC_FUNC_LOG
+ return location_fused_get_last_position_ext(self, NULL, velocity, accuracy);
+}
+
+static int location_fused_get_satellite(LocationFused *self, LocationSatellite **satellite)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int location_fused_get_last_satellite(LocationFused *self, LocationSatellite **satellite)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int location_fused_get_batch(LocationFused *self, LocationBatch **batch)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int location_fused_start_batch(LocationFused *self)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int location_fused_stop_batch(LocationFused *self)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int location_fused_request_single_location(LocationFused *self, int timeout)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int location_fused_cancel_single_location(LocationFused *self)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int location_fused_get_nmea(LocationFused *self, char **nmea_data)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int
+location_fused_set_mock_location(LocationFused *self, LocationPosition *position, LocationVelocity *velocity, LocationAccuracy *accuracy)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int location_fused_clear_mock_location(LocationFused *self)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int location_fused_set_option(LocationFused *self, const char *option)
+{
+ LOC_FUNC_LOG
+ return LOCATION_ERROR_NOT_SUPPORTED;
+}
+
+static int location_fused_set_fused_mode(LocationFused *self, LocationFusedMode mode)
+{
+ LOC_FUNC_LOG
+ g_return_val_if_fail(self, LOCATION_ERROR_PARAMETER);
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(priv, LOCATION_ERROR_NOT_AVAILABLE);
+
+ if (priv->fused_mode != mode) {
+ priv->fused_mode = mode;
+ }
+ return LOCATION_ERROR_NONE;
+}
+
+static void location_ielement_interface_init(LocationIElementInterface *iface)
+{
+ LOC_FUNC_LOG
+ g_return_if_fail(iface);
+ iface->start = (TYPE_START_FUNC) location_fused_start;
+ iface->stop = (TYPE_STOP_FUNC) location_fused_stop;
+ iface->get_position = (TYPE_GET_POSITION) location_fused_get_position;
+ iface->get_position_ext = (TYPE_GET_POSITION_EXT) location_fused_get_position_ext;
+ iface->get_last_position = (TYPE_GET_POSITION) location_fused_get_last_position;
+ iface->get_last_position_ext = (TYPE_GET_POSITION_EXT) location_fused_get_last_position_ext;
+ iface->get_velocity = (TYPE_GET_VELOCITY) location_fused_get_velocity;
+ iface->get_last_velocity = (TYPE_GET_VELOCITY) location_fused_get_last_velocity;
+ iface->set_option = (TYPE_SET_OPTION) location_fused_set_option;
+ iface->set_fused_mode = (TYPE_SET_FUSED_MODE) location_fused_set_fused_mode;
+ iface->get_satellite = (TYPE_GET_SATELLITE) location_fused_get_satellite;
+ iface->get_last_satellite = (TYPE_GET_SATELLITE) location_fused_get_last_satellite;
+ iface->get_batch = (TYPE_GET_BATCH) location_fused_get_batch;
+ iface->start_batch = (TYPE_START_BATCH) location_fused_start_batch;
+ iface->stop_batch = (TYPE_STOP_BATCH) location_fused_stop_batch;
+ iface->request_single_location = (TYPE_REQUEST_SINGLE_LOCATION) location_fused_request_single_location;
+ iface->cancel_single_location = (TYPE_CANCEL_SINGLE_LOCATION) location_fused_cancel_single_location;
+ iface->get_nmea = (TYPE_GET_NMEA) location_fused_get_nmea;
+ iface->set_mock_location = (TYPE_SET_MOCK_LOCATION) location_fused_set_mock_location;
+ iface->clear_mock_location = (TYPE_CLEAR_MOCK_LOCATION) location_fused_clear_mock_location;
+}
+
+static void location_fused_init(LocationFused *self)
+{
+ LOC_FUNC_LOG
+ g_return_if_fail(self);
+ LocationFusedPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(priv);
+
+ priv->mod = (LocationFusedMod *)module_new("fused");
+ LOC_COND_LOG(!priv->mod, _E, "Module loading failed");
+
+ __set_started(self, FALSE);
+ priv->set_noti = FALSE;
+ priv->enabled = FALSE;
+
+ priv->pos_interval = LOCATION_UPDATE_INTERVAL_DEFAULT;
+ priv->vel_interval = LOCATION_UPDATE_INTERVAL_DEFAULT;
+ priv->loc_interval = LOCATION_UPDATE_INTERVAL_DEFAULT;
+ priv->optimized_interval = LOCATION_UPDATE_INTERVAL_DEFAULT;
+ priv->min_interval = LOCATION_UPDATE_INTERVAL_NONE;
+ priv->min_distance = LOCATION_MIN_DISTANCE_DEFAULT;
+
+ priv->pos_updated_timestamp = 0;
+ priv->vel_updated_timestamp = 0;
+ priv->loc_updated_timestamp = 0;
+
+ priv->boundary_list = NULL;
+ priv->fused_mode = LOCATION_FUSED_HIGH;
+ priv->app_type = location_get_app_type(NULL);
+ LOC_COND_LOG(priv->app_type == 0, _W, "Fail to get app_type");
+}
+
+static void location_fused_class_init(LocationFusedClass *klass)
+{
+ LOC_FUNC_LOG
+ g_return_if_fail(klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->set_property = location_fused_set_property;
+ gobject_class->get_property = location_fused_get_property;
+ gobject_class->dispose = location_fused_dispose;
+ gobject_class->finalize = location_fused_finalize;
+
+ g_type_class_add_private(klass, sizeof(LocationFusedPrivate));
+
+ signals[SERVICE_ENABLED] = g_signal_new("service-enabled", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, G_STRUCT_OFFSET(LocationFusedClass, enabled), NULL, NULL, location_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
+ signals[SERVICE_DISABLED] = g_signal_new("service-disabled", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, G_STRUCT_OFFSET(LocationFusedClass, disabled), NULL, NULL, location_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
+ signals[SERVICE_UPDATED] = g_signal_new("service-updated", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, G_STRUCT_OFFSET(LocationFusedClass, service_updated), NULL, NULL, location_VOID__INT_POINTER_POINTER_POINTER, G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
+ signals[LOCATION_UPDATED] = g_signal_new("location-updated", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, G_STRUCT_OFFSET(LocationFusedClass, location_updated), NULL, NULL, location_VOID__INT_POINTER_POINTER_POINTER, G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
+ signals[ZONE_IN] = g_signal_new("zone-in", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, G_STRUCT_OFFSET(LocationFusedClass, zone_in), NULL, NULL, location_VOID__POINTER_POINTER_POINTER, G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
+ signals[ZONE_OUT] = g_signal_new("zone-out", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, G_STRUCT_OFFSET(LocationFusedClass, zone_out), NULL, NULL, location_VOID__POINTER_POINTER_POINTER, G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
+
+ properties[PROP_METHOD_TYPE] = g_param_spec_int("method", "method type", "location method type name (fused)", LOCATION_METHOD_FUSED, LOCATION_METHOD_FUSED, LOCATION_METHOD_FUSED, G_PARAM_READABLE);
+ properties[PROP_IS_STARTED] = g_param_spec_boolean("is_started", "fused is started prop", "status of the fused location", FALSE, G_PARAM_READWRITE);
+ properties[PROP_LAST_POSITION] = g_param_spec_boxed("last-position", "fused last position prop", "last fused position", LOCATION_TYPE_POSITION, G_PARAM_READABLE);
+ properties[PROP_POS_INTERVAL] = g_param_spec_uint("pos-interval", "pos-int prop", "desired signaling interval of position", LOCATION_UPDATE_INTERVAL_MIN, LOCATION_UPDATE_INTERVAL_MAX, LOCATION_UPDATE_INTERVAL_DEFAULT, G_PARAM_READWRITE);
+ properties[PROP_VEL_INTERVAL] = g_param_spec_uint("vel-interval", "vel-int prop", "desired signaling interval of velocity", LOCATION_UPDATE_INTERVAL_MIN, LOCATION_UPDATE_INTERVAL_MAX, LOCATION_UPDATE_INTERVAL_DEFAULT, G_PARAM_READWRITE);
+ properties[PROP_LOC_INTERVAL] = g_param_spec_uint("loc-interval", "loc-int prop", "desired signaling interval of entire location", LOCATION_UPDATE_INTERVAL_MIN, LOCATION_UPDATE_INTERVAL_MAX, LOCATION_UPDATE_INTERVAL_DEFAULT, G_PARAM_READWRITE);
+ properties[PROP_MIN_INTERVAL] = g_param_spec_uint("min-interval", "min-int prop", "minimal signaling interval", LOCATION_MIN_INTERVAL_MIN, LOCATION_MIN_INTERVAL_MAX, LOCATION_MIN_INTERVAL_DEFAULT, G_PARAM_READWRITE);
+ properties[PROP_MIN_DISTANCE] = g_param_spec_double("min-distance", "min-dist prop", "minimal signaling distance", LOCATION_MIN_DISTANCE_MIN, LOCATION_MIN_DISTANCE_MAX, LOCATION_MIN_DISTANCE_DEFAULT, G_PARAM_READWRITE);
+ properties[PROP_BOUNDARY] = g_param_spec_pointer("boundary", "fused boundary prop", "fused boundary data", G_PARAM_READWRITE);
+ properties[PROP_REMOVAL_BOUNDARY] = g_param_spec_boxed("removal-boundary", "fused removal boundary prop", "fused removal boundary data", LOCATION_TYPE_BOUNDARY, G_PARAM_READWRITE);
+ properties[PROP_SERVICE_STATUS] = g_param_spec_int("service-status", "location service status prop", "location service status data", LOCATION_STATUS_NO_FIX, LOCATION_STATUS_3D_FIX, LOCATION_STATUS_NO_FIX, G_PARAM_READABLE);
+
+ g_object_class_install_properties(gobject_class, PROP_MAX, properties);
+}