Fix a crash after changes that velocity is updated before position
[framework/location/libslp-location.git] / location / manager / location-hybrid.c
1 /*
2  * libslp-location
3  *
4  * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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>
8  *
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
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
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.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "location-setting.h"
27 #include "location-log.h"
28
29 #include "module-internal.h"
30
31 #include "location-hybrid.h"
32 #include "location-marshal.h"
33 #include "location-ielement.h"
34 #include "location-signaling-util.h"
35 #include "location-common-util.h"
36
37 #include "location-gps.h"
38 #include "location-wps.h"
39 #include "location-cps.h"
40
41 typedef struct _LocationHybridPrivate {
42         gboolean is_started;
43         gboolean gps_enabled;
44         gboolean wps_enabled;
45         guint pos_updated_timestamp;
46         guint pos_interval;
47         guint vel_updated_timestamp;
48         guint vel_interval;
49         guint sat_updated_timestamp;
50         guint sat_interval;
51         LocationObject *gps;
52         LocationObject *wps;
53         gboolean enabled;
54         LocationMethod current_method;
55         LocationPosition *pos;
56         LocationVelocity *vel;
57         LocationAccuracy *acc;
58         LocationSatellite *sat;
59         GList* boundary_list;
60         ZoneStatus zone_status;
61
62         gboolean set_noti;
63         guint pos_timer;
64         guint vel_timer;
65
66 } LocationHybridPrivate;
67
68 enum {
69         PROP_0,
70         PROP_METHOD_TYPE,
71         PROP_LAST_POSITION,
72         PROP_POS_INTERVAL,
73         PROP_VEL_INTERVAL,
74         PROP_SAT_INTERVAL,
75         PROP_BOUNDARY,
76         PROP_REMOVAL_BOUNDARY,
77         PROP_MAX
78 };
79
80 static guint32 signals[LAST_SIGNAL] = {0, };
81 static GParamSpec *properties[PROP_MAX] = {NULL, };
82
83 #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOCATION_TYPE_HYBRID, LocationHybridPrivate))
84
85 static void location_ielement_interface_init (LocationIElementInterface *iface);
86
87 G_DEFINE_TYPE_WITH_CODE (LocationHybrid, location_hybrid, G_TYPE_OBJECT,
88                          G_IMPLEMENT_INTERFACE (LOCATION_TYPE_IELEMENT,
89                          location_ielement_interface_init));
90
91 static LocationMethod
92 hybrid_get_current_method(LocationHybridPrivate* priv)
93 {
94         g_return_val_if_fail (priv, LOCATION_METHOD_NONE);
95         LOCATION_LOGW("Current Method [%d]\n", priv->current_method);
96         return priv->current_method;
97 }
98
99 static gboolean
100 hybrid_set_current_method (LocationHybridPrivate* priv, GType g_type)
101 {
102         g_return_val_if_fail (priv, FALSE);
103
104         if (g_type == LOCATION_TYPE_GPS) {
105                 priv->current_method = LOCATION_METHOD_GPS;
106                 LOCATION_LOGW("Set current Method [%d]\n", priv->current_method);
107         } else if (g_type == LOCATION_TYPE_WPS) {
108                 priv->current_method = LOCATION_METHOD_WPS;
109                 LOCATION_LOGW("Set current Method [%d]\n", priv->current_method);
110         } else if (g_type == LOCATION_TYPE_HYBRID){
111                 priv->current_method = LOCATION_METHOD_HYBRID;
112                 LOCATION_LOGW("Set current Method [%d]\n", priv->current_method);
113         } else
114                 return FALSE;
115
116         return TRUE;
117 }
118
119
120 static int
121 hybrid_get_update_method (LocationHybridPrivate* priv)
122 {
123         if(!priv->gps && !priv->wps) return -1;
124
125         if (priv->gps_enabled) {
126                 hybrid_set_current_method (priv, LOCATION_TYPE_GPS);
127         } else if (priv->wps_enabled) {
128                 hybrid_set_current_method (priv, LOCATION_TYPE_WPS);
129         } else {
130                 hybrid_set_current_method (priv,LOCATION_TYPE_HYBRID);
131         }
132
133         return 0;
134 }
135
136 static LocationObject *
137 hybrid_get_current_object (LocationHybridPrivate* priv)
138 {
139         LocationMethod method = hybrid_get_current_method (priv);
140
141         LocationObject *obj = NULL;
142         switch (method) {
143                 case LOCATION_METHOD_GPS:
144                         obj = priv->gps;
145                         break;
146                 case LOCATION_METHOD_WPS:
147                         obj = priv->wps;
148                         break;
149                 default:
150                         break;
151         }
152
153         return obj;
154 }
155
156 static gboolean /* True : Receive more accurate info. False : Receive less accurate info */
157 hybrid_compare_g_type_method(LocationHybridPrivate *priv, GType g_type)
158 {
159         if (g_type == LOCATION_TYPE_GPS) {
160                 hybrid_set_current_method(priv, LOCATION_TYPE_GPS);
161                 return TRUE;
162         } else if (g_type == LOCATION_TYPE_WPS && hybrid_get_current_method(priv) == LOCATION_METHOD_WPS) {
163                 hybrid_set_current_method(priv, LOCATION_TYPE_WPS);
164                 return TRUE;
165         }
166
167         return FALSE;
168 }
169
170 static gboolean
171 _position_timeout_cb (gpointer data)
172 {
173         LOCATION_LOGD("_position_timeout_cb");
174         GObject *object = (GObject *)data;
175         if (!object) return FALSE;
176         LocationHybridPrivate *priv = GET_PRIVATE(object);
177         if (!priv) return FALSE;
178
179         LocationPosition *pos = NULL;
180         LocationAccuracy *acc = NULL;
181
182         if (priv->pos) {
183                 pos = location_position_copy (priv->pos);
184         }
185         else {
186                 pos = location_position_new (0, 0.0, 0.0, 0.0, LOCATION_STATUS_NO_FIX);
187         }
188
189         if (priv->acc) {
190                 acc = location_accuracy_copy (priv->acc);
191         }
192         else {
193                 acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0.0, 0.0);
194         }
195
196         LOCATION_LOGD("POSITION SERVICE_UPDATED");
197         g_signal_emit(object, signals[SERVICE_UPDATED], 0, POSITION_UPDATED, pos, acc);
198
199         location_position_free (pos);
200         location_accuracy_free (acc);
201
202         return TRUE;
203 }
204
205 static gboolean
206 _velocity_timeout_cb (gpointer data)
207 {
208         LOCATION_LOGD("_velocity_timeout_cb");
209         GObject *object = (GObject *)data;
210         LocationHybridPrivate *priv = GET_PRIVATE(object);
211         if (!priv) return FALSE;
212
213         LocationVelocity *vel = NULL;
214         LocationAccuracy *acc = NULL;
215
216         if (priv->vel) {
217                 vel = location_velocity_copy(priv->vel);
218         }
219         else {
220                 vel = location_velocity_new (0, 0.0, 0.0, 0.0);
221         }
222
223         if (priv->acc) {
224                 acc = location_accuracy_copy (priv->acc);
225         }
226         else {
227                 acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0.0, 0.0);
228         }
229
230         LOCATION_LOGD("VELOCITY SERVICE_UPDATED");
231         g_signal_emit(object, signals[SERVICE_UPDATED], 0, VELOCITY_UPDATED, vel, acc);
232
233         location_velocity_free (vel);
234         location_accuracy_free (acc);
235
236         return TRUE;
237 }
238
239
240 static void
241 location_hybrid_state_cb (keynode_t *key, gpointer self)
242 {
243         LOCATION_LOGD("location_hybrid_state_cb");
244         g_return_if_fail (key);
245         g_return_if_fail (self);
246         LocationHybridPrivate *priv = GET_PRIVATE(self);
247         
248         if (location_setting_get_key_val (key) == VCONFKEY_LOCATION_POSITION_SEARCHING) {
249                 if (!priv->pos_timer) priv->pos_timer = g_timeout_add (priv->pos_interval * 1000, _position_timeout_cb, self);
250                 if (!priv->vel_timer) priv->vel_timer = g_timeout_add (priv->vel_interval * 1000, _velocity_timeout_cb, self);
251
252         }
253         else {
254                 if (priv->pos_timer) g_source_remove (priv->pos_timer);
255                 if (priv->vel_timer) g_source_remove (priv->vel_timer);
256                 
257                 priv->pos_timer = 0;
258                 priv->vel_timer = 0;
259         }
260 }
261
262 static void
263 hybrid_service_updated (GObject *obj,
264         guint type,
265         gpointer data,
266         gpointer accuracy,
267         gpointer self)
268 {
269         LocationPosition *pos = NULL;
270         LocationVelocity *vel = NULL;
271         LocationSatellite *sat = NULL;
272         LOCATION_LOGD ("hybrid_service_updated");
273
274         /* To discard invalid data in a hybrid */
275         switch (type) {
276                 case POSITION_UPDATED: {
277                         pos = (LocationPosition *)data;
278                         if (!pos->timestamp) return;
279                 }
280                 case VELOCITY_UPDATED: {
281                         vel = (LocationVelocity *)data;
282                         if (!vel->timestamp) return;
283                 }
284                 case SATELLITE_UPDATED: {
285                         sat = (LocationSatellite *)data;
286                         if (!sat->timestamp) return;
287                 }
288         }
289
290         LocationHybridPrivate* priv = GET_PRIVATE((LocationHybrid*)self);
291         GType g_type = G_TYPE_FROM_INSTANCE(obj);
292         if (g_type == LOCATION_TYPE_GPS) {
293                 if (type == SATELLITE_UPDATED) {
294                         satellite_signaling(self, signals, &(priv->enabled), priv->sat_interval, TRUE, &(priv->sat_updated_timestamp), &(priv->sat), sat);
295                         return ;
296                 }
297                 else if (location_setting_get_int (VCONFKEY_LOCATION_GPS_STATE) == VCONFKEY_LOCATION_GPS_SEARCHING) {
298                         LOCATION_LOGD ("Searching GPS");
299                         return;
300                 }
301                 
302         }
303         else if ((g_type == LOCATION_TYPE_WPS || g_type == LOCATION_TYPE_CPS) && location_setting_get_int (VCONFKEY_LOCATION_WPS_STATE) == VCONFKEY_LOCATION_WPS_SEARCHING) {
304                 LOCATION_LOGD ("Searching WPS or CPS");
305                 return;
306         }
307
308         if (hybrid_compare_g_type_method(priv, g_type)) {
309                 LocationAccuracy *acc = (LocationAccuracy*)accuracy;
310                 if (type == POSITION_UPDATED) {
311                         position_signaling(self, signals, &(priv->enabled), priv->pos_interval, TRUE, &(priv->pos_updated_timestamp), &(priv->pos), priv->boundary_list, &(priv->zone_status), pos, acc);
312                         LOCATION_LOGW("Position updated. timestamp [%d]", priv->pos->timestamp);
313                 } else if (type == VELOCITY_UPDATED) {
314                         velocity_signaling(self, signals, &(priv->enabled), priv->vel_interval, TRUE, &(priv->vel_updated_timestamp), &(priv->vel), &(priv->acc), vel, acc);
315                         LOCATION_LOGW("Velocity updated. timestamp [%d]", priv->vel->timestamp);
316                 }
317
318         } else if (type == POSITION_UPDATED && priv->pos) {
319                         if (pos->timestamp - priv->pos->timestamp > HYBRID_POSITION_EXPIRATION_TIME) {
320                                 hybrid_set_current_method(priv, g_type);
321                         }
322         }
323
324 }
325
326 static void
327 hybrid_service_enabled (GObject *obj,
328         guint status,
329         gpointer self)
330 {
331         LOCATION_LOGD ("hybrid_service_enabled");
332         LocationHybridPrivate* priv = GET_PRIVATE((LocationHybrid*)self);
333         GType g_type = G_TYPE_FROM_INSTANCE(obj);
334         if(g_type == LOCATION_TYPE_GPS) priv->gps_enabled = TRUE;
335         else if(g_type == LOCATION_TYPE_WPS) priv->wps_enabled = TRUE;
336         else {
337                 LOCATION_LOGW("Undefined GType enabled");
338                 return;
339         }
340         hybrid_get_update_method(priv);
341         if(priv->gps_enabled || priv->wps_enabled)
342                 enable_signaling(self, signals, &(priv->enabled), TRUE, status);
343
344 }
345
346 static void
347 hybrid_service_disabled (GObject *obj,
348         guint status,
349         gpointer self)
350 {
351         LOCATION_LOGD ("hybrid_service_disabled");
352         LocationHybridPrivate* priv = GET_PRIVATE((LocationHybrid*)self);
353         GType g_type = G_TYPE_FROM_INSTANCE(obj);
354         if(g_type == LOCATION_TYPE_GPS) priv->gps_enabled = FALSE;
355         else if(g_type == LOCATION_TYPE_WPS) priv->wps_enabled = FALSE;
356         else {
357                 LOCATION_LOGW("Undefined GType disabled");
358                 return;
359         }
360         hybrid_get_update_method(priv);
361         if(!priv->gps_enabled && !priv->wps_enabled)
362                 enable_signaling(self, signals, &(priv->enabled), FALSE, status);
363
364 }
365
366 static int
367 location_hybrid_start (LocationHybrid *self)
368 {
369         LOCATION_LOGD("location_hybrid_start");
370
371         int ret_gps = LOCATION_ERROR_NONE;
372         int ret_wps = LOCATION_ERROR_NONE;
373
374         LocationHybridPrivate* priv = GET_PRIVATE(self);
375         if (priv->is_started == TRUE)
376                 return LOCATION_ERROR_NONE;
377
378         if(priv->gps) ret_gps = location_start(priv->gps);
379         if(priv->wps) ret_wps = location_start(priv->wps);
380
381         if (ret_gps != LOCATION_ERROR_NONE &&
382                         ret_wps != LOCATION_ERROR_NONE) {
383                 if (ret_gps == LOCATION_ERROR_NOT_ALLOWED ||
384                                 ret_wps == LOCATION_ERROR_NOT_ALLOWED) {
385                         priv->is_started = TRUE;
386                         return LOCATION_ERROR_NOT_ALLOWED;
387                 }
388                 else {
389                         return LOCATION_ERROR_NOT_AVAILABLE;
390                 }
391         }
392
393         priv->is_started = TRUE;
394
395         if (priv->set_noti == FALSE) {
396                 location_setting_add_notify (VCONFKEY_LOCATION_POSITION_STATE, location_hybrid_state_cb, self);
397                 priv->set_noti = TRUE;
398         }
399
400
401         return LOCATION_ERROR_NONE;
402 }
403
404 static int
405 location_hybrid_stop (LocationHybrid *self)
406 {
407         LOCATION_LOGD("location_hybrid_stop");
408
409         LocationHybridPrivate* priv = GET_PRIVATE(self);
410         if( priv->is_started == FALSE)
411                 return LOCATION_ERROR_NONE;
412
413         int ret_gps = LOCATION_ERROR_NONE;
414         int ret_wps = LOCATION_ERROR_NONE;
415
416         if(priv->gps) ret_gps = location_stop(priv->gps);
417         if(priv->wps) ret_wps = location_stop(priv->wps);
418
419         priv->is_started = FALSE;
420
421         if (ret_gps != LOCATION_ERROR_NONE &&
422                 ret_wps != LOCATION_ERROR_NONE)
423                 return LOCATION_ERROR_NOT_AVAILABLE;
424
425         if (priv->pos_timer) g_source_remove (priv->pos_timer);
426         if (priv->vel_timer) g_source_remove (priv->vel_timer);
427         priv->pos_timer = 0;
428         priv->vel_timer = 0;
429
430         if (priv->set_noti == TRUE) {
431                 location_setting_ignore_notify (VCONFKEY_LOCATION_POSITION_STATE, location_hybrid_state_cb);
432                 priv->set_noti = FALSE;
433         }
434
435         return LOCATION_ERROR_NONE;
436 }
437
438 static void
439 location_hybrid_dispose (GObject *gobject)
440 {
441         LOCATION_LOGD("location_hybrid_dispose");
442         LocationHybridPrivate *priv = GET_PRIVATE(gobject);
443
444         if (priv->pos_timer) g_source_remove (priv->pos_timer);
445         if (priv->vel_timer) g_source_remove (priv->vel_timer);
446         priv->pos_timer = 0;
447         priv->vel_timer = 0;
448
449         if (priv->set_noti == TRUE) {
450                 location_setting_ignore_notify (VCONFKEY_LOCATION_POSITION_STATE, location_hybrid_state_cb);
451                 priv->set_noti = FALSE;
452         }
453
454         G_OBJECT_CLASS (location_hybrid_parent_class)->dispose (gobject);
455 }
456
457 static void
458 location_hybrid_finalize (GObject *gobject)
459 {
460         LOCATION_LOGD("location_hybrid_finalize");
461         LocationHybridPrivate* priv = GET_PRIVATE(gobject);
462
463         if (priv->gps) {
464                 g_signal_handlers_disconnect_by_func(priv->gps, G_CALLBACK (hybrid_service_enabled), gobject);
465                 g_signal_handlers_disconnect_by_func(priv->gps, G_CALLBACK (hybrid_service_disabled), gobject);
466                 g_signal_handlers_disconnect_by_func(priv->gps, G_CALLBACK (hybrid_service_updated), gobject);
467                 location_free(priv->gps);
468         }
469         if (priv->wps) {
470                 g_signal_handlers_disconnect_by_func(priv->wps, G_CALLBACK (hybrid_service_enabled), gobject);
471                 g_signal_handlers_disconnect_by_func(priv->wps, G_CALLBACK (hybrid_service_disabled), gobject);
472                 g_signal_handlers_disconnect_by_func(priv->wps, G_CALLBACK (hybrid_service_updated), gobject);
473                 location_free(priv->wps);
474         }
475
476         if (priv->boundary_list) {
477                 g_list_free_full(priv->boundary_list, free_boundary_list);
478                 priv->boundary_list = NULL;
479         }
480
481         if (priv->pos) {
482                 location_position_free(priv->pos);
483                 priv->pos = NULL;
484         }
485
486         if (priv->vel) {
487                 location_velocity_free(priv->vel);
488                 priv->vel = NULL;
489         }
490
491         if (priv->acc) {
492                 location_accuracy_free(priv->acc);
493                 priv->acc = NULL;
494         }
495
496         if (priv->sat) {
497                 location_satellite_free(priv->sat);
498                 priv->sat = NULL;
499         }
500
501         G_OBJECT_CLASS (location_hybrid_parent_class)->finalize (gobject);
502 }
503
504 static void
505 location_hybrid_set_property (GObject *object,
506         guint property_id,
507         const GValue *value,
508         GParamSpec *pspec)
509 {
510         LocationHybridPrivate* priv = GET_PRIVATE(object);
511         if (!priv->gps && !priv->wps) {
512                 LOCATION_LOGW("Set property is not available now");
513                 return;
514         }
515
516         int ret = 0;
517         switch (property_id){
518                 case PROP_BOUNDARY:{
519                         GList *boundary_list = (GList *)g_list_copy(g_value_get_pointer(value));
520                         ret = set_prop_boundary(&priv->boundary_list, boundary_list);
521                         if(ret != 0) LOCATION_LOGD("Set boundary. Error[%d]", ret);
522                    break;
523                 }
524                 case PROP_REMOVAL_BOUNDARY: {
525                         LocationBoundary *req_boundary = (LocationBoundary*) g_value_dup_boxed(value);
526                         ret = set_prop_removal_boundary(&priv->boundary_list, req_boundary);
527                         if(ret != 0) LOCATION_LOGD("Removal boundary. Error[%d]", ret);
528                         break;
529                 }
530                 case PROP_POS_INTERVAL: {
531                         guint interval = g_value_get_uint(value);
532                         if(interval > 0) {
533                                 if(interval < LOCATION_UPDATE_INTERVAL_MAX)
534                                         priv->pos_interval = interval;
535                                 else
536                                         priv->pos_interval = (guint) LOCATION_UPDATE_INTERVAL_MAX;
537
538                         }
539                         else
540                                 priv->pos_interval = LOCATION_UPDATE_INTERVAL_DEFAULT;
541
542                         if (priv->pos_timer) {
543                                 g_source_remove (priv->pos_timer);
544                                 priv->pos_timer = g_timeout_add (priv->pos_interval * 1000, _position_timeout_cb, object);
545                         }
546
547                         break;
548                 }
549                 case PROP_VEL_INTERVAL: {
550                         guint interval = g_value_get_uint(value);
551                         if(interval > 0) {
552                                 if(interval < LOCATION_UPDATE_INTERVAL_MAX)
553                                         priv->vel_interval = interval;
554                                 else
555                                         priv->vel_interval = (guint) LOCATION_UPDATE_INTERVAL_MAX;
556
557                         }
558                         else
559                                 priv->vel_interval = LOCATION_UPDATE_INTERVAL_DEFAULT;
560
561                         if (priv->vel_timer) {
562                                 g_source_remove (priv->vel_timer);
563                                 priv->vel_timer = g_timeout_add (priv->vel_interval * 1000, _velocity_timeout_cb, object);
564                         }
565
566                         break;
567                 }
568                 case PROP_SAT_INTERVAL: {
569                         guint interval = g_value_get_uint(value);
570                         if(interval > 0) {
571                                 if(interval < LOCATION_UPDATE_INTERVAL_MAX)
572                                         priv->sat_interval = interval;
573                                 else
574                                         priv->sat_interval = (guint) LOCATION_UPDATE_INTERVAL_MAX;
575
576                         }
577                         else
578                                 priv->sat_interval = LOCATION_UPDATE_INTERVAL_DEFAULT;
579
580                         break;
581                 }
582                 default:
583                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
584                         break;
585         }
586 }
587
588 static void
589 location_hybrid_get_property (GObject *object,
590         guint property_id,
591         GValue *value,
592         GParamSpec *pspec)
593 {
594         LocationHybridPrivate *priv = GET_PRIVATE (object);
595         if(!priv->gps && !priv->wps){
596                 LOCATION_LOGW("Get property is not available now");
597                 return;
598         }
599
600         LOCATION_LOGW("Get Propery ID[%d]", property_id);
601
602         switch (property_id){
603         case PROP_METHOD_TYPE:
604                 g_value_set_int(value, hybrid_get_current_method (priv));
605                 break;
606         case PROP_LAST_POSITION:
607                 g_value_set_boxed(value, priv->pos);
608                 break;
609         case PROP_BOUNDARY:
610                 g_value_set_pointer(value, g_list_first(priv->boundary_list));
611                 break;
612         case PROP_POS_INTERVAL:
613                 g_value_set_uint(value, priv->pos_interval);
614                 break;
615         case PROP_VEL_INTERVAL:
616                 g_value_set_uint(value, priv->vel_interval);
617                 break;
618         case PROP_SAT_INTERVAL:
619                 g_value_set_uint(value, priv->sat_interval);
620                 break;
621         default:
622                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
623                 break;
624         }
625 }
626
627 static int
628 location_hybrid_get_position (LocationHybrid *self,
629         LocationPosition **position,
630         LocationAccuracy **accuracy)
631 {
632         int ret = LOCATION_ERROR_NOT_AVAILABLE;
633         LOCATION_LOGD("location_hybrid_get_position");
634         if (!location_setting_get_int(VCONFKEY_LOCATION_ENABLED) && !location_setting_get_int(VCONFKEY_LOCATION_NETWORK_ENABLED)) {
635                 return LOCATION_ERROR_NOT_ALLOWED;
636         }
637
638         LocationHybridPrivate *priv = GET_PRIVATE (self);
639
640         if (priv->pos) {
641                 *position = location_position_copy (priv->pos);
642                 ret = LOCATION_ERROR_NONE;
643         }
644
645         if (priv->acc) {
646                 *accuracy = location_accuracy_copy (priv->acc);
647         }
648
649         return ret;
650 }
651
652 static int
653 location_hybrid_get_last_position (LocationHybrid *self,
654         LocationPosition **position,
655         LocationAccuracy **accuracy)
656 {
657         LOCATION_LOGD("location_hybrid_get_last_position");
658
659         int ret = LOCATION_ERROR_NONE;
660         LocationPosition *gps_pos = NULL, *wps_pos = NULL;
661         LocationAccuracy *gps_acc = NULL, *wps_acc = NULL;
662         LocationHybridPrivate *priv = GET_PRIVATE (self);
663
664         if (priv->gps) location_get_last_position (priv->gps, &gps_pos, &gps_acc);
665         if (priv->wps) location_get_last_position (priv->wps, &wps_pos, &wps_acc);
666
667         if (gps_pos && wps_pos) {
668                 if (wps_pos->timestamp > gps_pos->timestamp) {
669                         *position = wps_pos;
670                         *accuracy = wps_acc;
671                         location_position_free (gps_pos);
672                         location_accuracy_free (gps_acc);
673                 }
674                 else {
675                         *position = gps_pos;
676                         *accuracy = gps_acc;
677                         location_position_free (wps_pos);
678                         location_accuracy_free (wps_acc);
679                 }
680         } else if (gps_pos) {
681                 *position = gps_pos;
682                 *accuracy = gps_acc;
683         } else if (wps_pos) {
684                 *position = wps_pos;
685                 *accuracy = wps_acc;
686         } else {
687                 ret = LOCATION_ERROR_NOT_AVAILABLE;
688         }
689
690         return ret;
691 }
692
693 static int
694 location_hybrid_get_velocity (LocationHybrid *self,
695         LocationVelocity **velocity,
696         LocationAccuracy **accuracy)
697 {
698         int ret = LOCATION_ERROR_NOT_AVAILABLE;
699         LOCATION_LOGD("location_hybrid_get_velocity");
700         if (!location_setting_get_int(VCONFKEY_LOCATION_ENABLED) && !location_setting_get_int(VCONFKEY_LOCATION_NETWORK_ENABLED)) {
701                 return LOCATION_ERROR_NOT_ALLOWED;
702         }
703
704         LocationHybridPrivate *priv = GET_PRIVATE (self);
705
706         if (priv->vel) {
707                 *velocity = location_velocity_copy (priv->vel);
708                 ret = LOCATION_ERROR_NONE;
709         }
710
711         if (priv->acc) {
712                 *accuracy = location_accuracy_copy (priv->acc);
713         }
714
715         return ret;
716 }
717
718 static int
719 location_hybrid_get_last_velocity (LocationHybrid *self,
720         LocationVelocity **velocity,
721         LocationAccuracy **accuracy)
722 {
723         LOCATION_LOGD("location_hybrid_get_last_velocity");
724
725         int ret = LOCATION_ERROR_NONE;
726         LocationHybridPrivate *priv = GET_PRIVATE (self);
727         LocationVelocity *gps_vel = NULL, *wps_vel = NULL;
728         LocationAccuracy *gps_acc = NULL, *wps_acc = NULL;
729
730         if (priv->gps) location_get_last_velocity (priv->gps, &gps_vel, &gps_acc);
731         if (priv->wps) location_get_last_velocity (priv->wps, &wps_vel, &wps_acc);
732
733         if (gps_vel && wps_vel) {
734                 if (wps_vel->timestamp > gps_vel->timestamp) {
735                         *velocity = wps_vel;
736                         *accuracy = wps_acc;
737                         location_velocity_free (gps_vel);
738                         location_accuracy_free (gps_acc);
739                 } else {
740                         *velocity = gps_vel;
741                         *accuracy = gps_acc;
742                         location_velocity_free (wps_vel);
743                         location_accuracy_free (wps_acc);
744                 }
745         }
746         else if (gps_vel) {
747                 *velocity = gps_vel;
748                 *accuracy = gps_acc;
749         } else if (wps_vel) {
750                 *velocity = wps_vel;
751                 *accuracy = wps_acc;
752         } else {
753                 *velocity = NULL;
754                 *accuracy = NULL;
755                 ret = LOCATION_ERROR_NOT_AVAILABLE;
756         }
757
758         return ret;
759 }
760
761 static int
762 location_hybrid_get_satellite (LocationHybrid *self,
763         LocationSatellite **satellite)
764 {
765         int ret = LOCATION_ERROR_NOT_AVAILABLE;
766         LOCATION_LOGD("location_hybrid_get_satellite");
767         if (!location_setting_get_int(VCONFKEY_LOCATION_ENABLED) && !location_setting_get_int(VCONFKEY_LOCATION_NETWORK_ENABLED)) {
768                 return LOCATION_ERROR_NOT_ALLOWED;
769         }
770
771         LocationHybridPrivate *priv = GET_PRIVATE (self);
772         if (priv->sat) {
773                 *satellite = location_satellite_copy (priv->sat);
774                 ret = LOCATION_ERROR_NONE;
775         }
776
777         return ret;
778 }
779
780 static int
781 location_hybrid_get_last_satellite (LocationHybrid *self,
782         LocationSatellite **satellite)
783 {
784         LOCATION_LOGD("location_hybrid_get_last_satellite");
785
786         int ret = LOCATION_ERROR_NONE;
787         LocationHybridPrivate *priv = GET_PRIVATE (self);
788
789         if (priv->gps) ret = location_get_last_satellite (priv->gps, satellite);
790         else {
791                 *satellite = NULL;
792                 ret = LOCATION_ERROR_NOT_AVAILABLE;
793         }
794
795         return ret;
796 }
797
798 static void
799 location_ielement_interface_init (LocationIElementInterface *iface)
800 {
801         iface->start = (TYPE_START_FUNC)location_hybrid_start;
802         iface->stop = (TYPE_STOP_FUNC)location_hybrid_stop;
803         iface->get_position = (TYPE_GET_POSITION)location_hybrid_get_position;
804         iface->get_last_position = (TYPE_GET_POSITION)location_hybrid_get_last_position;
805         iface->get_velocity = (TYPE_GET_VELOCITY)location_hybrid_get_velocity;
806         iface->get_last_velocity = (TYPE_GET_VELOCITY)location_hybrid_get_last_velocity;
807         iface->get_satellite = (TYPE_GET_SATELLITE)location_hybrid_get_satellite;
808         iface->get_last_satellite = (TYPE_GET_SATELLITE)location_hybrid_get_last_satellite;
809 }
810
811 static void
812 location_hybrid_init (LocationHybrid *self)
813 {
814         LOCATION_LOGD("location_hybrid_init");
815         LocationHybridPrivate* priv = GET_PRIVATE(self);
816
817         priv->is_started = FALSE;
818         priv->pos_interval = LOCATION_UPDATE_INTERVAL_DEFAULT;
819         priv->vel_interval = LOCATION_UPDATE_INTERVAL_DEFAULT;
820         priv->sat_interval = LOCATION_UPDATE_INTERVAL_DEFAULT;
821
822         priv->pos_updated_timestamp = 0;
823         priv->vel_updated_timestamp = 0;
824         priv->sat_updated_timestamp = 0;
825
826         priv->gps_enabled = FALSE;
827         priv->wps_enabled = FALSE;
828
829         priv->gps = NULL;
830         priv->wps = NULL;
831
832         priv->set_noti = FALSE;
833
834         priv->pos_timer = 0;
835         priv->vel_timer = 0;
836
837         if(location_is_supported_method(LOCATION_METHOD_GPS)) priv->gps = location_new (LOCATION_METHOD_GPS);
838         if(location_is_supported_method(LOCATION_METHOD_WPS)) priv->wps = location_new (LOCATION_METHOD_WPS);
839
840         if(priv->gps){
841                 g_signal_connect (priv->gps, "service-enabled", G_CALLBACK(hybrid_service_enabled), self);
842                 g_signal_connect (priv->gps, "service-disabled", G_CALLBACK(hybrid_service_disabled), self);
843                 g_signal_connect (priv->gps, "service-updated", G_CALLBACK(hybrid_service_updated), self);
844         }
845         if(priv->wps){
846                 g_signal_connect (priv->wps, "service-enabled", G_CALLBACK(hybrid_service_enabled), self);
847                 g_signal_connect (priv->wps, "service-disabled", G_CALLBACK(hybrid_service_disabled), self);
848                 g_signal_connect (priv->wps, "service-updated", G_CALLBACK(hybrid_service_updated), self);
849         }
850
851         hybrid_set_current_method (priv, LOCATION_TYPE_HYBRID);
852         priv->enabled= FALSE;
853
854         priv->pos = NULL;
855         priv->vel = NULL;
856         priv->acc = NULL;
857         priv->sat = NULL;
858
859         priv->zone_status = ZONE_STATUS_NONE;
860         priv->boundary_list = NULL;
861
862 }
863
864 static void
865 location_hybrid_class_init (LocationHybridClass *klass)
866 {
867         LOCATION_LOGD("location_hybrid_class_init");
868         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
869
870         gobject_class->set_property = location_hybrid_set_property;
871         gobject_class->get_property = location_hybrid_get_property;
872
873         gobject_class->dispose = location_hybrid_dispose;
874         gobject_class->finalize = location_hybrid_finalize;
875
876         g_type_class_add_private (klass, sizeof (LocationHybridPrivate));
877
878         signals[SERVICE_ENABLED] = g_signal_new ("service-enabled",
879                         G_TYPE_FROM_CLASS (klass),
880                         G_SIGNAL_RUN_FIRST |
881                         G_SIGNAL_NO_RECURSE,
882                         G_STRUCT_OFFSET (LocationHybridClass, enabled),
883                         NULL, NULL,
884                         location_VOID__UINT,
885                         G_TYPE_NONE, 1,
886                         G_TYPE_UINT);
887
888         signals[SERVICE_DISABLED] = g_signal_new ("service-disabled",
889                         G_TYPE_FROM_CLASS (klass),
890                         G_SIGNAL_RUN_FIRST |
891                         G_SIGNAL_NO_RECURSE,
892                         G_STRUCT_OFFSET (LocationHybridClass, disabled),
893                         NULL, NULL,
894                         location_VOID__UINT,
895                         G_TYPE_NONE, 1,
896                         G_TYPE_UINT);
897
898         signals[SERVICE_UPDATED] = g_signal_new ("service-updated",
899                         G_TYPE_FROM_CLASS (klass),
900                         G_SIGNAL_RUN_FIRST |
901                         G_SIGNAL_NO_RECURSE,
902                         G_STRUCT_OFFSET (LocationHybridClass, updated),
903                         NULL, NULL,
904                         location_VOID__UINT_POINTER_POINTER,
905                         G_TYPE_NONE, 3,
906                         G_TYPE_UINT,
907                         G_TYPE_POINTER,
908                         G_TYPE_POINTER);
909
910         signals[ZONE_IN] = g_signal_new ("zone-in",
911                         G_TYPE_FROM_CLASS (klass),
912                         G_SIGNAL_RUN_FIRST |
913                         G_SIGNAL_NO_RECURSE,
914                         G_STRUCT_OFFSET (LocationHybridClass, zone_in),
915                         NULL, NULL,
916                         location_VOID__UINT_POINTER_POINTER,
917                         G_TYPE_NONE, 3,
918                         G_TYPE_UINT,
919                         G_TYPE_POINTER,
920                         G_TYPE_POINTER);
921
922         signals[ZONE_OUT] = g_signal_new ("zone-out",
923                         G_TYPE_FROM_CLASS (klass),
924                         G_SIGNAL_RUN_FIRST |
925                         G_SIGNAL_NO_RECURSE,
926                         G_STRUCT_OFFSET (LocationHybridClass, zone_out),
927                         NULL, NULL,
928                         location_VOID__UINT_POINTER_POINTER,
929                         G_TYPE_NONE, 3,
930                         G_TYPE_UINT,
931                         G_TYPE_POINTER,
932                         G_TYPE_POINTER);
933
934         properties[PROP_METHOD_TYPE] = g_param_spec_int ("method",
935                         "method type",
936                         "location method type name",
937                         LOCATION_METHOD_HYBRID,
938                         LOCATION_METHOD_HYBRID,
939                         LOCATION_METHOD_HYBRID,
940                         G_PARAM_READABLE);
941
942         properties[PROP_LAST_POSITION] = g_param_spec_boxed ("last-position",
943                         "hybrid last position prop",
944                         "hybrid last position data",
945                         LOCATION_TYPE_POSITION,
946                         G_PARAM_READABLE);
947
948         properties[PROP_POS_INTERVAL] = g_param_spec_uint ("pos-interval",
949                         "position interval prop",
950                         "position interval data",
951                         LOCATION_UPDATE_INTERVAL_MIN,
952                         LOCATION_UPDATE_INTERVAL_MAX,
953                         LOCATION_UPDATE_INTERVAL_DEFAULT,
954                         G_PARAM_READWRITE);
955         properties[PROP_VEL_INTERVAL] = g_param_spec_uint ("vel-interval",
956                         "velocity interval prop",
957                         "velocity interval data",
958                         LOCATION_UPDATE_INTERVAL_MIN,
959                         LOCATION_UPDATE_INTERVAL_MAX,
960                         LOCATION_UPDATE_INTERVAL_DEFAULT,
961                         G_PARAM_READWRITE);
962         properties[PROP_SAT_INTERVAL] = g_param_spec_uint ("sat-interval",
963                         "satellite interval prop",
964                         "satellite interval data",
965                         LOCATION_UPDATE_INTERVAL_MIN,
966                         LOCATION_UPDATE_INTERVAL_MAX,
967                         LOCATION_UPDATE_INTERVAL_DEFAULT,
968                         G_PARAM_READWRITE);
969
970         properties[PROP_BOUNDARY]  = g_param_spec_pointer ("boundary",
971                         "hybrid boundary prop",
972                         "hybrid boundary data",
973                         G_PARAM_READWRITE);
974
975         properties[PROP_REMOVAL_BOUNDARY] = g_param_spec_boxed("removal-boundary",
976                         "hybrid removal boundary prop",
977                         "hybrid removal boundary data",
978                         LOCATION_TYPE_BOUNDARY,
979                         G_PARAM_READWRITE);
980
981         g_object_class_install_properties (gobject_class,
982                         PROP_MAX,
983                         properties);
984
985 }