Separate in library the application
[googlelatitude] / liblocationmaemo5 / liblocationwrapper.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the Qt Mobility Components.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "liblocationwrapper_p.h"
43
44 #include <QDateTime>
45
46 using namespace std;
47
48 QTM_BEGIN_NAMESPACE
49
50 Q_GLOBAL_STATIC(LiblocationWrapper, LocationEngine)
51
52 LiblocationWrapper *LiblocationWrapper::instance()
53 {
54     return LocationEngine();
55 }
56
57 LiblocationWrapper::LiblocationWrapper()
58     : file(NULL),
59     locationControl(NULL),
60     locationDevice(NULL),
61     errorHandlerId(0),
62     posChangedId(0),
63     origUpdateInterval(0),
64     startcounter(0),
65     validLastUpdate(false),
66     validLastSatUpdate(false),
67     locationState(LiblocationWrapper::Undefined) {
68     qDebug() << "* LiblocationWrapper Fremantle Backport";
69 }
70
71 LiblocationWrapper::~LiblocationWrapper()
72 {
73     if (locationDevice)
74         g_object_unref(locationDevice);
75     if (locationControl)
76         g_object_unref(locationControl);
77 }
78
79 bool LiblocationWrapper::inited()
80 {
81     int retval = false;
82     if (!(locationState & LiblocationWrapper::Inited)) {
83         g_type_init();
84
85         locationControl = location_gpsd_control_get_default();
86
87         if (locationControl) {
88             g_object_set(G_OBJECT(locationControl),
89                          "preferred-method", LOCATION_METHOD_USER_SELECTED,
90                          "preferred-interval", LOCATION_INTERVAL_1S,
91                          NULL);
92             locationDevice =
93                 (LocationGPSDevice*)g_object_new(LOCATION_TYPE_GPS_DEVICE,
94                                                  NULL);
95
96             if (locationDevice) {
97                 errorHandlerId =
98                     g_signal_connect(G_OBJECT(locationControl), "error-verbose",
99                                      G_CALLBACK(&locationError),
100                                      static_cast<void*>(this));
101                 posChangedId =
102                     g_signal_connect(G_OBJECT(locationDevice), "changed",
103                                      G_CALLBACK(&locationChanged),
104                                      static_cast<void*>(this));
105                 locationState = LiblocationWrapper::Inited;
106                 retval = true;
107                 startcounter = 0;
108             }
109         }
110     } else {
111         retval = true;
112     }
113     return retval;
114 }
115
116 void LiblocationWrapper::locationError(LocationGPSDevice *device,
117                                        gint errorCode, gpointer data)
118 {
119     Q_UNUSED(device);
120     QString locationError;
121
122     switch (errorCode) {
123         case LOCATION_ERROR_USER_REJECTED_DIALOG:
124             locationError = "User didn't enable requested methods";
125             break;
126         case LOCATION_ERROR_USER_REJECTED_SETTINGS:
127             locationError = "User changed settings, which disabled location.";
128             break;
129         case LOCATION_ERROR_BT_GPS_NOT_AVAILABLE:
130             locationError = "Problems with BT GPS";
131             break;
132         case LOCATION_ERROR_METHOD_NOT_ALLOWED_IN_OFFLINE_MODE:
133             locationError = "Requested method is not allowed in offline mode";
134             break;
135         case LOCATION_ERROR_SYSTEM:
136             locationError = "System error.";
137             break;
138         default:
139             locationError = "Unknown error.";
140     }
141
142     qDebug() << "Location error:" << locationError;
143
144     LiblocationWrapper *object;
145     object = (LiblocationWrapper *)data;
146     emit object->error();
147 }
148
149 void LiblocationWrapper::locationChanged(LocationGPSDevice *device,
150         gpointer data)
151 {
152     QGeoPositionInfo posInfo;
153     QGeoCoordinate coordinate;
154     QGeoSatelliteInfo satInfo;
155     int satellitesInUseCount = 0;
156     LiblocationWrapper *object;
157
158     if (!data || !device) {
159         return;
160     }
161
162     object = (LiblocationWrapper *)data;
163
164     if (device) {
165         if (device->fix) {
166             if (device->fix->fields & LOCATION_GPS_DEVICE_TIME_SET) {
167                 posInfo.setTimestamp(QDateTime::fromTime_t(device->fix->time));
168             }
169
170             if (device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) {
171                 coordinate.setLatitude(device->fix->latitude);
172                 coordinate.setLongitude(device->fix->longitude);
173                 posInfo.setAttribute(QGeoPositionInfo::HorizontalAccuracy,
174                                      device->fix->eph / 100.0);
175                 posInfo.setAttribute(QGeoPositionInfo::VerticalAccuracy,
176                                      device->fix->epv);
177             }
178
179             if (device->fix->fields & LOCATION_GPS_DEVICE_ALTITUDE_SET) {
180                 coordinate.setAltitude(device->fix->altitude);
181             }
182
183             if (device->fix->fields & LOCATION_GPS_DEVICE_SPEED_SET) {
184                 posInfo.setAttribute(QGeoPositionInfo::GroundSpeed,
185                                      device->fix->speed / 3.6);
186             }
187
188             if (device->fix->fields & LOCATION_GPS_DEVICE_CLIMB_SET) {
189                 posInfo.setAttribute(QGeoPositionInfo::VerticalSpeed,
190                                      device->fix->climb);
191             }
192
193             if (device->fix->fields & LOCATION_GPS_DEVICE_TRACK_SET) {
194                 posInfo.setAttribute(QGeoPositionInfo::Direction,
195                                      device->fix->track);
196             }
197         }
198
199         if (device->satellites_in_view) {
200             QList<QGeoSatelliteInfo> satsInView;
201             QList<QGeoSatelliteInfo> satsInUse;
202             unsigned int i;
203             for (i = 0;i < device->satellites->len;i++) {
204                 LocationGPSDeviceSatellite *satData =
205                     (LocationGPSDeviceSatellite *)g_ptr_array_index(device->satellites,
206                             i);
207                 satInfo.setSignalStrength(satData->signal_strength);
208                 satInfo.setPrnNumber(satData->prn);
209                 satInfo.setAttribute(QGeoSatelliteInfo::Elevation,
210                                      satData->elevation);
211                 satInfo.setAttribute(QGeoSatelliteInfo::Azimuth,
212                                      satData->azimuth);
213
214                 satsInView.append(satInfo);
215                 if (satData->in_use) {
216                     satellitesInUseCount++;
217                     satsInUse.append(satInfo);
218                 }
219             }
220
221             if (!satsInView.isEmpty())
222                 object->satellitesInViewUpdated(satsInView);
223
224             if (!satsInUse.isEmpty())
225                 object->satellitesInUseUpdated(satsInUse);
226         }
227     }
228
229     posInfo.setCoordinate(coordinate);
230
231     emit object->positionUpdated(posInfo);
232 }
233
234 QGeoPositionInfo LiblocationWrapper::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
235 {
236     QGeoPositionInfo posInfo;
237     QGeoCoordinate coordinate;
238     double time;
239     double latitude;
240     double longitude;
241     double altitude;
242     double speed;
243     double track;
244     double climb;
245
246     GConfItem lastKnownPositionTime("/system/nokia/location/lastknown/time");
247     GConfItem lastKnownPositionLatitude("/system/nokia/location/lastknown/latitude");
248     GConfItem lastKnownPositionLongitude("/system/nokia/location/lastknown/longitude");
249     GConfItem lastKnownPositionAltitude("/system/nokia/location/lastknown/altitude");
250     GConfItem lastKnownPositionSpeed("/system/nokia/location/lastknown/speed");
251     GConfItem lastKnownPositionTrack("/system/nokia/location/lastknown/track");
252     GConfItem lastKnownPositionClimb("/system/nokia/location/lastknown/climb");
253
254     if (validLastSatUpdate)
255         return lastSatUpdate;
256
257     if (!fromSatellitePositioningMethodsOnly)
258         if (validLastUpdate)
259             return lastUpdate;
260
261     time = lastKnownPositionTime.value().toDouble();
262     latitude = lastKnownPositionLatitude.value().toDouble();
263     longitude = lastKnownPositionLongitude.value().toDouble();
264     altitude = lastKnownPositionAltitude.value().toDouble();
265     speed = lastKnownPositionSpeed.value().toDouble();
266     track = lastKnownPositionTrack.value().toDouble();
267     climb = lastKnownPositionClimb.value().toDouble();
268
269     if (longitude && latitude) {
270         coordinate.setLongitude(longitude);
271         coordinate.setLatitude(latitude);
272         if (altitude) {
273             coordinate.setAltitude(altitude);
274         }
275         posInfo.setCoordinate(coordinate);
276     }
277
278     if (speed) {
279         posInfo.setAttribute(QGeoPositionInfo::GroundSpeed, speed);
280     }
281
282     if (track) {
283         posInfo.setAttribute(QGeoPositionInfo::Direction, track);
284     }
285
286     if (climb) {
287         posInfo.setAttribute(QGeoPositionInfo::VerticalSpeed, climb);
288     }
289
290     // Only positions with time (3D) are provided.
291     if (time) {
292         posInfo.setTimestamp(QDateTime::fromTime_t(time));
293         return posInfo;
294     }
295
296     return QGeoPositionInfo();
297 }
298
299 void LiblocationWrapper::satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &satellites)
300 {
301     satsInView = satellites;
302 }
303
304 void LiblocationWrapper::satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &satellites)
305 {
306     satsInUse = satellites;
307 }
308
309 QList<QGeoSatelliteInfo> LiblocationWrapper::satellitesInView()
310 {
311     return satsInView;
312 }
313
314 QList<QGeoSatelliteInfo> LiblocationWrapper::satellitesInUse()
315 {
316     return satsInUse;
317 }
318
319 void LiblocationWrapper::start() {
320     startcounter++;
321
322     if ((locationState & LiblocationWrapper::Inited) &&
323             !(locationState & LiblocationWrapper::Started)) {
324         if (!errorHandlerId) {
325             errorHandlerId =
326                 g_signal_connect(G_OBJECT(locationControl), "error-verbose",
327                                  G_CALLBACK(&locationError),
328                                  static_cast<void*>(this));
329         }
330
331         if (!posChangedId) {
332             posChangedId =
333                 g_signal_connect(G_OBJECT(locationDevice), "changed",
334                                  G_CALLBACK(&locationChanged),
335                                  static_cast<void*>(this));
336         }
337
338         location_gpsd_control_start(locationControl);
339
340         locationState |= LiblocationWrapper::Started;
341         locationState &= ~LiblocationWrapper::Stopped;
342     }
343 }
344
345 void LiblocationWrapper::stop() {
346     startcounter--;
347
348     if (startcounter > 0)
349         return;
350     
351     if ((locationState & (LiblocationWrapper::Started |
352                           LiblocationWrapper::Inited)) &&
353             !(locationState & LiblocationWrapper::Stopped)) {
354         if (errorHandlerId)
355             g_signal_handler_disconnect(G_OBJECT(locationControl),
356                                         errorHandlerId);
357         if (posChangedId)
358             g_signal_handler_disconnect(G_OBJECT(locationDevice),
359                                         posChangedId);
360         errorHandlerId = 0;
361         posChangedId = 0;
362         startcounter = 0;
363         location_gpsd_control_stop(locationControl);
364
365         locationState &= ~LiblocationWrapper::Started;
366         locationState |= LiblocationWrapper::Stopped;
367     }
368 }
369
370 bool LiblocationWrapper::isActive() {
371     if (locationState & LiblocationWrapper::Started)
372         return true;
373     else
374         return false;
375 }
376
377 #include "moc_liblocationwrapper_p.cpp"
378 QTM_END_NAMESPACE
379